Быстрый свап 16/8 байт

Тема в разделе "WASM.ASSEMBLER", создана пользователем DevilDevil, 22 мар 2010.

  1. DevilDevil

    DevilDevil Member

    Публикаций:
    0
    Регистрация:
    14 ноя 2007
    Сообщения:
    101
    имеется алгоритм быстрой сортировки 8-байтового массива и 16-байтового

    узкое место - свап элементов
    а = [eax+esi*SIZE]
    b = [eax+edi*SIZE]

    Вопрос. Как быстро осуществить свап ?
    Я делаю так (для 8 байт)
    Код (Text):
    1.             mov ecx, [eax+esi*8]
    2.             mov edx, [eax+edi*8]
    3.             mov [eax+edi*8], ecx
    4.             mov [eax+esi*8], edx
    5.  
    6.             mov edx, [eax+edi*8+4]
    7.             mov ecx, [eax+esi*8+4]
    8.             mov [eax+esi*8+4], edx
    9.             mov [eax+edi*8+4], ecx
     
  2. murder

    murder Member

    Публикаций:
    0
    Регистрация:
    3 июн 2007
    Сообщения:
    628
  3. murder

    murder Member

    Публикаций:
    0
    Регистрация:
    3 июн 2007
    Сообщения:
    628
    Для 16 байт - SSE.
     
  4. DevilDevil

    DevilDevil Member

    Публикаций:
    0
    Регистрация:
    14 ноя 2007
    Сообщения:
    101
    MMX/SSE я не знаю

    как это будет выглядеть ?

    ещё вопрос. Разумно ли использовать MMX/SSE для свапа ?
    переход из "обычного режима" в MMX/SSE, как я слышал, медленный. и для разового использования нецелесообразно
     
  5. murder

    murder Member

    Публикаций:
    0
    Регистрация:
    3 июн 2007
    Сообщения:
    628
    Такой переход нужно делать только для MMX в конце сортировки. Цель оправдывает средства.

    MMX
    Код (Text):
    1. movq mm0,[eax+esi*8]
    2. movq mm1,[eax+edi*8]
    3. movq [eax+esi*8],mm1
    4. movq [eax+edi*8],mm0
    По окончании сортировки нужно будет выполнить EMMS.

    SSE
    Код (Text):
    1. movups xmm0,[eax+esi*8]
    2. movups xmm1,[eax+edi*8]
    3. movups [eax+esi*8],xmm1
    4. movups [eax+edi*8],xmm0
    Но лучше будет выравнять массив по границе 16 байт и использовать movaps.
     
  6. DevilDevil

    DevilDevil Member

    Публикаций:
    0
    Регистрация:
    14 ноя 2007
    Сообщения:
    101
    Большое спасибо !

    murder
    ,
    первый случай для восьми байт, второй для 16 ?

    EMMS в конце MMX и SSE ? Для обоих случаев работает ?

    В случае 16 байт и esi/edi кратным двойке нормально будет так ?

    test eax, 15
    jz @1

    movups xmm0,[eax+esi*8]
    movups xmm1,[eax+edi*8]
    movups [eax+esi*8],xmm1
    movups [eax+edi*8],xmm0
    jmp @2

    @1:
    movaps xmm0,[eax+esi*8]
    movaps xmm1,[eax+edi*8]
    movaps [eax+esi*8],xmm1
    movaps [eax+edi*8],xmm0

    @2:
     
  7. DevilDevil

    DevilDevil Member

    Публикаций:
    0
    Регистрация:
    14 ноя 2007
    Сообщения:
    101
    ещё вопрос

    как определить: поддерживается ли SSE на машине
    ?
     
  8. Sol_Ksacap

    Sol_Ksacap Миша

    Публикаций:
    0
    Регистрация:
    6 мар 2008
    Сообщения:
    623
     
  9. DevilDevil

    DevilDevil Member

    Публикаций:
    0
    Регистрация:
    14 ноя 2007
    Сообщения:
    101
    Sol_Ksacap,

    Код (Text):
    1. asm
    2.   push ebx
    3.   mov eax, 1
    4.   cpuid
    5.   test edx, 02000000h
    6.   jz @Done
    7.   mov [SSE], 1
    8.   test edx, 04000000h
    9.   jz @Done
    10.   mov [SSE2], 1
    11. @Done:
    12.   pop ebx
    13. end;
     
  10. murder

    murder Member

    Публикаций:
    0
    Регистрация:
    3 июн 2007
    Сообщения:
    628
    EMMS только для MMX.

    http://www.wl.unn.ru/~ragozin/doc/mmx/mmx_main.htm

    Да.

    Нормально.
     
  11. DevilDevil

    DevilDevil Member

    Публикаций:
    0
    Регистрация:
    14 ноя 2007
    Сообщения:
    101
    murder,

    спасибо
    точно не нужно ничего делать после SSE ?
     
  12. DevilDevil

    DevilDevil Member

    Публикаций:
    0
    Регистрация:
    14 ноя 2007
    Сообщения:
    101
    Здравствуйте, друзья
    только сейчас занялся оптимизацией и понял, что MMX-вариант работает в 2.5 раза медленнее, чем обычный
    почему?
    размер массива - 100 элементов (по 16 байт каждый)

    Код (Text):
    1. procedure InvertArray16_MMX(var DynArray);
    2. asm
    3.   mov eax, [eax]
    4.   test eax, eax
    5.   jz @exit;
    6.   mov ecx, [eax-4]
    7.   {$ifdef fpc} inc ecx {$endif}
    8.   cmp ecx, 1
    9.   jle @exit
    10.  
    11.   // eax - left
    12.   // edx - right
    13.   // ecx - count
    14.   // mm0, mm1 - buffers
    15.   lea edx, [ecx*8]
    16.   lea edx, [eax+edx*2-16]
    17.   shr ecx, 1
    18.  
    19.   @loop:
    20.     // swap eax <--> edx
    21.  
    22.     movq mm0,[eax]
    23.     movq mm1,[edx]
    24.     movq [eax],mm1
    25.     movq [edx],mm0
    26.  
    27.     movq mm0,[eax+8]
    28.     movq mm1,[edx+8]
    29.     movq [eax+8],mm1
    30.     movq [edx+8],mm0
    31.  
    32.     add eax, 16
    33.     sub edx, 16
    34.   dec ecx
    35.   jnz @loop
    36.  
    37.   EMMS
    38.   @exit:
    39. end;
    40.  
    41. procedure InvertArray16_NORM(var DynArray);
    42. asm
    43.   mov eax, [eax]
    44.   test eax, eax
    45.   jz @exit;
    46.   mov ecx, [eax-4]
    47.   {$ifdef fpc} inc ecx {$endif}
    48.   cmp ecx, 1
    49.   jle @exit
    50.  
    51.   // eax - left
    52.   // edx - right
    53.   // ecx - count
    54.   // edi, esi - buffers
    55.   push esi
    56.   push edi
    57.   //lea edx, [eax+ecx*16-16]
    58.     lea edx, [ecx*8]
    59.     lea edx, [eax+edx*2-16]
    60.   shr ecx, 1
    61.  
    62.   @loop:
    63.     // swap eax <--> edx
    64.  
    65.     mov esi, [eax]
    66.     mov edi, [edx]
    67.     mov [eax], edi
    68.     mov [edx], esi
    69.  
    70.     mov esi, [eax+4]
    71.     mov edi, [edx+4]
    72.     mov [eax+4], edi
    73.     mov [edx+4], esi
    74.  
    75.     mov esi, [eax+8]
    76.     mov edi, [edx+8]
    77.     mov [eax+8], edi
    78.     mov [edx+8], esi
    79.  
    80.     mov esi, [eax+12]
    81.     mov edi, [edx+12]
    82.     mov [eax+12], edi
    83.     mov [edx+12], esi
    84.  
    85.  
    86.     add eax, 16
    87.     sub edx, 16
    88.   dec ecx
    89.   jnz @loop
    90.  
    91.   pop edi
    92.   pop esi
    93.  
    94.   @exit:
    95. end;
     
  13. edemko

    edemko New Member

    Публикаций:
    0
    Регистрация:
    25 ноя 2009
    Сообщения:
    454
    mov ecx,[eax-4]:
    тут число байт или элементов по 8 байт?
     
  14. DevilDevil

    DevilDevil Member

    Публикаций:
    0
    Регистрация:
    14 ноя 2007
    Сообщения:
    101
    edemko,
    это delphi-функции
    там в динамических массивах [указатель - 4] - количество элементов

    P.S.
    странно, но теперь MMX-вариант работает быстрее
    так и не понял почему
     
  15. edemko

    edemko New Member

    Публикаций:
    0
    Регистрация:
    25 ноя 2009
    Сообщения:
    454
    s:WideString;
    i:dword;
    i:=length(s);
    примерно, ибо не помню:
    mov eax,
    mov eax,[eax-4]
    shr eax,1 ;число байт в число wChar-символов
    mov ,1 ;число БАЙТ(редактировал) / число байт в элементе(2 для wChar)
    Посему и спрашивал, не надо ли там:
    shr ecx,3 // делить на 8 и узнать число элементов
    shr ecx,1 // число шагов для цикла реверсирования
    //или
    shr ecx,4 // вместо двух shr выше
    jz @exit // пустой масив
     
  16. edemko

    edemko New Member

    Публикаций:
    0
    Регистрация:
    25 ноя 2009
    Сообщения:
    454
    emms можно лишний раз не использовать, только перед задействованием инструкций FPU, но делфи, кажись, такого не ожидает и чего-то пишет об этом, ничего уже не помню толком.
     
  17. DevilDevil

    DevilDevil Member

    Публикаций:
    0
    Регистрация:
    14 ноя 2007
    Сообщения:
    101
    edemko,
    WideString - это единственное исключение
    во всех остальных случаях - количество элементов. Для FreePascal в [указатель - 4] хранится High массива, т.е. Length-1
     
  18. edemko

    edemko New Member

    Публикаций:
    0
    Регистрация:
    25 ноя 2009
    Сообщения:
    454
    понял
     
  19. Y_Mur

    Y_Mur Active Member

    Публикаций:
    0
    Регистрация:
    6 сен 2006
    Сообщения:
    2.494
    DevilDevil
    А тестовые массивы для сортировки небось заполняешь случайными числами и каждый раз разными? Следи чтобы оба варианта тестировались на одинаковых исходных данных ;)

    ЗЫ: сам на этом обжигался.
     
  20. edemko

    edemko New Member

    Публикаций:
    0
    Регистрация:
    25 ноя 2009
    Сообщения:
    454
    Масив сортируют?, если да, то даже на GP(простых инструкциях) будет упадок: всякое сравнение решает, писать ему или нет. mmx флагов не устанавливает, отсюда задержка на проверку даже больше от GP, хотя их размер 2xDWORD может компенсировать.

    Ну, я наверно не понял.
    Попробуйте GetTickCount на входе в тело и выходе.