Advanced member
Статус: Не в сети Регистрация: 09.06.2003 Откуда: USSR
Вот назрел вопрос о создании процедуры сравнения двух блоков памяти и нахождение кол-ва не совпадений.
Задача такая, блоки памяти одинакового размера и всегда кратны 4. Сравнение идет не по байтам , а по DWORD.
Стандартная CompareMem в Delphi пашет очень быстро, сравнение двух блоков по 30 мегов каждый проходит за 40-42 тика (GetTickCount до и после), но эта процедура выходит при нахождении первого не совпадения.
Я набросал простой вариант
Код:
function MCompareMem(p1, p2: pointer; size: Integer;var mismatch:dword): boolean; var i:longint; dw1,dw2:^DWORD; ms:dword; begin dw1:=p1; dw2:=p2; mismatch:=0; ms:=size div 4; for i:=1 to ms do begin if dw1^<>dw2^ then begin inc(mismatch); end; inc(dw1);inc(dw2); end; result:=mismatch=0; end;
по скорости также как и CompareMem , но вот думаю может можно как то еще ускорить? У кого есть идеи?
Advanced member
Статус: Не в сети Регистрация: 09.06.2003 Откуда: USSR
Asteroid Как раз нет, я специально смотрел что получается в АСМе, так вот
Код:
for ms := size div 4 - 1 downto 0 do ...
ты уверен что это меньше в асме? Я нет
serj_ Да вот понадобилось , насчет асма, так этот код Delphi сам прекрасно перевел в асм , даже лучше чем я сам бы это сделал.
Просто подумываю над чем то иным, скажем с применение SSE !
Advanced member
Статус: Не в сети Регистрация: 10.04.2003 Откуда: Москва
Ray Adams писал(а):
скажем с применение SSE !
ага! давай, давай ... и получишь дикий провал для AMD. Ладно, не хочешь сознаваться - твои проблемы.
Если сравниваются большие блоки, очень помогает prefetchnta. Для сравнения надо их выдавать два раза.
Кроме того, обязательно надо align 16 по первой инструкции цикла. И ... цикл с одной проверкой внутри себя - это уже порядка х2 меньше скорость.
Операции надо-бы делать с блоком.
(ты все еще хочешь обойтись без asm? )
Member
Статус: Не в сети Регистрация: 23.09.2003 Откуда: South Ural
Ray Adams по алгоритму: сравнение есть вычитание и если нужно знать количество всех несовпадений вычитать нужно все оптимизировать тут практически нечего
по реализации: лучше всего конечно асмовская вставка - никакой компилятор не сможет понять что все что тебе нужно есть подобие repe cmps но рассматривая код сгенерированный делфи много чего есть улучшить не прибегая к асму и оптимизации под конкретные процессоры, выравнивания, парабельность команд, sse и т.п.
1. избегаем локальных переменных - они храняться в стеке - что есть память и работа с ними медленнее чем с регистрами; полезно также знать что делфи при использовании стандартного вызова fastcall старается разместить параметры в регистрах:
учитывая все это и то что с p1 и p2 работаем в цикле присваивание dw1:=p1; dw2:=p2; явно невыгодно (переносим переменные в медленную память из быстрого процессора )
2. мелкая оптимизация по размеру + помещение переменной в регистр вместо ms:=size div 4 лучше написать size:=size shr 2;
3. использование цикла while do вместо for to - избавляемся от лишней локальной (стековой) переменной i
в результате получается что-то типа этого - возможно даже заработает - я не проверял
Код:
type pDWord = ^longword; begin mismatch := 0; size := size shr 2; while size >= 0 do begin if pDWord(p1)^ = pDWord(p2)^ then begin inc(integer(p1), 4); inc(integer(p2), 4); dec(size); end else inc(mismatch); end; result:=mismatch=0; end;
Advanced member
Статус: Не в сети Регистрация: 09.06.2003 Откуда: USSR
serj_ Да я согласен и на АСМ, галвное чтобы быстро было, а что SSE такой фиговый под AMD полчуается? Ну тогда можно и на MMX, хотя это всеже тривиальная задача и все решается простейшими способами.
Цитата:
Ладно, не хочешь сознаваться - твои проблемы.
Сознаваться в чем?
stargaz0r проверил таже скорость 62 тика. Видимо уже оптимизировать это только перевода на АСМ хотя не уверен в том что будет лучше.
Но надо попробовать.
Advanced member
Статус: Не в сети Регистрация: 09.06.2003 Откуда: USSR
stargaz0r не совсем понял как именно это сделать может модифицировать стандартную процедуру?
Код:
function CompareMem(P1, P2: Pointer; Length: Integer): Boolean; assembler; asm PUSH ESI PUSH EDI MOV ESI,P1 MOV EDI,P2 MOV EDX,ECX XOR EAX,EAX AND EDX,3 SAR ECX,2 JS @@1 // Negative Length implies identity. REPE CMPSD JNE @@2 MOV ECX,EDX REPE CMPSB JNE @@2 @@1: INC EAX @@2: POP EDI POP ESI end;
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 5
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения