|
|
| Посл.отвђт | Сообщенiе |
|
|
Дата: Апр 25, 2004 15:31:28 Eraser Извини за дурость, а ты скорость чем измеряешь и в чем? :))) |
|
|
Дата: Апр 25, 2004 22:24:04 [Eraser: 2) Loop || dec ECX, jnz @@_for действительно пофигу.] а ты думаешь у всех p4-1600??? Например у моего друга 486 проц стоит... если так относиться к этому делу, то уж лучше на VB писать, типа все равно процы быстрые :))) зачем тогда вообще все это затеял? |
|
|
Дата: Апр 26, 2004 08:25:37 · Поправил: Eraser 2 EvilsInterrupt Смотри сообщение от Апр 24, 2004 12:29:57. 2 Mad_C Я не собираюсь "кидать" счастливых обладателей 486'х, просто я подтверждал _Chingachguk_'a Что Loop полезнее DEC ECX, JNZ @@_Метка на P120, а на P800 зто мало влияет на скорость. 2All А что на счёт передачи сложных структур FastCall'om, ответит кто нибудь? см три сообщения назад! |
|
|
Дата: Апр 26, 2004 11:25:38 А что на счёт передачи сложных структур FastCall'om, ответит кто нибудь? А что там отвечать? Как в eax или edx указатель на локальную структуру поместить? :) Вообще-то dec ecx, jnz побыстрее loop выходит, имхо |
|
|
Дата: Апр 26, 2004 13:12:49 · Поправил: S_T_A_S_ Привет :) Оптимизируем inner loops ? Так, смотрим условие задачи: -Прграмма загружает файл на 81mb в память. . Понятно.
AND ECX,000000FFH
MOV ECX,DWORD PTR [CRC_32_TAB+ECX*4]
Еще есть табличка 256*4байт. Тоже понятно.
К тому же не понятно, выровняна ли она по границе 256байт или нет? Дальше смотрим, например: P4 2600Mhz, 256mb DDR -результат 812, 250, 460 тиков. Ядро проца 2600Mhz, а память? 800 в случае DUAL DDR. Разница в скорости есть. Выводы: - узкое место - пропускная способность шины памяти. - поскольку используется обращзение к 2м блокам памяти неизбежно возникают конфликты банков кеша, что приводит к лишним операциям записи/чтения. Что же делать? - убрать табличку, если это возможно. - использовать предвыборку данных из памяти в кеш, для того чтобы ускорить их обработку. Для реализации 2го предложения алгоритм работы меняем на следующий: - по возможности "разворачиваем направление" чтения из памяти (т.е. с конца к началу) - основной цикл разбиваем примерно так: CACHELINE equ 20h ;; for Celerons etc CACHESIZE equ 20000h ;; 128Kb for celeron/duron mov ESI, source array mov ECX, number of bytes lea ESI, [ESI+ECX] neg ECX .l: add ECX, CACHESIZE ;; move up to end of cashed block mov EAX, CACHESIZE / (CACHELINE*2) ;; цикл развернут 2X ;; читаем данные в кеш процессора.. @@: mov ebx, [ESI+ECX-CACHELINE] ;; ..для этого читаем байт (из памяти считается строка кеша полностью)... mov ebx, [ESI+ECX-CACHELINE*2] ;; ... и еще для предыдущей строки кеша sub ECX, CACHELINE*2 dec EAX jnz @b ;; use data block from the cache mov EAX, CACHESIZE / 64 @@: ;; ЗДЕСЬ ОБРАБАТЫВАМ 64 байта данных ;; по адресам [esi+ecx] .. [esi+ecx+63] ;; если будет другое кол-во, меняем значение в ECX ниже и EAX выше ;; для примера цикл развернут add ECX, 64 dec EAX jnz @b or ECX, ECX jnz .l Иллюстрация разницы в скорости операций с памятью при использовании подобного приема здесь (не работает на старых процах из-за команд записи) Теоретические основы (англ. с картинками) ЗЫ Пинания меня приветствуются :) |
|
|
Дата: Апр 28, 2004 15:01:29 · Поправил: Eraser Если я правильно понял, при MOV EBX,[ESI] в кэш читаются данные размером CACHELINE, от адреса ESI по ESI+CACHELINE и при последующем запросе данных по адресу находящемуся в пределах от ESI до ESI+CACHELINE они читаются не из памяти ,а из кэша что ускоряет весь процесс. Но попробовав этот метод я не увидел ни какого прироста скорости, при этом если у каждого проца свой кэшлайн то функция теряет универсальность и метод KISS + ко всему увеличивает её размер. Вот что получилось у меня:
procedure IncPCRC32ASMCache(P:Pointer;Count:integer;var CRC:cardinal);assembler;
const
LineSize = $40;
TabSize = Length(CRC_32_TAB)*$20;
CntLine = TabSize div LineSize;
asm
CMP EDX,1
JL @@_END//Если Count<1 выходим
PUSH EBX
PUSH ESI
PUSH ECX
LEA ESI,[CRC_32_TAB+TabSize]//ESI указывает на конец таблицы CRC_32_TAB
MOV ECX,CntLine/2
@@LodCache:
MOV EBX,[ESI-LineSize]
MOV EBX,[ESI-LineSize*2]
SUB ESI,LineSize*2
DEC ECX
JNZ @@LodCache
POP ECX
MOV EBX,[ECX]
PUSH ECX
MOV ECX,EDX
MOV EDX,EAX
MOV EAX,EBX
@@CalcCRC:
XOR AL,BYTE PTR [EDX]
INC EDX
AND EAX,000000FFH
MOV EAX,DWORD PTR [ESI+EAX*4]
SHR EBX,8
XOR EAX,EBX
MOV EBX,EAX
LOOP @@CalcCRC
POP ECX
MOV [ECX],EBX
POP ESI
POP EBX
@@_END:
end;
Т.К не знаю какой CACHELINE у P4 перепробовал от 16 до 256. |
|
|
Дата: Апр 28, 2004 17:00:50 · Поправил: S_T_A_S_ [ Eraser : при MOV EBX,[ESI] в кэш читаются данные.. ..и при последующем запросе данных.. ..они читаются не из памяти, а из кэша что ускоряет весь процесс. ] Да, принцип такой. "Загружаем" блок из памяти в кеш в первом цикле и с ним уже работаем во втором. Накидал простой тест (само вычисление CRC я тут сильно упростил :) CACHELINE equ 20h ;; for Celerons etc CACHESIZE equ 20000h ;; 128Kb for celeron/duron mov ESI, src ;; source array mov ECX, [EBP+4] ;; number of bytes lea ESI, [ESI+ECX] neg ECX .l: add ECX, CACHESIZE mov EAX, CACHESIZE / (CACHELINE*2) ;; prefetch data @@: test ebx, [ESI+ECX-CACHELINE] test ebx, [ESI+ECX-CACHELINE*2] sub ECX, CACHELINE*2 dec EAX jnz @b mov EAX, CACHESIZE / 64 @@: xor ebx,dword [esi+ecx] xor ebx,dword [esi+ecx+4] xor ebx,dword [esi+ecx+8] xor ebx,dword [esi+ecx+12] xor ebx,dword [esi+ecx+16] xor ebx,dword [esi+ecx+20] xor ebx,dword [esi+ecx+24] xor ebx,dword [esi+ecx+28] xor ebx,dword [esi+ecx+32] xor ebx,dword [esi+ecx+36] xor ebx,dword [esi+ecx+40] xor ebx,dword [esi+ecx+44] xor ebx,dword [esi+ecx+48] xor ebx,dword [esi+ecx+52] xor ebx,dword [esi+ecx+56] xor ebx,dword [esi+ecx+60] add ECX, 64 dec EAX jnz @b or ECX, ECX jnz .l Результаты для CPU AuthenticAMD @ 1657 MHz (AXP2k+, DDR2100) (меряю не такты, что малоинформативно, а скорость чтения из памяти): 1372 Mb/sec ;; это код выше 624,5 Mb/sec ;; это, если просто убрать test ebx, [ESI+ECX-CACHELINE] и следующую строку В общем-то это не до тягивает до 85% скорости DDR2100 (т.е. в теории должно быть 1700-1800 Mb/sec), но разницу видно. Почему разницы нет у вас? Есть же табличка - когда происходит чтение из нее, происходят конфликты банков кеша. Если хотите поднять скорость - меняйте алгоритм. "Внутриннее циклы" надо оптимизировать в последнюю очередь. > если у каждого проца свой кэшлайн то функция теряет универсальность У P2/PIII 32 байта, у Athlon / PIV - 64. В моем примере ипользуется 32, что дает универсальность (хотя несколько терянется эффективность на Athlon/PIV) > метод KISS + ко всему увеличивает её размер Обычно по другому оптимизировать по скорости не получается. За все нужно платить :) ЗЫ Если всеже от таблички уйти нельзя - попробуйте все равно сделать 2 цикла. Внутринний фиктивно читает из [EDX+32] и потом обрабатывает 32 байта начиная с [EDX] Тут можно будет поэкспериментировать немного со смещением для предвыборки и с кол-вом байт во внутреннем цикле (64, 128, делать предвыборку из 2х, 4х строк) А смотреть спариваются ли команды - imho в данном случае мало смысла, пока этим командам нечего обрабатывать, выполняться они не будут. 634767297__read_test.exe |
|
|
Дата: Июн 1, 2004 06:06:06 · Поправил: Black_mirror Оптимизация по размеру:
crc_32:;(buf +4, len +8)
push esi
mov esi,[4+esp+4]
mov ecx,[4+esp+8]
xor eax,eax
jecxz .l1
.l0:
mov edx,eax
lodsb
xor edx,eax
shr eax,8
xor eax,[crc_32_table+edx*4]
loop .l0
.l1:
pop esi
ret 8
|
|
Powered by miniBB 1.6 © 2001-2002
Время загрузки страницы (сек.): 0.104 |