неужели сдвиг так быстро работает?

Тема в разделе "WASM.HEAP", создана пользователем _basmp_, 21 мар 2009.

  1. _basmp_

    _basmp_ New Member

    Публикаций:
    0
    Регистрация:
    10 июл 2005
    Сообщения:
    2.939
    бенч
    Код (Text):
    1. #include <stdio.h>
    2. #include <time.h>
    3.  
    4.  
    5. void
    6. main(){
    7.     char *b1, *b2;
    8.     int i;
    9.     unsigned clkb1, clkl1;
    10.     time_t tb1, te1;
    11.     unsigned clkb4, clkl4;
    12.     time_t tb4, te4;
    13.  
    14.     b1 = (char*)malloc(10*1024*1024);
    15.     b2 = (char*)malloc(10*1024*1024);
    16.  
    17.  
    18.     __asm{
    19.         push esi
    20.         push edi
    21.         push ecx
    22.         push edx
    23.     }
    24.  
    25.  
    26. // by dword copying bench
    27.     tb4 = time(0);
    28.     __asm{
    29.         rdtsc
    30.         mov clkl4,eax
    31.         mov clkb4,edx
    32.     }
    33.  
    34. // 1.000x copy b1 --> b2 by dwords with format coversion
    35.     //for( i=0; i<1000; i++){
    36.     __asm{
    37.         mov edx,1000
    38.     }
    39.     test_loop_4:
    40.         __asm{
    41.             mov esi,b1
    42.             mov edi,b2
    43.             mov ecx,10*1024*1024/4
    44.         }
    45.         copy4_loop:
    46.         __asm{
    47.             lodsd
    48.             bswap eax
    49.             stosd
    50.             dec ecx
    51.             jnz short copy4_loop
    52.         }
    53.     __asm{
    54.         dec edx
    55.         jnz short test_loop_4
    56.     }
    57.     //}
    58.  
    59.     __asm{
    60.         rdtsc
    61.         sub eax,clkl4
    62.         sbb edx,clkb4
    63.         mov clkl4,eax
    64.         mov clkb4,edx
    65.     }
    66.     te4 = time(0);
    67.  
    68.  
    69. // by byte copying bench
    70.     tb1 = time(0);
    71.     __asm{
    72.         rdtsc
    73.         mov clkl1,eax
    74.         mov clkb1,edx
    75.     }
    76.  
    77. // 1.000x copy b1 --> b2 by bytes
    78.     //for( i=0; i<1000; i++){
    79.     __asm{
    80.         mov edx,1000
    81.     }
    82.     test_loop_1:
    83.         __asm{
    84.             mov esi,b1
    85.             mov edi,b2
    86.             mov ecx,10*1024*1024/4
    87.         }
    88.         copy1_loop:
    89.         __asm{
    90.             mov eax,[esi]
    91.             shr eax,24
    92.             stosb
    93.             ;--
    94.             mov eax,[esi]
    95.             shr eax,16
    96.             and eax,0ffh
    97.             stosb
    98.             ;--
    99.             mov eax,[esi]
    100.             shr eax,8
    101.             and eax,0ffh
    102.             stosb
    103.             ;--
    104.             lodsd
    105.             and eax,0ffh
    106.             stosb
    107.             ;--
    108.             dec ecx
    109.             jnz short copy1_loop
    110.         }
    111.     __asm{
    112.         dec edx
    113.         jnz short test_loop_1
    114.     }
    115.     //}
    116.  
    117.     __asm{
    118.         rdtsc
    119.         sub eax,clkl1
    120.         sbb edx,clkb1
    121.         mov clkl1,eax
    122.         mov clkb1,edx
    123.     }
    124.     te1 = time(0);
    125.  
    126.  
    127.  
    128.     __asm{
    129.         pop edx
    130.         pop ecx
    131.         pop edi
    132.         pop esi
    133.     }
    134.  
    135.     printf("1.000x copys b1[ 10meg ] --> b2[ 10meg ] \n"
    136.         "---\n"
    137.         "by dword with conversion between 'le' and 'be' forms takes \n"
    138.         "\t0x%X:%X processor clocks or \n"
    139.         "\t%.0f seconds\n"
    140.         "---\n"
    141.         "by byte with conversion between 'le' and 'be' as proposed takes \n"
    142.         "\t0x%X:%X processor clocks or \n"
    143.         "\t%.0f seconds",
    144.             clkb4, clkl4,
    145.             difftime(te4, tb4),
    146.             clkb1, clkl1,
    147.             difftime(te1, tb1)
    148.     );
    149. }
    выдает мне резулт
    неужели все эти сдвиги/энды так быстро работают?
     
  2. PSR1257

    PSR1257 New Member

    Публикаций:
    0
    Регистрация:
    30 ноя 2008
    Сообщения:
    933
    Мое имхо что у тебя все основное время жреццо на эти lodsd/stosb (а все остальное мелочь), а если сделать по 8 или 16 байт блоки типа

    add esi,8
    mov eax,[esi-8]
    mov ebx,[esi-4]
    ...
    bswap eax
    bswap ebx
    ...
    mov [edi-8],eax

    то будет другая картина..
     
  3. Pavia

    Pavia Well-Known Member

    Публикаций:
    0
    Регистрация:
    17 июн 2003
    Сообщения:
    2.409
    Адрес:
    Fryazino
    А какой процессор?
    У меня коре 2 дуе.
    У тебя используется медленная инструкция lodsd/stosb.
    Медленная она по двум причинам первая это потому чото использует для чтения и записи байты. На которые тратятся по тику или 0.5 По этому если читать писать блоками по несколько байт DWord к примеру то экономим в скорости в 4 раза. Поэтому лучше через MMX или SSE 64 и 128бит читаются и пишуться за раз.

    Процессор за один такт может выполнять несколько не зависимых инструкций. Так что хорошим результатом будет 1 тик чтение и 1 запись так как зависимые инструкции и еще 0-1 на вычисления.

    lodsd/stosb вторая особенность это тормоза из за того что помимо сложений она выполняет увелечение счетчиков что неспариваются поэтому инструкция выполняется медленее. А эти вещи можно загнать в вычисления адресса которое может делаться паралельно.

    Остается учесть размеры данных и скорость интерфейса. И получить новый придел в 8*800=64 ГБайт/с.
     
  4. _basmp_

    _basmp_ New Member

    Публикаций:
    0
    Регистрация:
    10 июл 2005
    Сообщения:
    2.939
    без лодс/стос
    Код (Text):
    1. #include <stdio.h>
    2. #include <time.h>
    3.  
    4.  
    5. void
    6. main(){
    7.     char *b1, *b2;
    8.     int i;
    9.     unsigned clkb1, clkl1;
    10.     time_t tb1, te1;
    11.     unsigned clkb4, clkl4;
    12.     time_t tb4, te4;
    13.  
    14.     b1 = (char*)malloc(10*1024*1024);
    15.     b2 = (char*)malloc(10*1024*1024);
    16.  
    17.  
    18.     __asm{
    19.         push esi
    20.         push edi
    21.         push ecx
    22.         push edx
    23.     }
    24.  
    25.  
    26. // by dword copying bench
    27.     tb4 = time(0);
    28.     __asm{
    29.         rdtsc
    30.         mov clkl4,eax
    31.         mov clkb4,edx
    32.     }
    33.  
    34. // 1.000x copy b1 --> b2 by dwords with format coversion
    35.     //for( i=0; i<1000; i++){
    36.     __asm{
    37.         mov edx,1000
    38.     }
    39.     test_loop_4:
    40.         __asm{
    41.             mov esi,b1
    42.             mov edi,b2
    43.             mov ecx,10*1024*1024/4
    44.         }
    45.         copy4_loop:
    46.         __asm{
    47.             mov eax,[esi]
    48.             bswap eax
    49.             mov [edi],eax
    50.             add esi,4
    51.             add edi,4
    52.             dec ecx
    53.             jnz short copy4_loop
    54.         }
    55.     __asm{
    56.         dec edx
    57.         jnz short test_loop_4
    58.     }
    59.     //}
    60.  
    61.     __asm{
    62.         rdtsc
    63.         sub eax,clkl4
    64.         sbb edx,clkb4
    65.         mov clkl4,eax
    66.         mov clkb4,edx
    67.     }
    68.     te4 = time(0);
    69.  
    70.  
    71. // by byte copying bench
    72.     tb1 = time(0);
    73.     __asm{
    74.         rdtsc
    75.         mov clkl1,eax
    76.         mov clkb1,edx
    77.     }
    78.  
    79. // 1.000x copy b1 --> b2 by bytes
    80.     //for( i=0; i<1000; i++){
    81.     __asm{
    82.         mov edx,1000
    83.     }
    84.     test_loop_1:
    85.         __asm{
    86.             mov esi,b1
    87.             mov edi,b2
    88.             mov ecx,10*1024*1024/4
    89.         }
    90.         copy1_loop:
    91.         __asm{
    92.             mov eax,[esi]
    93.             shr eax,24
    94.             mov [edi],al
    95.             inc edi
    96.             ;--
    97.             mov eax,[esi]
    98.             shr eax,16
    99.             and eax,0ffh
    100.             mov [edi],al
    101.             inc edi
    102.             ;--
    103.             mov eax,[esi]
    104.             shr eax,8
    105.             and eax,0ffh
    106.             mov [edi],al
    107.             inc edi
    108.             ;--
    109.             mov eax,[esi]
    110.             and eax,0ffh
    111.             mov [edi],al
    112.             inc edi
    113.             ;--
    114.             add esi,4
    115.             dec ecx
    116.             jnz short copy1_loop
    117.         }
    118.     __asm{
    119.         dec edx
    120.         jnz short test_loop_1
    121.     }
    122.     //}
    123.  
    124.     __asm{
    125.         rdtsc
    126.         sub eax,clkl1
    127.         sbb edx,clkb1
    128.         mov clkl1,eax
    129.         mov clkb1,edx
    130.     }
    131.     te1 = time(0);
    132.  
    133.  
    134.  
    135.     __asm{
    136.         pop edx
    137.         pop ecx
    138.         pop edi
    139.         pop esi
    140.     }
    141.  
    142.     printf("1.000x copys b1[ 10meg ] --> b2[ 10meg ] \n"
    143.         "---\n"
    144.         "by dword with conversion between 'le' and 'be' forms takes \n"
    145.         "\t0x%X:%X processor clocks or \n"
    146.         "\t%.0f seconds\n"
    147.         "---\n"
    148.         "by byte with with conversion between 'le' and 'be' as proposed takes \n"
    149.         "\t0x%X:%X processor clocks or \n"
    150.         "\t%.0f seconds",
    151.             clkb4, clkl4,
    152.             difftime(te4, tb4),
    153.             clkb1, clkl1,
    154.             difftime(te1, tb1)
    155.     );
    156. }
    еще меньше разницы. видать потому, что лодсы/стосы не спариваются
    нет, я конечно понимаю, что кэш выравнивает байты и дворды и что основную задержку вносит чтение/запись линеек кэша.. но всетаки я удивлен такой микроскопической разницей.

    ath 2000+, pc2100
     
  5. aa_dav

    aa_dav Active Member

    Публикаций:
    0
    Регистрация:
    24 дек 2008
    Сообщения:
    443
    У тебя получился не тест инструкций, а тест кеша/пропускной способности памяти.
    Похожий результат получал недавно тестируя сумму векторов на FPU vs SSE2. При размере векторов до 10000 (16-тибайтных структур) SSE2 рвал FPU в полтора-два раза, но при увеличении массивов разрыв стремительно сокращался и при 100000 разница была уже порядка 8 процентов. Потому что тест уперся в пропускную способность памяти.
     
  6. _basmp_

    _basmp_ New Member

    Публикаций:
    0
    Регистрация:
    10 июл 2005
    Сообщения:
    2.939
    aa_dav
    вот и я так думаю. гдето правда читал, что для доступа к кэшам тратятся лишние такты, но память видать очень сильнее перекрывает.
    кстати почему не тест инструкций? побочное наблюдение - при работе с большим объемом памяти даже подряд идущей, что 2 команды, что десяток.
     
  7. aa_dav

    aa_dav Active Member

    Публикаций:
    0
    Регистрация:
    24 дек 2008
    Сообщения:
    443
    Вот, кстати, при обсуждении того же теста FPU vs SSE2 один человек высказал эмпирический принцип, который вроде как в современных x86 имеет место соблюдаться - что на 1 инструкцию работающую с памятью должно быть не менее 5 инструкций, работающих с регистрами, чтобы соблюсти паритет узких мест. Т.е. если 1 инструкция доступа к памяти и от 1 до 5 команд работающих чисто с регистрами будут работать с одинаковой скоростью, т.к. всё упрется в память. Более (примерно) 5 команд на 1 доступ к памяти уже упираться будут в скорость этих команд. Как-то так.