О выравнивании кода: наверное заметил "неправильное" начало процедуры - mov edx,[esp+4] push ebx а не push ebx mov edx,[esp+8] разницы никакой в логике процедуры, а первый вариант выполняется на 10 тиков быстрее. Точно не знаю, но предположительно из-за того, что сложная инструкция в первом варианте выравнена на 16 (перед процедурой align 16) или тут: Код (Text): xor eax,eax jmp _st align 16 _add:or al,byte ptr[offset hh_tbl+ecx] shl eax,4 or al,byte ptr[offset hh_tbl+ebx] _st: movzx ecx,byte ptr[edx] ...... jns _add Лучше один раз сделать jmp _st, и за счёт этого выравнять начало цикла на 16, что в конечном итоге сэкономит во много раз больше, чем время на jmp. Тест у меня не фасмовый, фасм не понимаю (или не хочу). На масме. Если надо, давай мыло, скину.
cresta Давай на alpet<font color="red]&40;</font><!--color-->hotmail.ru. У меня есть только masm32. В принципе он вроде и pdb файлы генерит, что необходимо к сожалению для CodeAnalyst.
cresta Получил, результаты на Celeron в целом в пользу моего алгоритма: 280 тиков, 344 у тебя, 440 у bogrus, и 558 у buliaNaza. Что интересно у тебя первый тест часто получается быстрее второго - например 556 / 860 тиков, и в любом случае быстрее чем у всех остальных алгоритмов - результат видимо малого размера таблички. Подробный результ лови на мыло.
cresta > "разницы никакой в логике процедуры, а первый вариант выполняется на 10 тиков быстрее. Точно не знаю, но предположительно из-за того, что ..." В высокоуровневой логике разницы нет, а в микрооперациях разница существенная, т.к. push\pop\call\ret неявно изменяют регистр esp. Поэтому mov edx,[esp+4] и push ebx могут выполняться параллельно, а вот push ebx и mov edx,[esp+8] нет, т.к. mov должен ждать изменения esp после push.
Сделал так-же и высокоуровневую функцию преобразования, без таблички на C++. Проверял двумя компиляторами - gcc 3.4.2 и ms cl 14.0. Для первого задал опции оптимизации: "-O3 -s -ffast-math -mwindows". Для другого - следующие: Код (Text): /Ox /Og /Ob2 /Oi /Ot /G6 /GA /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FD /EHsc /ML /GS /Yu"stdafx.h" /Fp"Release/fscan2.pch" /Fo"Release/" /Fd"Release/vc70.pdb" /W3 /nologo /c /Wp64 /Zi /TP Итог - результат gcc получился размером 7кб и выполнял преобразование в среднем за 80 тиков (грамотное встраивание inline). Результат ms cl = 44кб и 100 тиков (инлайн не использовался, а при задании __forceinline получилось еще хуже - 114 тиков). Исходник в аттаче и бинарник(gcc) в аттаче. P.S. При этом попытался воспользоваться встроенным ассемблером, но синтаксис асмовых вставок в gcc похоже придумали инопланетяне - все перевернуто с ног на голову, кроме головной боли ничего короче не добился. 371609841__1.zip
Код (Text): QWORD inline __stdcall rdc () { asm ("rdtsc\n" ); } Это что за зверь? vc++ 7.1 не понимает этого
cresta Да - это пример убившего меня вчера GNU Assembler syntax (GAS). Вот например еще код: Код (Text): int main(void) { int x = 10, y; asm ("movl %1, %%eax; "movl %%eax, %0;" :"=r"(y) /* y is output operand */ :"r"(x) /* x is input operand */ :"%eax"); /* %eax is clobbered register */ } На сколько я понял в традионном асме это выглядит так: Код (Text): push eax ; Сохранить ударенный регистр :)) mov eax, x ; movl %1, %%eax mov y, eax ; movl %%eax, %0 pop eax GetTickCount правильно юзается - смотри выражение которое тики получает: Код (Text): [b] double dspeed = ((double) nTicks / (double)loops) / (1000 / 2.4e9); Equ: ( msec_time_of_test / cycle_loops ) / (msec_in_sec / cpu_speed ). [/b] Взялся GetTickCount использовать, потому что не удалось написать на gcc функцию rdtsc (вернее написал - но она работает только в неоптимизированной версии). Макрос, предложенный на одном из сайтов, gcc не принял. Видать со стандартами плохо в Linux и каждый стремится свой изобрести :( #define rdtscll(val) \ __asm__ __volatile__ ("rdtsc" : "=A" (val))
Умудрился таки немного разобраться в синтаксисе AT&T asm. Результат в аттаче, выводит два результат - по таймеру и по rdtsc. У меня на машине результат таймера обычно оптимистичнее примерно на тик чем у rdtsc. После введения увеличения приоритета код стал выполнятся быстрее - 72-73 тиков на цикл. Я мельком глянул под Olly на сгенерированный код, и весьма был заинтригован - хорошая в целом работа. _1556112236__2.zip
alpet А чего не сделать свой rdc? В исходнике, что мылил тебе, есть макросы INIT_CLOCK, STOP_CLOCK, READ_CLOCK, SERIAL. Попробуй их вставь как _asm вставку. Или в виде in line функции. Можно конечно и с GetTickCount, но масштаб совсем другой, под каждый проц нужен свой коэффициент вместо (1000 / 2.4e9)
cresta Дык уже сделал: Код (Text): QWORD inline rdc () { union { QWORD rr; struct { DWORD r1, r2; }; } mix; asm volatile ("rdtsc\n" : "=a"(mix.r1),"=d"(mix.r2) ); return mix.rr; } А если юзать твой - gcc воспротивится, ему Intelовский синтаксис непонятен. Вот для MSVC у меня простая rcd inline функция: Код (Text): __forceinline __int64 rdc () { __asm rdtsc } Поправка - в принципе можно заставить работать gcc и с интеловским синтаксисом (как и отладчик gdb), но только в плане отдельных файлов - не вставок.