Пытаюсь померить скорость, результат скачет в диком диапазоне, то ...e+300 то ...e-400 не могу понять чем вызван такой разброс Код (Text): invoke GetCurrentProcess invoke SetPriorityClass, eax, REALTIME_PRIORITY_CLASS invoke GetCurrentThread invoke SetThreadPriority, eax, THREAD_PRIORITY_TIME_CRITICAL invoke Sleep, 100 ;тест data_input invoke SendMessage,hIDC_n_cicl,WM_GETTEXT, 15, addr str_for_float invoke ustr2dw, addr str_for_float mov Ncicl, eax mov iCicl, eax invoke QueryPerformanceFrequency, addr f invoke QueryPerformanceCounter, addr c1 rdtsc mov dword ptr [rez_data],eax mov dword ptr [rez_data+4],edx invoke Sleep,100 rdtsc sub eax,dword ptr [rez_data] sbb edx,dword ptr [rez_data+4] mov dword ptr [rez_data],eax mov dword ptr [rez_data+4],edx ;---- ii: invoke data_input, pBuffNMPTH, addr hIDC_1_00, 16 dec [iCicl] jnz ii ;---- invoke QueryPerformanceCounter, addr c2 fld qword ptr [rez_data] fld qword ptr [f] fld qword ptr [c2] fld qword ptr [c1] fsub fdiv fmul fstp qword ptr [rez_data] ;тест собственно процедуры invoke QueryPerformanceFrequency, addr f invoke QueryPerformanceCounter, addr c1 rdtsc mov dword ptr [rez],eax mov dword ptr [rez],edx invoke Sleep,100 rdtsc sub eax,dword ptr [rez] sbb edx,dword ptr [rez+4] mov dword ptr [rez],eax mov dword ptr [rez+4],edx ;---- iii: invoke data_input, pBuffNMPTH, addr hIDC_1_00, 16 push pBuffNMPTH call sample_1 dec [Ncicl] jnz iii ;---- invoke QueryPerformanceCounter, addr c2 fld qword ptr [rez] fld qword ptr [f] fld qword ptr [c2] fld qword ptr [c1] fsub fdiv fmul fstp qword ptr [rez] ;вычислим результат с учетом теста data_input mov eax, dword ptr [rez] mov edx, dword ptr [rez+4] sub eax, dword ptr [rez_data] sbb edx, dword ptr [rez_data+4] mov dword ptr [rez], eax mov dword ptr [rez+4], edx ;выведем на экран данные теста invoke FloatToStr, rez, addr str_for_float invoke SendMessage,hIDC_test_rez,WM_SETTEXT, NULL, addr str_for_float
QueryPerformanceXXX выдают результат в Int64, поэтому загружать f,c1,c2 нужно не fld, а fild (как целые) PS: И res_data тоже
leo Изменил Код (Text): invoke GetCurrentProcess invoke SetPriorityClass, eax, REALTIME_PRIORITY_CLASS invoke GetCurrentThread invoke SetThreadPriority, eax, THREAD_PRIORITY_TIME_CRITICAL invoke Sleep, 100 ;тест data_input c Ncicl invoke SendMessage,hIDC_n_cicl,WM_GETTEXT, 15, addr str_for_float invoke ustr2dw, addr str_for_float mov Ncicl, eax mov iCicl, eax invoke QueryPerformanceFrequency, addr f invoke QueryPerformanceCounter, addr c1 rdtsc mov dword ptr [rez_data],eax mov dword ptr [rez_data+4],edx invoke Sleep,100 rdtsc sub eax,dword ptr [rez_data] sbb edx,dword ptr [rez_data+4] mov dword ptr [rez_data],eax mov dword ptr [rez_data+4],edx ;---- ii: invoke data_input, pBuffNMPTH, addr hIDC_1_00, 16 dec [iCicl] jnz ii ;---- invoke QueryPerformanceCounter, addr c2 fild qword ptr [rez_data] fild qword ptr [f] fild qword ptr [c2] fild qword ptr [c1] fsub fdiv fmul fistp qword ptr [rez_data] ;тест собственно процедуры invoke QueryPerformanceFrequency, addr f invoke QueryPerformanceCounter, addr c1 rdtsc mov dword ptr [rez],eax mov dword ptr [rez],edx invoke Sleep,100 rdtsc sub eax,dword ptr [rez] sbb edx,dword ptr [rez+4] mov dword ptr [rez],eax mov dword ptr [rez+4],edx ;---- iii: invoke data_input, pBuffNMPTH, addr hIDC_1_00, 16 push pBuffNMPTH call sample_1 dec [Ncicl] jnz iii ;---- invoke QueryPerformanceCounter, addr c2 fild qword ptr [rez] fild qword ptr [f] fild qword ptr [c2] fild qword ptr [c1] fsub fdiv fmul fistp qword ptr [rez] ;вычислим результат с учетом теста data_input mov eax, dword ptr [rez] mov edx, dword ptr [rez+4] sub eax, dword ptr [rez_data] sbb edx, dword ptr [rez_data+4] mov dword ptr [rez], eax mov dword ptr [rez+4], edx ;выведем на экран данные теста invoke UtoA, rez, addr str_for_float invoke SendMessage,hIDC_test_rez,WM_SETTEXT, NULL, addr str_for_float добавил конвертацию int64 в строку Код (Text): UtoA proc __num: qword, __buffer:dword .data numtab db '0123456789ABCDEF' .code ALIGN 4 mov eax, dword ptr [__num] mov edx, dword ptr [__num+4] mov ecx, 10 mov edi, [__buffer] ; edx:eax - number ; edi - buffer ; ecx - база счисления (от 2 до 16) push ebp mov ebp, esp ; сохраняем верхушку стека mov esi, edx mov ebx, eax __big: cmp esi, ecx jb __small mov eax, esi xor edx, edx div ecx ; делим старшую часть mov esi, eax mov eax, ebx div ecx ; теперь младшую, с учетом предыдущего деления push dword ptr [edx+numtab] mov edx, esi jmp __big __small: div ecx push dword ptr [edx+numtab] xor edx, edx or eax, eax jnz __small __store: pop eax mov [edi], al inc edi cmp ebp, esp jne __store xor eax, eax pop ebp mov [edi], al ; завершающий нуль ret UtoA endp результат - 1493901652715795 такого быть не может, если счетчик выдает в наносекундах.... у меня опять косяк гдето
Во-первых, явная ошибка\опечатка: Во-вторых, или ты с физикой не дружишь или я чего не понимаю Причем тут вообще rdtsc ? У тебя res_data = числу тактов процессора за ~100 мс, т.е. это частота проца Fcpu, деленная на 10. Затем ты ее умножаешь на f/(c2-c1), т.е. на величину обратную времени выполнения какой-то операции, т.е. опять на некую скорость. Спрашивается - что это за хитрая величина такая получается ? PS: надеюсь ты знаешь, что fdiv делит st1 на st0, т.е. f/(c2-c1)
согласен... дурацкий пример передЁра того в чем слабо разбираешься... пошевелил мозгом, переделал на свое слабое разумение.... задача: есть некая функция, лопатит данные в опр.адресе треб-ся: померить примерное время выполнения функции как делал: в цикле меряю скорость передачи данных в опр.адрес (с2-с1)/f далее в такомже цикле меряю скорость (передачи данных+функция) (с2-с1)/f вычитаю из второго рез-та первый, по идее должен получить примерное время выполнения функции Результат: 1. часто время выполнения функции + передача данных почему-то меньше времени просто передачи данных 2. часто что цикл10, что 10000 =рез-тат = e-4 Код (Text): invoke SendMessage,hIDC_n_cicl,WM_GETTEXT, 15, addr str_for_float invoke ustr2dw, addr str_for_float mov Ncicl, eax mov iCicl, eax invoke GetCurrentProcess invoke SetPriorityClass, eax, REALTIME_PRIORITY_CLASS invoke GetCurrentThread invoke SetThreadPriority, eax, THREAD_PRIORITY_TIME_CRITICAL invoke Sleep, 10 ;тест data_input invoke QueryPerformanceFrequency, addr f invoke QueryPerformanceCounter, addr c1 invoke Sleep,100 ;---- ii: invoke data_input, pBuffNMPTH, addr hIDC_1_00, 16 dec [iCicl] jnz ii ;---- invoke QueryPerformanceCounter, addr c2 fild qword ptr f fild qword ptr c2 fild qword ptr c1 fsub fdiv st,st(1) fxch st(1) ;тест собственно процедуры invoke QueryPerformanceCounter, addr c1 invoke Sleep,100 ;---- iii: invoke data_input, pBuffNMPTH, addr hIDC_1_00, 16 push pBuffNMPTH call simpl_1 dec [Ncicl] jnz iii ;---- invoke QueryPerformanceCounter, addr c2 fild qword ptr c2 fild qword ptr c1 fsub fdiv st,st(1) fsub st,st(2) fstp qword ptr rez invoke FloatToStr, rez, addr str_for_float invoke SendMessage,hIDC_test_rez,WM_SETTEXT, NULL, addr str_for_float
NetDemon Товагисч, пешите на другом языке - вот ответ. Не вижу повода писать на ассемблере, ну нету тут в вашем коде ничего критичного к скорости выполнения, а лопатить всё это смог один многоуважаемый leo. способ 2. Изучите дебаггер. ну хоть какой-нибудь, тем самым вы поможите себе и облегчите жизнь другим.
asmfan не вижу повода писать ответ, если неудосужился даже прочитать.... способ 2. из разряда, собрался копать землю - копай лопатой... а я по твоему руками копаю?! А насчет лопатить... если б я не привел код, что ты написал бы? догадываюсь... "че тут тебе телепаты?"
NetDemon Самокритично пошевелил, но видимо не достаточно интенсивно Sleep(100) зачем оставил ? Если для проверки насколько точно винда 0.1 сек выдерживает, то и без проверки известно, что хреново (+-15 мсек). Вот тебе и ответ на вопросы 1) и 2) Еще не понятно зачем ты дважды пытаешься измерять время некого data_Input - уверен, что результаты должны быть стабильными ? По крайней мере при первом вызове любой процедуры и первом обращении к данным с большой вероятностью получишь завышенные значения если соотв.кода и данных еще нет в кэше, не настроена схема предсказания переходов и т.п. Лучше замерять передачу и функцию отдельно или вместе, но без всяких вычитаний Ну и наконец нужно приучаться чистить за собой стек FPU - у тебя в итоге в FPU остаются два значения, а это чревато последствиями. Последние три инструкции можно переписать так Код (Text): fdivrp fsubrp fstp qword ptr rez
leo 1.Насчет слипа гдето читал, что нужно притормазить, чтобы не было лишних обращений изза многопоточности windows (немного сумбурно, но надеюсь понятно ) 2.Некий data_input собирает значения с edit control'ов, конвертит значения в float и помещает в опр. адрес. тк функция возвращает результат в тот же адрес, то цикл вызова функции после 1 прохода будет давать неправильный результат.... а тк мне нужно примерную скорость самой функции, то зачем мне в нагрузку опрос памяти? который наверняка и сам нестабильный результат дает!!! А у меня ведь есть функции, у которых сбор данных может быть больше раза в два! 3. Насчет FPU понял, учту...вопрос: А какие могут быть последствия?
Во-первых, про Sleep(100) ты врядли где-то читал, а просто скопипастил из примера определения частоты процессора, где ее использование несет совсем другой смысл Во-вторых, есть рекомендация перед измерениями вызывать Sleep(0), при этом ты отдаешь винде неиспользованные остатки кванта времени потока и (с определенной долей вероятности) гарантируешь, что код после Sleep возобновиться в начале нового кванта и у тебя будет ~10-20 мс на проведение измерений. Но при использовании реал-тайм приоритета этот трюк мало что дает И в-третьих, самое главное - если хочешь, то используй любые Sleep, но зачем их во время измерения то включать ?!! Я же сказал, что Sleep имеет погрешность ~15 мс, нафига тогда точные измерения по QueryXXX или rdtsc использовать. Если нужен плюс-минус километр, используй GetTickCount. В общем, не дури и выкини эти sleep вообще или хотя бы вытащи их перед invoke QueryPerformanceCounter, addr c1 Ужас, представляешь какие это тормоза и нестабильности ! Во-первых, намного быстрее и стабильнее было бы один раз вызвать data_input, поместив данные в дополнительный буфер, а в цикле измерений копировать его pBuffNMPTH Во-вторых, если время выполнения самой функции simpl_1 не слишком маленькое, то можно измерять непосредственно его, переместив QueryXXX внутрь цикла (можно суммировать значения, а можно просто выводить серию из скажем 10-ти значений и смотреть их разброс). Если значения окажутся = 0, то заменить Query на rdtsc Код (Text): xor eax,eax mov dword ptr [c2],eax mov dword ptr [c2+4],eax iii: invoke data_input, pBuffNMPTH, addr hIDC_1_00, 16 ;--- rdtsc mov dword ptr [c1],eax mov dword ptr [c1+4],edx ;--- push pBuffNMPTH call simpl_1 ;--- rdtsc sub eax,dword ptr [c1] sbb edx,dword ptr [c1+4] add dword ptr [c2],eax adc dword ptr [c2+4],edx ;--- dec [Ncicl] jnz iii Последствия от неполной очистки стэка FPU могут быть плачевными - переполнение оного стэка, выброс исключения и как следствие - кранты твоей проге (т.к. SEH ты видимо не используешь). В данной конкретной проге тебе может и повезло, что FloatToStr использует мало регистров FPU, но в другой ситуации может и не повезти. И еще - раз функция data_input тоже работает с FPU, то оставлять в нем значения частоты и первого измерения тоже не хорошо. Негласное правило - при выходе из своей функции и перед вызовом других функций, которые могут работать с FPU, нужно обязательно очищать все его регистры