Re[10]: Слишком сложно и к тому-же не верно работает :)
От: Aquila http://www.wasm.ru
Дата: 18.07.02 06:38
Оценка:
Здравствуйте Алексей Петров, Вы писали:

АП>Мне не надо считать позиции. Есть конкретная задача — максимально быстро посчитать число различий.


Есть конкретная задача — максимально быстро посчитать число различий. Надо учесть, что вопрос был задан в форуме по ассемблеру, поэтому можно предположить, что задавшего его интересовало решение на ассемблере.

А>>Человек это с трудом может закодировать — нужно знать длину каждой команды.

АП>Понятно, что с трудом. Но это как раз аргумент против чрезмерного увлечения асм-ом.

Этот аргумент отдыхает. Сейчас настолько быстрые компьютеры, что небольшое замедление, вызванное (возможно) неоптимальным решением человека, не играет никакой роли (мой любимый аргумент, который я позаимстововал у дельфистов ).
Re[12]: Слишком сложно и к тому-же не верно работает :)
От: Aquila http://www.wasm.ru
Дата: 18.07.02 06:46
Оценка:
Здравствуйте Алексей Петров, Вы писали:

АП>Все равно пофигу. Мне не нужно выпендриваться размером программы — это болезнь начинающих.


Флеймите, уважаемый. Но, как говорится, кто к нам с мечом придет, тот от оного и погибнет. Чай и сами не дураки и в местах пофлеймистей писали (гы — RU.OS.CMP).

АП>Опытный — согласен, при желании сгенерит и лучше, но станет этим заниматься только на очень критичной по времени функции и тогда, когда на ЯВУ мысли выразить сложнее, чем на asm.


Заметьте, (не)уважаемый, вы сейчас говорите не по делу. Такое впечатление, что вы так и ждете, как кинуться в бой с криком "Асм маздай! Дельфи рулит!". Мы находимся в форуме по ассемблеру. Решения на C++ следует приводить в _другом_ форуме.

>В остальных случаях дополнительные затраты времени и сил на asm не окупаются.


Слушай, я это где-то уже слышал . Только вот к чему ты это пишешь?

АП>А размером с тобой меряться — нет у меня желания, т.к. 5 — 10 байт не имеет значения в 20мегабайтном проекте. Если конечно весь его переписать руками (только не такими кривыми, как у тебя), он из 20 станет 15 мегабайтным, но не за год, а за 10 — а это не приемлемо.


Нехорошо ты на человека наехал. Не по понятиям живешь.
Re[9]: Слишком сложно и к тому-же не верно работает :)
От: Edmond  
Дата: 18.07.02 08:28
Оценка:
Поправка...

А>
А>    xor ecx,ecx               ;; Лучше, чтобы команда инкримента ecx была несколько позже...
        xor ebx,ebx               ;;
        inc ecx                   ;; Поплавок...
А>    mov eax,dword ptr i1+4
А>    xor eax,dword ptr i2+4
А>    jnz l1                     
;;А>l4:    inc ecx                   ;; Это теперь не надо!!!
А>    mov eax,dword ptr i1
А>    xor eax,dword ptr i2
А>    jz l3
        ;;А>l1:    bswap eax                ;; Зачем так жестоко?
        
l1:    test al,0Fh              ;; 
А>    jz @F
А>    inc ebx
А>@@:    test al,0F0h
А>    jz @F
А>    inc ebx

А>@@:    shr eax,8                 ;; Очень плохо!!! Очень, тут надо что-то придумать!!!
    jz l2

;; Развернём цикл мы не жадные, тем более, что есть маленькая тонкость...

А>    test al,0Fh              ;; Так, а теперь внимание, если это ноль, значит последняя точно не ноль!!!
А>    jz @F
А>    inc ebx                  ;; Хе-хе
А>@@:    inc ebx

        dec ecx                   ;; Приём поплавка!!!
        jnz l2
.................................................
.................................................
l3:
С уважением, Edmond
Re[10]: Слишком сложно и к тому-же не верно работает :)
От: Edmond  
Дата: 19.07.02 06:21
Оценка: 45 (3)
Делаю исправления и поправки на все предыдущие случаи и бросаю рабочий пример.
На этом и камень забиваем!!!



          .386
          .model flat
          option casemap :none   ; case sensitive
   
         .data
     
     str1    db 22h,33h,33h,11h,34h,33h,55h,99h
     str2    db 33h,44h,77h,22h,34h,77h,44h,88h  
   
          .code
_start:
EXTERN  __imp__ExitProcess@4:dword
        
        xor        eax,eax
        mov        ecx,0        ;; Вместо mov ecx,eax это стоит за тем, чтобы
                            ;; метка @@loop1 и @@loop2 была выравненной

        mov        eax, dword ptr str1
        xor        eax, dword ptr str2
        jz        @@word2        ;; Редко выполняеться

@@loop1:
        test    al,al
        jz        short    @@next1 ;; То же не часто..., но под конец частенько
        test    al,0fh        ; Если есть совпадение (ноль),
                            ; значит вторая часть точно не ноль 
        jz        short    @@1
; если совпадения нет  ( не ноль), значит
        inc        ecx
        test    al,0f0h
        jz        @@next1
@@1:    inc        ecx
        

@@next1:
        shr        eax,8
        jnz        short    @@loop1
@@word2:
        mov        eax, dword ptr str1+4
        xor        eax, dword ptr str2+4
;        jz        short    @@end
        

@@loop2:
        test    al,al
        jz        @@next2


        test    al,0fh        ; Если есть совпадение (ноль),
                            ; значит вторая часть точно не ноль 
        jz        @@2
; если совпадения нет  ( не ноль), значит
        inc        ecx
        test    al,0f0h
        jz        @@next2
@@2:    inc        ecx
        

@@next2:
        shr        eax,8
        jnz        short    @@loop2

                
@@end:

          push    ecx


        call __imp__ExitProcess@4
          
          end _start
С уважением, Edmond
Re[11]: Слишком сложно и к тому-же не верно работает :)
От: masquer Украина  
Дата: 19.07.02 08:51
Оценка:
Здравствуйте Edmond, Вы писали:

E>Делаю исправления и поправки на все предыдущие случаи и бросаю рабочий пример.

E>На этом и камень забиваем!!!

А моя реализация с ММХ (см. посты выше ) не канает?
Re[12]: Слишком сложно и к тому-же не верно работает :)
От: Edmond  
Дата: 19.07.02 09:38
Оценка:
Здравствуйте masquer, Вы писали:

M>Здравствуйте Edmond, Вы писали:


E>>Делаю исправления и поправки на все предыдущие случаи и бросаю рабочий пример.

E>>На этом и камень забиваем!!!

M>А моя реализация с ММХ (см. посты выше ) не канает?


ХМ... Ну так вообще с MMX своя проблемма.
Но если б ты её немного доканал... то...
С уважением, Edmond
Re[13]: Слишком сложно и к тому-же не верно работает :)
От: masquer Украина  
Дата: 19.07.02 11:50
Оценка:
Здравствуйте Edmond, Вы писали:

E>ХМ... Ну так вообще с MMX своя проблемма.

E>Но если б ты её немного доканал... то...

То есть... А в чем там проблема?
Re: Подведем итоги?
От: Алексей Петров Россия  
Дата: 22.07.02 08:23
Оценка:
Провожу тестирование разных вариантов.

Тестирование провожу следующим образом:
Все фрагменты кода привожу к виду функции с прототипом int __stdcall countDiffs(__int64 i1, __int64 i2) и с запретом inline.
и вызываю её 5 раз для проверки скорости выполнения на разных входных условиях:
Сравниваемые пары:
{0x1234567890123456, 0x1234567890123456}, // Полное совпадение
{0x8234567890123456, 0x1234567890123456}, // Отличае в 1-й цифре
{0x1234567890123459, 0x1234567890123456}, // Отличае в последней цифре
{0x2345678901234591, 0x1234567890123456}, // Нет совпадений
{0x1234568890123456, 0x1234567890123456} // Отличае в середине

Скорость меряю с помощью инструкции RDTSC процессора.

Вот результаты:

1) Эталон для замера накладных расходов:
volatile int Result=0;
int __stdcall DummyCall(__int64 a, __int64 b)
{
return Result;
}
Time=48, Result= 0 — OK
Time=46, Result= 0 — Fail
Time=48, Result= 0 — Fail
Time=46, Result= 0 — Fail
Time=46, Result= 0 — Fail
AvgTime=46.8

2) Вариант реализации "в лоб" на С:
int __stdcall countDiffs(__int64 a, __int64 b)
{
__int64 Temp = a ^ b;
int result = 0;
while (Temp)
{
if (Temp & 0xF)
result ++;
Temp >>= 4;
}
return result;
}
Оказался неудачным, т.к. >> транслируется как sar, а не shr (в отличаи от Delphi, на котором это когда-то работало),
что приводит зацикливанию при различаи в старшей цифре.

3) То-же на Delphi:
function Cmp(a, b: Int64): Integer; stdcall;
var
t: Int64;
begin
t := a xor b;
Result := 0;
while t<>0 do
begin
if t and $F<>0 then
Inc(Result);
t := t shr 4;
end;
end;
Time=79, Result= 0 — OK
Time=324, Result= 1 — OK
Time=95, Result= 1 — OK
Time=288, Result=16 — OK
Time=262, Result= 1 — OK
AvgTime=209.600000

4) пред-последний вариант от Алекс
Time=58, Result= 0 — OK
Time=105, Result= 1 — OK
Time=183, Result= 1 — OK
Time=249, Result=16 — OK
Time=139, Result= 1 — OK
AvgTime=146.800000

в последнем — опять ошибка. ebx, где потом результат накапливается не обнуляется предварительно. И работает он дольше.

5) Мой вариант на asm
Time=85, Result= 0 — OK
Time=172, Result= 1 — OK
Time=85, Result= 1 — OK
Time=234, Result=16 — OK
Time=102, Result= 1 — OK
AvgTime=135.600000

6) Вариант от Chorkov
не работает корректно:
Time=222, Result= 2 — Fail
Time=223, Result= 2 — Fail
Time=222, Result= 4 — Fail
Time=223, Result=10 — Fail
Time=223, Result= 2 — Fail
AvgTime=222.600000

6) Вариант от Edmond
Time=64, Result= 0 — OK
Time=133, Result= 1 — OK
Time=111, Result= 1 — OK
Time=256, Result=16 — OK
Time=73, Result= 1 — OK
AvgTime=127.400000

Что мне понравилось, так это обилие коментариев в коде, достаточное для понимания написанного, и выравнивание
на границу комманд, достигаемое путем выбора предшествующих операций из набора эквивалентных.
Мое почтение мастеру.

Вот и все.

Предлагаю всем поставить максимальный бал победителю в качестве награды.
Re[2]: Подведем итоги?
От: masquer Украина  
Дата: 22.07.02 16:21
Оценка: 15 (1)
Здравствуйте Алексей Петров, Вы писали:

АП>Вот и все.

Хотелось бы финальный аккорд на MMX предоставить, сонный был, немного не так задание понял . А если не 5 проходов задать а, скажем. 5 000 000. Можно результаты.

    .686
    .MMX
    .model flat, stdcall
    option casemap :none
    include \masm32\include\windows.inc
    include \masm32\include\user32.inc
    include \masm32\include\kernel32.inc

    includelib \masm32\lib\user32.lib
    includelib \masm32\lib\kernel32.lib

    Diff PROTO :QWORD, :QWORD

.data
align 4
d0_1 dq 1234567890123456h
d0_2 dq 1234567890123456h

d1_1 dq 8234567890123456h
d1_2 dq 1234567890123456h

d2_1 dq 1234567890123459h
d2_2 dq 1234567890123456h

d3_1 dq 2345678901234591h
d3_2 dq 1234567890123456h

d4_1 dq 1234568890123456h
d4_2 dq 1234567890123456h

eq1 dq 0101010101010101h
msk0f dq 0f0f0f0f0f0f0f0fh
.code
start:
    invoke Diff, d3_1, d3_2
    invoke ExitProcess,0

;---------------------------------
Diff proc a:QWORD, b:QWORD
    movq mm0, a
    movq mm1, mm0
    movq mm2, b
    movq mm3, mm2
    movq mm4, msk0f
    movq mm5, eq1

    psllw mm0, 4
    psllw mm2, 4

    psrlw mm0, 4
    psrlw mm2, 4

    psrlw mm1, 4
    psrlw mm3, 4

    pand mm0, mm4
    pand mm1, mm4
    pand mm2, mm4
    pand mm3, mm4

    pcmpeqb mm0,mm2
    pcmpeqb mm1,mm3

    paddb mm0, mm5
    paddb mm1, mm5
    paddb mm0, mm1
    pxor mm1, mm1
    psadbw mm0, mm1
    movd eax, mm0
    emms
    ret
Diff endp
end start
Re[3]: Подведем итоги?
От: Алексей Петров Россия  
Дата: 23.07.02 04:43
Оценка:
Здравствуйте masquer, Вы писали:

M>Хотелось бы финальный аккорд на MMX предоставить, сонный был, немного не так задание понял . А если не 5 проходов задать а, скажем. 5 000 000. Можно результаты.


Суперски:
Time=74, Result= 0 — OK
Time=72, Result= 1 — OK
Time=74, Result= 1 — OK
Time=72, Result=16 — OK
Time=72, Result= 1 — OK
AvgTime=72.800000

А 5 или 5000000 проходов — значения не имеет — RDTSC хорошая инструкция
Re[3]: Подведем итоги?
От: Алексей Петров Россия  
Дата: 23.07.02 04:49
Оценка:
Здравствуйте masquer, Вы писали:

M>Здравствуйте Алексей Петров, Вы писали:


АП>>Вот и все.

M>Хотелось бы финальный аккорд на MMX предоставить, сонный был, немного не так задание понял . А если не 5 проходов задать а, скажем. 5 000 000. Можно результаты.

А не мог бы ты снабдить комментариями свое творение, чтоб всем стало ясно, как оно работает. MMX-овский набор инструкция мало кто знает
Re[4]: Подведем итоги?
От: masquer Украина  
Дата: 23.07.02 05:44
Оценка: 32 (3)
Здравствуйте Алексей Петров, Вы писали:

АП>А не мог бы ты снабдить комментариями свое творение, чтоб всем стало ясно, как оно работает. MMX-овский набор инструкция мало кто знает :-Не верю (с) Станиславский



    movq mm0, a    ; загружаем сравниваемые числа
    movq mm1, mm0
    movq mm2, b
    movq mm3, mm2
    movq mm4, msk0f ; и маски как 64-битные числа
    movq mm5, eq1 
;--------------------------------------
    psllw mm0, 4 ; сдвигаем каждое слово влево на 4 бита
    psllw mm2, 4

    psrlw mm0, 4 ; сдвигаем каждое слово вправо на 4 бита
    psrlw mm2, 4

    psrlw mm1, 4 ; опять :)
    psrlw mm3, 4

    pand mm0, mm4 ; ложим маску
    pand mm1, mm4
    pand mm2, mm4
    pand mm3, mm4
; смысл всего этого сделать из
; mm0=1234567890123456
; mm0=0103050709010305
; mm1=0204060800020406
;--------------------------------------

    pcmpeqb mm0,mm2 ; сравниваем побайтно, если байты равны, в mm0 и mm1 каждый
    pcmpeqb mm1,mm3 ; соответствующий байт = FF, иначе  00

    paddb mm0, mm5 ; добавим 01 к каждому байту, получится 01 если не рывны были
    paddb mm1, mm5
    paddb mm0, mm1 ; просуммируем полученные "неравности" для 16 mm0=0202020202020202
    pxor mm1, mm1 ; обнулим mm1 для следующей команды
    psadbw mm0, mm1 ; требует проц не ниже P3, суммирует абсолютные значения разницы
    ; соответствующих байт и результат помещает в нижнее слово mm0
    movd eax, mm0 ; которое мы и сохраняем в eax
    emms ; для предосторожности чистим стек сопроцессора
Re[5]: Подведем итоги?
От: Edmond  
Дата: 23.07.02 07:06
Оценка:
Здравствуйте masquer, Вы писали:

M>Здравствуйте Алексей Петров, Вы писали:


АП>>А не мог бы ты снабдить комментариями свое творение, чтоб всем стало ясно, как оно работает. MMX-овский набор инструкция мало кто знает :-Не верю (с) Станиславский

M>

M>
M>    movq mm0, a    ; загружаем сравниваемые числа
M>    movq mm1, mm0
M>    movq mm2, b
M>    movq mm3, mm2
M>    movq mm4, msk0f ; и маски как 64-битные числа
M>    movq mm5, eq1 
M>;--------------------------------------
M>    psllw mm0, 4 ; сдвигаем каждое слово влево на 4 бита
M>    psllw mm2, 4

M>    psrlw mm0, 4 ; сдвигаем каждое слово вправо на 4 бита
M>    psrlw mm2, 4

M>    psrlw mm1, 4 ; опять :)
M>    psrlw mm3, 4

M>    pand mm0, mm4 ; ложим маску
M>    pand mm1, mm4
M>    pand mm2, mm4
M>    pand mm3, mm4
M>; смысл всего этого сделать из
M>; mm0=1234567890123456
M>; mm0=0103050709010305
M>; mm1=0204060800020406
M>;--------------------------------------

M>    pcmpeqb mm0,mm2 ; сравниваем побайтно, если байты равны, в mm0 и mm1 каждый
M>    pcmpeqb mm1,mm3 ; соответствующий байт = FF, иначе  00

M>    paddb mm0, mm5 ; добавим 01 к каждому байту, получится 01 если не рывны были
M>    paddb mm1, mm5
M>    paddb mm0, mm1 ; просуммируем полученные "неравности" для 16 mm0=0202020202020202
M>    pxor mm1, mm1 ; обнулим mm1 для следующей команды
M>    psadbw mm0, mm1 ; требует проц не ниже P3, суммирует абсолютные значения разницы
M>    ; соответствующих байт и результат помещает в нижнее слово mm0
M>    movd eax, mm0 ; которое мы и сохраняем в eax
M>    emms ; для предосторожности чистим стек сопроцессора
M>
С уважением, Edmond
Re[5]: Подведем итоги?
От: Edmond  
Дата: 23.07.02 07:07
Оценка: 3 (1)
Здравствуйте masquer, Вы писали:

M>Здравствуйте Алексей Петров, Вы писали:


АП>>А не мог бы ты снабдить комментариями свое творение, чтоб всем стало ясно, как оно работает. MMX-овский набор инструкция мало кто знает :-Не верю (с) Станиславский

M>

Ну вот, теперь конеает!!!
Мои поздравления
С уважением, Edmond
Re[6]: Подведем итоги?
От: masquer Украина  
Дата: 23.07.02 08:11
Оценка:
Здравствуйте Edmond, Вы писали:

E>Ну вот, теперь конеает!!!

E>Мои поздравления
Спасибо! Побольше бы таких конкурсов, интересно и проблему решить и для самообразования полезно.
Добавлю для тех, кто на МАСМ32 пишет (как я), что директиву .MMX на .XMM заменить нужно, иначе ругаться на инструкцию psadbw будет
Re[7]: Подведем итоги?
От: Аноним  
Дата: 23.07.02 08:24
Оценка:
Здравствуйте masquer, Вы писали:

M>Спасибо! Побольше бы таких конкурсов, интересно и проблему решить и для самообразования полезно.

А вместо спасибо (или вместе) здесь принято оценки ставить
Re[8]: Подведем итоги?
От: masquer Украина  
Дата: 24.07.02 10:26
Оценка:
Здравствуйте Аноним, Вы писали:

А>Здравствуйте masquer, Вы писали:


M>>Спасибо! Побольше бы таких конкурсов, интересно и проблему решить и для самообразования полезно.

А>А вместо спасибо (или вместе) здесь принято оценки ставить
Уже

добавлю сам себя. Если выравнять стек перед вызовом функции Diff (я свой код имею ввиду) на границу 8 байт, например так
sub esp, 8
and esp, 0fffffff0h
add esp, 8

то скорость где-то на 10-15% возрастет за счет попадания в кеш
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.