|
|
| Посл.отвђт | Сообщенiе |
|
|
Дата: Ноя 10, 2004 13:46:44 leo, поигрался я с твоим удивительным leo_ADC_fast4 в перестановки инструкций (на P4 15.2.9). Удалось еще немного ускорить : macro leo_ADC_fast4_m{ shr ecx,2 clc ;align 2 .loop: mov eax,[esi] mov edi,[ebx] mov ebp,eax adc eax,edi add ebp,edi inc ebp jnz .ret1 cmp eax,-1 .ret1: mov edx,[esi+4] mov edi,[ebx+4] mov ebp,edx adc edx,edi add ebp,edi inc ebp jnz .ret2 cmp edx,-1 .ret2: mov [ebx],eax mov eax,[esi+8] mov edi,[ebx+8] mov ebp,eax mov [ebx+4],edx adc eax,edi add ebp,edi inc ebp mov [ebx+8],eax jnz .ret3 cmp eax,-1 .ret3: mov edx,[esi+12] mov edi,[ebx+12] adc edx,edi mov [ebx+12],edx lea esi,[esi+16] lea ebx,[ebx+16] dec ecx jnz .loop .end: };========================================== ;____________________Data1_____Data1_____Data2____Data1____Data2____Da ta1____Data2____Data1 ;____________________Comp1_____Comp2_____Comp2____Comp3____Comp3____Co mp4____Comp4____Comp5 ;Gray_SSE2;____________940_______880______880_________________________ ____________________ ;leo_JZ_pop2;__________824_______916_____1008______625_____958_______6 25_____1026______625 ;leo_JZ_pop;___________948_______920_____1204_____1034____1432______10 34_____1432_____1034 ;leo_JZ;_______________824_______924_____1064______657____1307_______6 57_____1432______780 ;gray_pop;____________1092______1100_____1164_____1400____1414______14 00_____1415_____1400 ;svin_test2;__________1216______1176_____1120_____1459____1473______14 59_____1473_____1459 ;leo_setc;____________1224______1212_____1232_____1044____1044______10 44_____1044_____1044 ;leo;_________________1232______1228_____1228______738_____738_______7 66______766______739 ;leo_setc2;___________1300______1272_____1412______796_____796_______7 96______796______796 ;svin_test_gray;______1220______1284_____1280_____1401____1413______14 01_____1413_____1401 ;svin_test;___________1220______1292_____1272_____1400____1412______14 04_____1412_____1400 ;Gray;________________1428______1400_____1400_____1033____1033______10 33_____1033_____1033 ;leo2;________________1428______1400_____1400_____1118____1118______11 18_____1118_____1118 ;The_Svin;____________1432______1420_____1420_____1119____1119______11 19_____1119_____1119 ;gray_popall;_________1588______1624_____1624______371_____371_______3 57______357______371 ;leo_ADC_fast4;________692______1248_____1256_____1200____1211______12 00_____1211_____1200 ;leo_ADC_fast4_m;______676______1244_____1248_____1124____1136______11 24_____1136_____1124 ; ; ;Comp1 - Processor= x86 Family 15 Model 2 Stepping 9 GenuineIntel ~2664 Mhz (Windows XP) DDR (Notebook Dell Lattitude 100, Windows XP) ;Comp2 - Processor= x86 Family 15 Model 2 Stepping 4 GenuineIntel ~2254 Mhz (Windows XP) ;Comp3 - Processor= x86 Family 6 Model 8 Stepping 3 GenuineIntel ~601 Mhz (Windows 2000) ;Comp4 - Processor= x86 Family 6 Model 11 Stepping 1 GenuineIntel ~601 Mhz) (Windows 2000 Server). ;Comp5 - Processor= x86 Family 6 Model 11 Stepping 4 GenuineIntel ~1327 Mhz (Windows XP) Notebook Toshiba Satellite Удивительно и немного обидно, что этот вариант быстрошустр только на старших моделях процессора. На младших моделях самый шустрый gray_popall. Иль я упустил какой-то из развернутых вариантов? P.S. Чудны твои пути, Intel! Ну кто бы мог подумать, что 2*N сложений можно сделать быстрее чем N. |
|
|
Дата: Ноя 10, 2004 23:39:04 · Поправил: leo Gray > "Удивительно и немного обидно, что этот вариант быстрошустр только на старших моделях процессора" В случае с P3 и вообще P6-family это понятно - у них сама ADC достаточно шустрая. А вот интересно почему на P4 15.2.4 не получается перекрытия ADC - все теже 9-10 тактов на сложение. Может для этой модели попробовать увеличить число сложений в цикле ? Или все-таки Агнер частично прав насчет throughput (не с потолка же он взял свои цифры) ? > "Иль я упустил какой-то из развернутых вариантов?" Наверное, упустил простой безымянный разворот на 32 сложения за цикл (leo: Окт 28, 2004 22:55:36). По сути это практически тоже самое, что и твой вариант с POPA. Но он, на мой взгляд показывает, что выигрыш на P3 достигается не за счет POPА, а за счет "хорошего" расположения инструкций (что, кстати, вполне соответствует "учению" Агнера). |
|
|
Дата: Ноя 12, 2004 11:20:43 · Поправил: leo Вот оптимизированный вариант разворота для P3. Для 16,32 сложений на цикл получается пошустрее чем gray_popall. macro P3_ADC_unroll countdeg {
;countdeg = 3,4,5,6 = log2(count)
count = 1 shl countdeg ;число сложений в цикле = 8,16,32,64
shr ecx,countdeg
clc
align 16
@@:
;два первых сложения
mov eax,[esi] ;a 0
mov ebx,[esi+4] ;b 4
mov edx,[esi+8] ;d 8
adc eax,[edi]
mov [edi],eax
adc ebx,[edi+4]
;повтор блоков по 6 сложений
reps = (count-2)/6
repeat reps
ofs = (%-1)*24 ;смещение в каждом блоке увеличивается на 6*4=24
mov eax,[esi+12+ofs] ;a
mov [edi+4+ofs],ebx
adc edx,[edi+8+ofs]
mov ebx,[esi+16+ofs] ;b
mov [edi+8+ofs],edx
adc eax,[edi+12+ofs]
mov edx,[esi+20+ofs] ;d
mov [edi+12+ofs],eax
adc ebx,[edi+16+ofs]
mov eax,[esi+24+ofs] ;a
mov [edi+16+ofs],ebx
adc edx,[edi+20+ofs]
mov ebx,[esi+28+ofs] ;b
mov [edi+20+ofs],edx
adc eax,[edi+24+ofs]
;если последнее сложение для count = 8,32,128
if %*6 = count-2
mov [edi+24+ofs],eax
adc ebx,[edi+28+ofs]
mov [edi+28+ofs],ebx ;сохраняем результат
else
;если не последнее, то грузим след.значение, а рез-т ADC не сохраняем
mov edx,[esi+32+ofs] ;d
mov [edi+24+ofs],eax
adc ebx,[edi+28+ofs]
end if
end repeat
;для count = 16 и 64 остаются еще 2 сложения
if (count-2) mod 6 > 0
ofs2 = reps*24
mov eax,[esi+12+ofs2] ;a
mov [edi+4+ofs2],ebx
adc edx,[edi+8+ofs2]
mov [edi+8+ofs2],edx
adc eax,[edi+12+ofs2]
mov [edi+12+ofs2],eax
end if
lea esi,[esi+count*4]
lea edi,[edi+count*4]
dec ecx
jnz @B
};======================================================
macro P3_ADC_unroll_8{P3_ADC_unroll 3}
macro P3_ADC_unroll_16{P3_ADC_unroll 4}
macro P3_ADC_unroll_32{P3_ADC_unroll 5}
macro P3_ADC_unroll_64{P3_ADC_unroll 6}
};======================================================
Результаты на P3-650 (6.8.1)
gray_popall......................371
P3_ADC_unroll_8..................389
P3_ADC_unroll_16.................340
P3_ADC_unroll_32.................311
P3_ADC_unroll_64.................313 - видимо "насыщение" ~ 2.4 такта на сложение Вывод: по-видимому гипотеза о "массовом чтении" не подтверждается. Рулит обычное распараллеливание: циклическая последовательность операций adc(r,m) mov(r,m) mov(m,r) для P3 по всей видимости является "оптимальной" - согласованной по latency и по использованию разных портов.
Возможно даже схема оптимального декодирования 4-1-1 моп за такт по Агнеру рулила бы, да вот только длина каждой инструкции 3 байта, поэтому неизбежны разбивки инструкций границами 16 байтных ifetch блоков, а с ними и изменение порядка декодирования и соответствующие penalty. В принципе можно поизвращаться и в каждом втором ADC заменить [edi+ofs] на [edi+ebp+ofs] при ebp=0. Может попробую ради спортивного интереса и проверки учения Агнера. |
|
|
Дата: Ноя 12, 2004 23:22:08 · Поправил: leo Вот поизвращался с выравниванием длины 5 инструкций на 16 байт (замена [edi+ofs] на [edi+ebp+ofs] при ebp = 0). Разницы никакой. Оказывается тот же Агнер учит, что mov(m,r) на P3 это 2 микрооп (а не 1), так что схема 4-1-1 не действует. Хотя при явном (без repeat) развороте цикла 32 сложений удается уменьшить число тиков с 311 до 303 за счет перестановки местами mov(r,m) и mov(m,r) на границах 16 байт (для ускорения декодирования по Агнеру). Но это мелочь, не стоящая свечь. Так что теория действует, но конкретный код оставляет мало простора для ее реализации. Кстати попробовал заменить все mov r,[esi+disp] на вариант с POP r - получилось значительно хуже (для 32 сложений 412 тиков вместо 311). У Агнера и на это можно найти ответ: POP это 2 мопа - mov и приращение esp на 4, которое выполняется на одном из АЛУ и => отнимает такт у ADC. |
|
|
Дата: Ноя 13, 2004 11:30:29 · Поправил: leo Кстати еще о тонкостях "при ловле блох". В используемом test.asm от Gray начало макроса соответствует смещению xCh. Поэтому если луп выравнен align 16, то перед ним хорошо умещаются до 4 байт подготовительных инструкций. Если больше, то в итоге получаем длинную цепочку нопов перед лупом которые по крайней мере на P3 ухудшают результат на ~ 5 тиков. Поэтому можно считать, что в упомянутом выше эксперименте с добавлением [edi+ebp+ofs] выигрыш чуть больше, но он съедается за счет добавления перед лупом xor ebp,ebp и как следствие вставкой длинной цепочки нопов. Вот такая "блин", наука.. PS: Если вынести обнуление ebp в начало тестовой проги, то как раз получается 298 тиков (= 303-5). А 5 тиков это время декодирования на P3 xor и цепочки нопов на общей длиной в 16 байт. |
|
|
Дата: Ноя 13, 2004 12:20:47 длины 5 инструкций на 16 байт (замена [edi+ofs] на [edi+ebp+ofs] Поэтому можно считать, что в упомянутом выше эксперименте с добавлением [edi+ebp+ofs] выигрыш чуть больше, но он съедается за счет добавления перед лупом xor ebp,ebp и как следствие вставкой длинной цепочки нопов. :) Хрестоматийный пример зачем нужно знать формат. Закодируй вручную при этом в sib в index поставь 100 а в scale 00 (это будет означать отсутвие индекса), edi (111)поставь в base и всё. Тогда ebp не понадобится при той же длине инструкции. Например MOV EAX,[EBP+EDI+400000] это в Hex 8B 84 3D 00 00 40 00 8B - это инструкция с указанием размера 84 3D - это modrm и sib 3D - sib раскладывается как 00 111 101 00 - маштабирование 111 - код индекса (edi) 101 - код базы (ebp) чтобы индекс вообще не использовать можно сделать так 00 100 111 00 100 - указывает что индекса нет 111 - базовый edi. в HEX будет 27 т.е. весь опкод должен быть 8B 84 27 00 00 40 00 Это будет не что иное как MOV EAX,[EDI+400000] но в альтернативной кодировке Оптимальная кодировка будет 8B 87 00 00 40 00 это тоже MOV EAX,[EDI+400000] здесь edi кодируется в modrm (как обычно ассемблер и делает) а выше приведена альтернативная кодировка на байт длинее с использованием sib. можно и по другому - сделать индекс без базы. Я как то статью пытался написать про как раз использование альтернативного кодирования именно в целях выравнивания (что на данный момент не делает ни один ассемблер) но мне показалось логичным приложить тогда уж тулзу для этого, а тулза получалась вроде как целым ассемблером со втроенной фичей, и что-то я остановился в раздумье начинать ли :)) |
|
|
Дата: Ноя 13, 2004 12:43:11 Забыл написать без базы: 8B 04 3D 00 00 40 00 84 меняешь на 04 (снимаешь 10 в mod - в сочитании mod=00 base = 101 означает - нет базы один displacement) |
|
|
Дата: Ноя 13, 2004 23:22:00 · Поправил: leo TheSvin Кодирование "вручную" это конечно супер. Изредка балуюсь этим делом, но поскольку на память ничего не помню, приходится лазить за подзказками к интеловскому мануалу - получается не быстро. А вообще-то я эти проверки с выравниванием затеял только ради интереса. После "тыканья в потемках" и твоей дельной критики пришлось взяться за ликбез. Теперь хоть какое-то разумное представление складывается и ес-но по ходу возникакают кой-какие мыслишки и желание их проверить. |
|
|
Дата: Ноя 14, 2004 02:01:46 · Поправил: S_T_A_S_ The Svin > тулза получалась вроде как целым ассемблером со втроенной фичей, и что-то я остановился в раздумье начинать ли :)) А были ли мысли относительно синтаксиса? Я имею ввиду, как сказать транстлятору, что данную команду нужно кодировать минимальным по размеру опкодом, а другую - user defined ? С ходу приходит на ум вариант с различным положением скобочек: [base+scale*index+displasement] - оптимизируется по размеру [base][scale*index][displasement] - не оптимизируется по размеру Приминительно к рассмотренному примеру это могло бы выглядеть так: MOV EAX,[EDI+400000] ; 8B 87 00 00 40 00 MOV EAX,[EDI][][400000] ; 8B 84 27 00 00 40 00Хотя все возможные проблемы это не решает, например, нужно учесть варианты использования disp32, вместо disp8, или случаи когда disp нужно закодировать, но в оптимальном случае он не нужен.. можно добавить (при необходимости) оператор размерности: MOV EAX,[EDI] ; 8B 07 MOV EAX,[EDI][][byte 0] ; 8B 44 27 00 MOV EAX,[EDI][][dword 0] ; 8B 84 27 00 00 00 00 Конечно рассмотреный вариант можно без кодирования вручную так записать: MOV EAX,[ES:EDI+400000] ; 26 8B 87 00 00 40 00 Но речь не об этом, сама идея использовать в ассемблере возможность кодирования различных форматов очень интересная, вот только через DB это как-то не очень красиво делать :-) |
|
|
Дата: Ноя 14, 2004 06:59:21 Чтобы программно реализованное это могло быть эффективным, это несомненно должно быть частью ассемблера. Однако, это должно применяться не к отдельным инструкциям. С помощью различных методов кодирования адресации длина не может быть настроена с точностью до байта... Лучше если будет возможность указывать блок кода, который нужно выровнять. А ассемблер будет пытаться добиться желаемого (например, сделать размер кода блока в байтах кратным 16) варьируя метод кодирования адресации всех инструкций блока... |
|
|
Дата: Ноя 15, 2004 01:07:33 Совершенно верно. |
|
|
Дата: Ноя 16, 2004 07:25:23 Гм..
#pragma size 7
{
MOV EAX,[EDI+400000]
}
? :) |
|
|
Дата: Ноя 16, 2004 08:52:54 Во-первых, все слова, у которых первая буква '#' выглядят подозрительно. ;) Во-вторых, данная возможность обычно будет применятся для выравнивания где важна только кратность, а не фактический размер. Поэтому средство должно позволять указывать не точный размер блока в байтах, а число (степень двойки), которому размер должен быть кратен. Каков именно будет этот кратный размер - программисту знать не обязательно, это будет проблема транслятора. ;) |
|
|
Дата: Ноя 16, 2004 11:04:14 Основная идея в том, что выравнивание которое и сейчас уже существует (например ALIGN) и выполняется вставкой пустых инструкций (не обязательно NOP но по логике тот же NOP, например каким-нить Lea eax,[eax][0000000] и т.п) выполнялось не вставкой а удлинением инструкции это дополнительное удлинение и заменит все NOPы но при этом не увеличит количество инструкций. На самом деле я вроде видел эту же идею воплощённую в результате работы каког-то компилятора, но там было сделано наихудшим и очень ограниченным по возможностям способом - добавлением префиксов переопределения сегмента которые указаывали на тот же дефолтный сегмент, но указывали явно. Наиболее интересные, эффективные и гибкие возможности даёт альтернативное кодирование modrm, это авторов компиляторов видимо ломает писать (если вообще они понимают что-то в этом) гораздо проще в логике компилятора им впендюрить nop'ов нужной длины или насобачить префиксов. Наиболее эффективно IMHO будет альтернативное кодирование когда на узком участке нужно выравнять несколько меток, так бывает со вложенными циклами в купе с необходимостью выравнивать сам вход в короткую и часто вызываемую процедуры где к тому же возможно есть сложное ветвление в блоках управления и вход в какие-то ветки тоже хорошо бы выравнять. Т.е. в кратце то о чём мы говорили здесь - как сделать выравнивание без нопоподобных вставок, обойдясь альтернативным кодированием. |
|
|
Дата: Ноя 16, 2004 12:23:27 Ага, речь идёт об "интеллектуальном" операторе align. Который будет подбирает для предшествующих команд опкоды определённых размеров. С другой стороны, случаи, когда необходимо точно знать размер опкодов так же существуют - например констукции типа switch (jmp eax). Таким образом, IHMO необходимо две фичи. > гораздо проще в логике компилятора им впендюрить nop'ов нужной длины или насобачить префиксов. Да, это конечно проще, встретили align, кол-во нопов подсчитать не проблема. Если мы говорим компилятору, что некий кусок должен быть NN байт, до того как он его будет компилировать, то тут ему проще соображать будет.. Но если говорить о варианте с "удлиннением" предыдущих опкодов, то логика компилятора будет несколько сложнее. "Возвращаться назад" нужно будет или компилировать за кучу проходов.. К чему я это - то, как это будет записано в исходнике, влияет на сложность реальзации. очевидно, что традиционная директива ALIGN не будет наилучшим решением :-( ЗЫ А почему '#' выглядит подозрительно ? : ) ЗЫЫ Гы, что-то я тут оффтоп развёл =) |
|
Powered by miniBB 1.6 © 2001-2002
Время загрузки страницы (сек.): 0.178 |