кстати, я решил (для надежности) брать в качестве оверхеда не последнее значение, а прогонять цикл 12 раз, затем отбирать только то число, которое гарантировано встречается не менее 7 раз тоже самое делаю и при замере нужного кода (это я пробовал сделать привязку к железу через rdtsc), т.е. принцип такой: - есть процедура берущая оверхед (proc %overhead) - есть множество ф-ций, скорость выполнения каждой из которых, зависит от какой-то определенной характеристики железа - есть процедура замеряющая скорость выполнения тестируемой функции, переданой в качестве параметра (proc %rdtsc,%proc) это все ясно и хорошо, но! результат есс-но нестабилен, даже на простых ф-циях (это у меня на pentium d одна и таже ф-ция может иметь два стабильных результата, но чередующиеся через раз, на старом pIII такой проблемы нет), а тем более на ф-циях, замеряющих к примеру, скорость обращения к первому сектору hdd, там результат получается с разбросом, допустим: 000000000000000635342315 000000000000000635385424 000000000000000635421245 000000000000000635389641 ... Из этих чисел, делая между ними AND и отбирая только неизменяющиеся биты получаем стабильное число, затем (чтобы исключить возможность брутфорса) убираем все биты, которые гарантировано встречаются в результатах ф-ции на всех возможных машинах, таким образом у нас остается несколько там десятков бит, стабильно прыгающих на разном железе - есть процедура, собирающая все такие биты ф-ций в одно 128 битное число (оно будет ключем шифровки\дешифровки защищенного кода) т.е. на клиентской машине получаем ключ и под него генерим копию программы, запущенная у клиента программа - делает тоже самое, но с небольшим дополнением: - иногда (из-за вспышек на солнце)) какой-то бит может все таки прыгнуть - для этого, процедура расшифровки повторяется 5-10 раз, пока CRC не совпадет с ключевым - если за это, n-ное кол-во так и не удалось правильно расшифровать - значит с железом что-то не то
Позвольте уж и мне на суд столь уважаемых Дзенствующих выставить маскос писаный мной давненько под masm. Замечания и конструктивная критика приветствуется.
bogrus Насчет оверхеда ты в общем прав, хотя ИМХО на "простых" камнях разброса практически нет, а на P4 с HT=on получить повторяющиеся значения вообще проблематично - только отключать HT. Поэтому отбор гарантированных повторов видимо актуален для двухядерников, хотя и тут ради эксперимента лучше отключать второй процессор. И потом если речь идет о тестере (а не о генераторе ключа), то я предпочитаю видеть глазками разброс значений и для надежности повторять тест несколько раз, а не выводить какое-то одно значение - будь оно повторяющееся или вообще какое-то непонятное среднее Ну и как вердикт ? Вспышки на Солнце не достают ? PS: Для "простых функций" разброс на Pentiun D это ИМХО цветочки по сравнению с кашей на HT - тут на одном проце рулят два конкурирующих потока, поэтому и разброс значений может быть практически любым, и измерять более или менее надежно можно видимо только достаточно большие "внешние" задержки. Или я не прав ? Y_Mur, asmfan 1) Повторю - rdtsc is not a serializing instruction, subsequent instructions may begin execution before the read operation is performed, т.е. тестируемый код может выполняться параллельно с rdtsc и сохранением edx:eax. Поэтому непосредственно перед тестируемым кодом нужно вставлять cpuid, т.е. всего их должно быть 3 шт. - перед каждым rdtsc и перед тестируемым кодом. 2) Задержка самой cpuid зависит от наличия записи в память в предыдущем куске кода, т.к. cpuid форсирует сброс содержимого буферов записи в кэш. Поэтому если тестируемый код ничего в память не пишет, то на P6 результаты получаются "тик в тик" (или в худшем случае на 1 тик меньше за счет спараллеливания с xor eax,eax), а на P4\P4E результаты получаются с дискретом в 4\8 тиков соотв-но. Если же тестируемый код пишет в память, то итоговая задержка получается больше на несколько десятков тактов - тут остается либо 1) не обращать внимания на абсолютную задержку и проводить только относительные сравнения разных вариантов с одинаковым числом записей в память, либо 2) пытаться заменить cpuid перед последним rdtsc на нечто другое - в частности на пеньках неплохие результаты дает инструкция cld - результата "тик в тик" не получим, но по кр.мере он будет гораздо ближе к истине, чем при cpuid
leo Учел замечания и соединил два теста в один. Первое значение без цикла второе в цикле PII 266 МГц Pentium M 1,6 ГГц Celeron 2,8 ГГц std 239, 239 244, 237 380, 267 new 209, 192 206, 161 316, 230 Интересно, что значение в цикле намного меньше, чем просто от спаривания с кодом цикла и от задержки записи в память, т.е. получается оно как бы характеризует способность кода спариваться с самим собой? И где здесь более корректный "дифференциальный" результат в цикле или без? Еще попробовал в std заменить FSTP [qZ] на FSTP ST(0) : PII: 239, 239 <- пишет в память 238, 237 <- не пишет в память т.е. практически без разницы Celeron: 380, 267 <- пишет в память 348, 267 <- не пишет в память т.е. получается цикл тоже позволяет абстрагироваться от записи в память, если конечно считать "самоспаривание" нормальным явлением.
Y_Mur Это нормальное явление для цикла и ненормальное для "нецикла" Поэтому в общем случае в цикле можно корректно тестировать только сами циклы А если хочешь "выцепить" малые задержки небольших кусков кода или вообще латентности отдельных инструкций, то универсальных методов тут нет и нужны специальные квазинаучные эксперименты а ля доктор Фог (у которого кстати, тоже не все безупречно - например, он продолжает утверждать, что в P4\P4E у adc,sbb througput = 8\10, хотя и мануалы Intel и элементарные проверки дают цифры ~2-3). Поэтому осчастливить начинающих оптимизаторов универсальным тестером на все случаи жизни не удастся ) И поэтому нагружать тестер измерениями в цикле ИМХО ни к чему - кому надо, тот сам три строчки добавит для организации цикла, а чтобы проще было "делить в уме" для получения задержки на итерацию достаточно просто брать число итераций = 100, 1000 и т.д. - тут кстати и штраф за непредсказанный выход из цикла будет виден и задержка на выгрузку буферов в кэш
Не я собственно делаю не универсальный, а просто удобный тестер, с помощью которого начинающие оптимизаторы смогут кидаться друг в друга результами тестирования кода на разных машинах, и кажется наконец оно получилось Протокол дописывается в файл чтобы можно было протестить на нескольких машинах подряд. А существует API или cpuid функция для определения реальной тактовой частоты или только "метод dr_dred"?
leo Увы "т.к. ffree не изменяет указатель вершины стека" противоречит тому, что "fstp st и ffree st эквивалентны с точки зрения результата", и замена fstp на ffree быстро приводит FPU стек в полную непригодость ((
Y_Mur Противоречит, если вырывать цитаты из контекста Вообще-то речь шла о полной очистке стека FPU и в этом смысле fstp и ffree очищают регистры одинаково успешно, если конечно кому то не придет в голову после ffree использовать fstp или другие операции с инвалидным регистром (кроме fld ес-но)
leo Ага уже и сам понял, что полностью очищать стек ими можно , только мне пришло в голову заменить fstp на ffree когда над ним были занятые позиции, есно получил баг и запостил #68
на моем стареньком PIII 855MГц тест Y_Mur-а из поста #67 вывел: посмотрим, что покажет этот же тест на Box Core 2 Duo E6600 2.40 Ghz )
итого, на моем новом Intel Core 2 Duo E6600 2400GHz (1066 MHz FSB 4MB L2 Cache), материнской P5B Deluxe LGA775 и гигом корсаровской оперативки тест Y_Mur-a из поста #67 выдал следующее: