Прооптимизировать IMUL

Тема в разделе "WASM.ASSEMBLER", создана пользователем sarin, 12 фев 2008.

  1. sarin

    sarin Member

    Публикаций:
    0
    Регистрация:
    2 июн 2005
    Сообщения:
    30
    Имеем A - dword RGB цвет (00000000RRRRRRRRGGGGGGGGBBBBBBBB)
    Нужно посчитать B byte = (((R * 77) + (G * 151) + (B * 28)) / 256)

    Решение:

    1) C: (для образца)

    B = (((A.rgbRed * 77) + (A.rgbGreen * 151) +
    (A.rgbBlue * 28)) >> 8) & 255;

    2а) asm: (мой вариант c imul)
    Код (Text):
    1. mov edx, A.Value
    2. movzx eax, dl
    3. movzx ecx, dh
    4. shr edx,16
    5. imul eax,eax,28
    6. imul ecx,ecx,151
    7. imul edx,edx,77
    8. add eax, ecx
    9. add eax, edx
    10. sar eax, 8
    11. mov B, al
    2b) asm: (мой вариант c shl/shr)
    Код (Text):
    1. mov edx, A.Value
    2. movzx ecx, dl
    3. movzx eax, dl // 1 (B 28)
    4. shl eax,3   // 8
    5. sub eax,ecx // 7 (-)
    6. shl eax,2   // 28
    7. mov ebx,eax // store
    8.  
    9. movzx ecx, dh
    10. movzx eax, dh // 1 (G 151)
    11. shl eax,2   // 4
    12. add eax,ecx // 5 (+)
    13. shl eax,2   // 20
    14. sub eax,ecx // 19 (-)
    15. shl eax,3   // 152
    16. sub eax,ecx // 151 (-)
    17. add ebx,eax // store
    18.  
    19. shr edx, 8
    20. movzx ecx, dh
    21. movzx eax, dh // 1 (R 77)
    22. shl eax,2   // 4
    23. add eax,ecx // 5  (+)
    24. shl eax,2   // 20
    25. sub eax,ecx // 19 (-)
    26. shl eax,2   // 76
    27. add eax,ecx // 77 (+)
    28.  
    29. add eax, ebx // store all
    30. sar eax, 8
    31. mov B, al
    1. А быстрее можно ( чем asm: ) ?
    Оптимизация нужна под Pentium, P!! - P!!! - PIV, т.е. более менее универсальная. Правда если есть "частные" случаи оптимизации тоже будет интересно. Пробовалось заменить imul на shr/shl - выигрыша не было (см. пример).

    2. По ходу вопрос как мерять производительность выполения кода функцией Win32 ? QueryPerformanceCounter()? GetTickCount()?
     
  2. asmfan

    asmfan New Member

    Публикаций:
    0
    Регистрация:
    10 июл 2006
    Сообщения:
    1.004
    Адрес:
    Abaddon
    Используй потоковые инструкции mmx, sse, проч.
     
  3. KeSqueer

    KeSqueer Сергей

    Публикаций:
    0
    Регистрация:
    19 июл 2007
    Сообщения:
    1.183
    Адрес:
    Москва
    Числа небольшие, можно табличку составить на 256*3*2 байт. Если жалко килобайта, можно динамически ее заполнить.
     
  4. reverser

    reverser New Member

    Публикаций:
    0
    Регистрация:
    27 янв 2004
    Сообщения:
    615
    CL /Ox предлагает такое (вход в ecx):
    Код (Text):
    1. mov     eax, ecx
    2. shr     eax, 8
    3. movzx   edx, al
    4. mov     eax, ecx
    5. imul    edx, 151
    6. shr     eax, 16
    7. movzx   eax, al
    8. movzx   ecx, cl
    9. imul    ecx, 77
    10. push    esi
    11. lea     esi, DWORD PTR [eax*8]
    12. sub     esi, eax
    13. lea     eax, DWORD PTR [edx+esi*4]
    14. add     eax, ecx
    15. cdq
    16. and     edx, 255
    17. add     eax, edx
    18. sar     eax, 8
    19. movzx   eax, al
    20. pop     esi
     
  5. NoResponse

    NoResponse New Member

    Публикаций:
    0
    Регистрация:
    28 дек 2005
    Сообщения:
    89
    Код (Text):
    1. .DATA
    2.     Val_77_151_28       DQ 0000004D0097001Ch
    3.     Val_000000000000FF  DQ 00000000000000FFh
    4.  
    5. .CODE
    6. ...
    7.     movd        MM0, eax
    8.     pxor        MM1, MM1
    9.     punpcklbw   MM0, MM1
    10.     pmullw      MM0, Val_77_151_28
    11.     movq        MM1, MM0
    12.     movq        MM2, MM0
    13.     psrlq       MM0, 8
    14.     psrlq       MM1, 24
    15.     psrlq       MM2, 40
    16.     pand        MM0, Val_000000000000FF
    17.     pand        MM1, Val_000000000000FF
    18.     paddusw     MM0, MM1
    19.     paddusw     MM0, MM2
    20.     movd        eax, MM0
    21. ...
     
  6. KeSqueer

    KeSqueer Сергей

    Публикаций:
    0
    Регистрация:
    19 июл 2007
    Сообщения:
    1.183
    Адрес:
    Москва
    NoResponse
    Не правильно делать таким способом. При сдвиге, который используется в примере (psrlq mm0, 8 и др.) теряются младшие 8 бит произведения, что влияет на сумму в итоге.
     
  7. sarin

    sarin Member

    Публикаций:
    0
    Регистрация:
    2 июн 2005
    Сообщения:
    30
    reverver
    Ваш вариант медленнее в 1.2375 раза чем мой 2a) :dntknw:
    Интересно, какой CL/MSVC вы использовали?

    По совету KeSqueer появился вариант с таблицей. Вышло быстрее варианта 2a) в 1.5 раза. Другие оптимизации медленнее этой в 1.75 - 2 раза.

    Код (Text):
    1. ...
    2. unsigned short vv, rv[256],gv[256],bv[256];
    3. ...
    4.  
    5. ...
    6. for (vv = 0; vv < 256 ; vv++) // fill tables :)
    7. {
    8. rv[vv] = vv * 77; gv[vv] = vv * 151; bv[vv] = vv * 28;
    9. }
    10. ...
    11.  
    12. ...
    13. mov edx, A.Value
    14. movzx eax, dl
    15. movzx ecx, dh
    16. shr edx,16
    17. movzx eax,word ptr [bv + eax*2]
    18. movzx ecx,word ptr [gv + ecx*2]
    19. movzx edx,word ptr [rv + edx*2]
    20. add eax,ecx
    21. add eax,edx
    22. sar eax, 8
    23. mov B, al
    А такой вариант выдал Intel C++ 7.0 ( icl.exe /Ox ) :
    Код (Text):
    1. mov         eax,A.uValue
    2. movzx       edi,al                    
    3. mov         edx,eax                    
    4. shr         edx,000000010 ;' '        
    5. movzx       ecx,dl                    
    6. lea         edx,[ecx][ecx]            
    7. add         edx,edx                    
    8. sub         edx,ecx                    
    9. add         edx,edx                    
    10. add         edx,edx                    
    11. sub         edx,ecx                    
    12. lea         ecx,[edx][edx]            
    13. add         ecx,ecx                    
    14. add         ecx,ecx                    
    15. sub         ecx,edx                    
    16. shr         eax,8                      
    17. movzx       edx,al                    
    18. lea         eax,[edx][edx]*4          
    19. add         eax,eax                    
    20. add         eax,eax                    
    21. sub         eax,edx                    
    22. add         eax,eax                    
    23. add         eax,eax                    
    24. add         eax,eax                    
    25. sub         eax,edx                    
    26. add         ecx,eax                    
    27. add         edi,edi                    
    28. add         edi,edi                    
    29. lea         eax,[edi][edi]            
    30. add         eax,eax                    
    31. add         eax,eax                    
    32. sub         eax,edi                    
    33. add         ecx,eax                    
    34. sar         ecx,8                      
    35. mov         B, cl
    На P4 он работал шустрее 2а) до тех пор пока не появился вариант с таблицей.
     
  8. asmfan

    asmfan New Member

    Публикаций:
    0
    Регистрация:
    10 июл 2006
    Сообщения:
    1.004
    Адрес:
    Abaddon
    Код (Text):
    1.         punpcklbw       mm1,[ARGB_32bit]
    2.         psrlw   mm1,8
    3.         pmaddwd mm1,[Scale_0_77_151_28]
    4.         movq    mm2,mm1
    5.         psrlq   mm1,32
    6.         paddd   mm2,mm1
    7.         psrld   mm2,8
    8.         movd    eax,mm2
    для sse тоже самое,толь константу увеличиваем *2, не забывая про 0 вместо альфа компоненты, для зануления при умножении и двигаемся на каждой итерации не на 4, а на 8, т.е. 2 пиксела за раз и это без разроливания (unroll)
     
  9. S_Alex

    S_Alex Alex

    Публикаций:
    0
    Регистрация:
    27 авг 2004
    Сообщения:
    561
    Адрес:
    Ukraine
    При переводе цвета в монохром в одной из своих прог использовал вот такой кусок кода.
    Не помню как мне это пришло на ум, и комменты я не силен писать.
    Могу только сказать, что реально работало. Скорость не тестировал.

    Исходный цвет в eax == A.Value

    результат в BL

    ;<32to8
    mov ecx, eax

    and eax, 000ff00ffh
    mov ebx, 0001D004Ch
    mul ebx
    and eax, 0FFFFh
    add edx, eax

    mov eax, ecx
    mov ah,
    mul ah
    add dx, ax
    mov bl, dh
    ;>32to8
     
  10. sarin

    sarin Member

    Публикаций:
    0
    Регистрация:
    2 июн 2005
    Сообщения:
    30
    В итоге на P-4 вариант от S_Alex оказался медленнее табличного в 1.5 раза, а MMX-вариант от asmfan - в 2 раза.
     
  11. t00x

    t00x New Member

    Публикаций:
    0
    Регистрация:
    15 фев 2007
    Сообщения:
    1.921
    как и все частотники, P4 эффективно обрабатывает объёмные линейные вычисления.
     
  12. asmfan

    asmfan New Member

    Публикаций:
    0
    Регистрация:
    10 июл 2006
    Сообщения:
    1.004
    Адрес:
    Abaddon
    sarin
    На каком объёме данных тестировали? SSE вариант не тестировали? только ММХ?
     
  13. sarin

    sarin Member

    Публикаций:
    0
    Регистрация:
    2 июн 2005
    Сообщения:
    30
    А так, видимо, короче но чуть медленнее (таблица выравнена по dword).
    Код (Text):
    1. ...
    2. unsigned long vv, rv[256],gv[256],bv[256];
    3. ...
    4.  
    5. ...
    6. for (vv = 0; vv < 256 ; vv++) // fill tables :)
    7. {
    8. rv[vv] = vv * 77; gv[vv] = vv * 151; bv[vv] = vv * 28;
    9. }
    10. ...
    11.  
    12. ...
    13. mov edx, A.Value
    14. movzx eax, dl
    15. movzx ecx, dh
    16. shr edx,16
    17. mov eax,dword ptr [bv + eax*4]
    18. add eax,dword ptr [gv + ecx*4]
    19. add eax,dword ptr [rv + edx*4]
    20. sar eax, 8
    21. mov B, al
     
  14. sarin

    sarin Member

    Публикаций:
    0
    Регистрация:
    2 июн 2005
    Сообщения:
    30
    asmfan
    8192 пикселов т.е. разных значений ARGB из труколорной текстуры в оперативной памяти PC. А таблица ведь один раз заполняется и всё. Цель затеи - перегнать 32/24-bit картинку x*y т.е. любого размера ( правда x всегда кратен 8-ми ) в 8-bit greyscale максимально быстрым методом.
     
  15. asmfan

    asmfan New Member

    Публикаций:
    0
    Регистрация:
    10 июл 2006
    Сообщения:
    1.004
    Адрес:
    Abaddon
    В смысле? пикселов? или повторения над одним и тем же пикселом циклов? Если синтетика, то не тадо брать такие большие значения ибо переключения контекстов, если вживую на картинке, то это реальнее.
    По идее табличный метод должне выиграть на достаточно больших объёмах т.к. заполнение таблицы займет сравнительно меньшее время чем остальные операции, можно ещё ускориться - не заполнять таблицу, а хранить её как статические данные. 3KB можно себе позволить если скорость критична.
     
  16. KeSqueer

    KeSqueer Сергей

    Публикаций:
    0
    Регистрация:
    19 июл 2007
    Сообщения:
    1.183
    Адрес:
    Москва
    Мелочь, но позволю заметить:
    sar eax, 8
    mov , al
    можно заменить на mov , ah.
     
  17. SEA

    SEA New Member

    Публикаций:
    0
    Регистрация:
    8 фев 2008
    Сообщения:
    17
    там про просто Pentium было написано. Тогда точно так быстрее будет (для 2х пикселов сразу). Для Pentium II + не уверен, но, думаю, не хуже.

    mov edx, A.Value1
    mov ebx, A.Value2
    movzx eax,dl
    movzx ecx,bl
    movzx esi, dh
    movzx edi, bh
    shr edx,16
    shr ebx,16
    mov ax,word ptr [bv + eax*2]
    mov cx,word ptr [bv + ecx*2]
    add ax,word ptr [gv + esi*2]
    add cx,word ptr [gv + edi*2]
    add ax,word ptr [rv + edx*2]
    add cx,word ptr [rv + ebx*2]
    mov B1, ah
    mov B2, ch
     
  18. SEA

    SEA New Member

    Публикаций:
    0
    Регистрация:
    8 фев 2008
    Сообщения:
    17
    Ещё, уже точно не помню, но вполне возможно, что movzx в первом пентиуме была микрокодовой командой (несколько тактов без распараллеливания). Тогда начало надо переписать, например, так:
    mov edx,A.Value1
    mov ebx,A.value2
    xor eax,eax
    xor ecx,ecx
    xor esi,esi
    xor edi,edi
    mov al,dl
    mov cl,bl
    mov si,dx
    mov di,bx
    shr esi,8
    shr edi,8

    Вообще, сколь интересно было оптимизировать под первый пентиум. Когда я понял, что почти все методы во втором пентиуме не работают, я практически перестал программировать на асме.