Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.15.147.53] |
|
Страницы: (2) 1 [2] все ( Перейти к последнему сообщению ) |
Сообщ.
#16
,
|
|
|
не совсем так.. Чтобы получить реальное время, нужно иметь счётчик и частоту, на которой этот счётчик работает. Например если взять счётчик процессора TSC и разделить его не на частоту процессора, а частоту таймера HPET, то получим не правильное время. Именно поэтому пара QPC+QPF должны всегда ходить вместе. Если замерить, сколько раз простучит QPC в течении одной секунды, то непременно получим значение, которое вернёт нам QPF. Это-же касается и пары RDTSC+CPUfreq. да.. он кривой, т.к. я его набросал на коленке. Спасибо вот Jin X поправил. я имел в виду, что индусы точили набор функций NtCreateProfile(), с которыми я кстати так и разобрался до конца. вполне возможно, только эта частота у меня всегда совпадает с физической частотой системной шины, без множителя CPU. именно так он и работает! На новых чипсетах TSC выделен в отдельный домен, и идёт напрямую от системного клокера, - овер биоса на неё не влияет. Прикреплённый файлtscp.png (9,88 Кбайт, скачиваний: 1027) |
Сообщ.
#17
,
|
|
|
Цитата core-i7 @ А на ВМ проц типа стартует сразу с разогнанной частоты, поэтому и показывает её? овер биоса на неё не влияет Добавлено Цитата core-i7 @ Я в том году поинтереснее код для теста начал писать, но не доделал. Хотя, осталось чуть-чуть.Спасибо вот Jin X поправил. Я вот только думаю, есть ли смысл выравнивать тестовый код по 16 байтам? Как я понял, основная фишка этого выравнивания в том, чтобы весь код попал в один 16-байтный блок. Т.е. если код занимает, скажем, 8 байт (ну или 24), то он может начинаться с любого адреса от 0 до 7 (в младшем полубайте), разницы не будет никакой. update: Вот инфа по этому поводу. Получается, что так и есть. Прикреплённый файлcode_align.png (101,79 Кбайт, скачиваний: 1191) |
Сообщ.
#18
,
|
|
|
Доделал вроде как вполне приличную тестилку скорости кода.
Пока только под 64 бита. format PE64 Console 5.0 include 'win64axp.inc' ;-- CODE SECTION ------------------------------------------------------------------------------------------------------- .code entry: frame ; -1 is handle of current process (GetCurrentProcess), -2 is handle of current thread (GetCurrentThread) invoke SetProcessAffinityMask, -1, 1 ; to aviod CPU migration invoke SetPriorityClass, -1, REALTIME_PRIORITY_CLASS ; available only when running with administrator rights invoke SetThreadPriority, -2, THREAD_PRIORITY_TIME_CRITICAL stdcall SpeedTestInit, -1 stdcall SpeedTestMsg, test1, 'Testing 1...', <' %llu ticks%s',10>, ' (CPU migration is detected)' stdcall SpeedTestMsg, test2, 'Testing 2...', <' %llu ticks%s',10>, ' (CPU migration is detected)' stdcall SpeedTestMsg, test3, 'Testing 3...', <' %llu ticks%s',10>, ' (CPU migration is detected)' invoke SetThreadPriority, -2, THREAD_PRIORITY_NORMAL invoke SetPriorityClass, -1, NORMAL_PRIORITY_CLASS cinvoke printf, 'Press a key to exit...' cinvoke getch invoke ExitProcess, 0 endf align 16 test1: xor eax,eax cpuid ret align 16 test2: mov ecx,65536 @@: dec ecx jnz @B ret align 16 test3: mov ecx,65536 loop $ ret ;-- SPEED TEST PROCEDURES ---------------------------------------------------------------------------------------------- ; Speed-test procedures for Windows x64, v1.00a ; (c) 2020 by Jin X (jin_x@list.ru) SPEEDTEST_REPEATS = 256 ; number of code execution repeats (must be power of two!!!) SPEEDTEST_WARMUPS = 1 shl (bsr SPEEDTEST_REPEATS / 2) ; number of warming-up executions assert SPEEDTEST_WARMUPS >= 0 & SPEEDTEST_REPEATS > 0 & bsf SPEEDTEST_REPEATS = bsr SPEEDTEST_REPEATS ; Initialize speed-test and show message if needed (via printf) ; Parameters: ecx = show message flags: bit 0 - when rdtscp is NOT supported, bit 1 - when invariant TSC is NOT supported, bit 2 - when everything's ok (ecx = -1 - all messages) ; Returns: rax = unsupported feature flags: bit 0 - rdtscp is NOT supported, bit 1 - invariant TSC is NOT supported (eax = 0 - both features are supported) proc SpeedTestInit uses rbx, MsgFlags frame mov r8b,3 ; temp result mov r9d,ecx ; show message flags mov eax,0x80000000 cpuid mov r10d,eax ; max extended cpuid leaf level ; RDTSCP instruction support check mov eax,0x80000001 cmp r10d,eax jb .no_inv ; both features are NOT supported cpuid bt edx,27 ; rdtscp support bit jnc .no_rdtscp and r8b,not 1 ; mark as supported mov [SpeedTestGetTSC],SpeedTestRDTSCP ; use RDTSC instruction .no_rdtscp: ; Invariant TSC support check mov eax,0x80000007 cmp r10d,eax jb .no_inv cpuid bt edx,8 ; invariant TSC support bit jnc .no_inv and r8b,not 2 ; mark as supported .no_inv: mov bl,r8b mov bh,bl ; save result mask test bl,bl setz cl shl cl,2 or bl,cl ; set bit 2 in r8d if both features are supported and bl,r9b ; bit mask for messages ; Messages test bl,1 jz @F cinvoke printf, <"Warning: RDTSCP instruction is not supported, RDTSC will be used instead (CPU migration can't be detected)!", 10> @@: test bl,2 jz @F cinvoke printf, <"Warning: invariant TSC is not supported (results may be inaccurate)!", 10> @@: test bl,4 jz @F cinvoke printf, <"Success: both RDTSCP instruction and invariant TSC are supported.", 10> @@: ; Measure overhead xor eax,eax mov [SpeedTestOverhead],rax stdcall SpeedTest, SpeedTestEmptyFunc ; overhead test mov [SpeedTestOverhead],rax movzx eax,bh ; results ret endf endp ; SpeedTestInit ; Measure procedure speed and show message (via printf) ; Parameters: ; * rcx = proc address ; * rdx = starting message (0 - no message, -1 - 'Testing...' message); ; * r8 = result message (0 - no message, -1 - just a number of ticks and new line), should contain '%llu' for result TSC count and then '%s' (optional) for CPU migration message (specified by r9); ; * r9 = CPU migration message (optional, should be used only is r8 message contains '%s'). ; Returns: rax = TSC count (always positive value), zf = 1 if no CPU migration is occured proc SpeedTestMsg ProcAddr, PreMsg, ResultMsg, MigMsg SpeedTestMsg% = 0 ; turn off parameter count check frame mov [ProcAddr],rcx mov [ResultMsg],r8 mov [MigMsg],r9 ; Starting message test rdx,rdx jz .no_start cmp rdx,-1 jne @F mov rdx,.testing_msg @@: cinvoke printf, '%s', rdx .no_start: ; Test speed stdcall SpeedTest, [ProcAddr] mov [ProcAddr],rax setz byte [PreMsg] ; save zf ; Result message mov r8,.no_message jz @F ; jump if no CPU migration mov r8,[MigMsg] @@: mov rcx,[ResultMsg] test rcx,rcx jz .no_results cmp rcx,-1 jne @F mov rcx,.just_ticks @@: cinvoke printf, rcx, rax, r8 .no_results: ; Return values mov rax,[ProcAddr] dec byte [PreMsg] ; restore zf ret endf .testing_msg db 'Testing...',0 .just_ticks db ' %llu',10 .no_message db 0 endp ; SpeedTestMsg ; Measure procedure speed ; Parameters: rcx = proc address ; Returns: rax = TSC count (always positive value), zf = 1 if no CPU migration is occured proc SpeedTest uses rbx rsi rdi r12 r13 r14 r15, ProcAddr frame mov r12,rcx ; Warming-up calls if SPEEDTEST_WARMUPS > 0 mov esi,SPEEDTEST_WARMUPS @@: stdcall r12 dec esi jnz @B end if ; Main tests cld mov rdi,SpeedTestResults xor r15d,r15d mov esi,SPEEDTEST_REPEATS @@:; invoke SwitchToThread ; try to update thread time slice invoke SpeedTestGetTSC ; get ticks in rax, CPU id in ecx mov r13,rax mov r14d,ecx stdcall r12 ; main call invoke SpeedTestGetTSC ; get ticks in rax, CPU id in ecx sub rax,r13 sub rax,[SpeedTestOverhead] ; result TSC count stosq ; store to SpeedTestResults sub ecx,r14d ; detect CPU migration or r15d,ecx ; migration flag for all tests dec esi jnz @B if SPEEDTEST_REPEATS > 2 ; Sort results mov rcx,SpeedTestResults mov rdx,SPEEDTEST_REPEATS stdcall InsertionSort64 end if ; Calculate average CPU ticks if SPEEDTEST_REPEATS <= 2 mov ecx,SPEEDTEST_REPEATS else mov ecx,SPEEDTEST_REPEATS/2 ; use only 50% of results from array middle (assuming that 25% at the start and end are errors) end if xor eax,eax xor edx,edx @@: add rax,[SpeedTestResults+(SPEEDTEST_REPEATS/4)*8 + rdx*8] ; sum of all relevant results inc edx dec ecx jnz @B if SPEEDTEST_REPEATS > 2 sar rax,bsr (SPEEDTEST_REPEATS/2) ; average value else if SPEEDTEST_REPEATS = 2 sar rax,bsr SPEEDTEST_REPEATS ; average value test rax,rax end if cmovs eax,ecx ; zero result if negative test r15d,r15d ; zf = 1 if no CPU migration is occured ret endf endp ; SpeedTest ; Read TSC via RDTSC [for internal use] ; Returns: rax = current TSC counter value, ecx = 0 (processor id detection is not supported) ; Changes ebx !!! if used SpeedTestRDTSC SpeedTestRDTSC: xor eax,eax ; cpuid execution time may vary depending on eax value cpuid ; serialization xor ecx,ecx rdtsc shl rdx,32 or rax,rdx mfence SpeedTestEmptyFunc: ret end if ; used SpeedTestRDTSC ; Read TSC via RDTSCP [for internal use] ; Returns: rax = current TSC counter value, ecx = processor id if used SpeedTestRDTSCP SpeedTestRDTSCP: rdtscp shl rdx,32 or rax,rdx mfence ret end if ; used SpeedTestRDTSCP if used InsertionSort64 ; Insertion sort of 64-bit elements ; Parameters: rcx = array address, rdx = number of elements InsertionSort64: mov r8d,1 ; start key_index cmp rdx,r8 jle .exit ; jump if number of element <= 1 .loop1: mov rax,[rcx+r8*8] ; key mov r9,r8 ; el_index .loop2: mov r10,[rcx+(r9-1)*8] ; prev_el cmp r10,rax ; prev_el <=> key ? jng @F mov [rcx+r9*8],r10 ; if (prev_el > key) el = prev_el dec r9 ; --el_index jnz .loop2 ; repeat if el_index > 0 @@: mov [rcx+r9*8],rax ; el = key inc r8 ; ++key_index cmp r8,rdx jb .loop1 ; repeat if key_index < number of elements .exit: ret end if ; used InsertionSort64 ;-- DATA SECTION ------------------------------------------------------------------------------------------------------- .data if used SpeedTestInit SpeedTestGetTSC dq SpeedTestRDTSC ; TSC read procedure SpeedTestOverhead rq 1 ; TSC read overhead tick count SpeedTestResults rq SPEEDTEST_REPEATS ; Temporary result array end if ; used SpeedTestInit ;-- IMPORT SECTION ----------------------------------------------------------------------------------------------------- section '.idata' import data readable library kernel32, 'kernel32.dll',\ msvcrt, 'msvcrt.dll' import_kernel32 all_api import msvcrt,\ printf, 'printf',\ getch, '_getch' Прикреплённый файлspeedtest64.fasm (8,73 Кбайт, скачиваний: 740) |
Сообщ.
#19
,
|
|
|
Цитата Jin X @ А на ВМ проц типа стартует сразу с разогнанной частоты, поэтому и показывает её? ..имхо на вирту вообще не нужно делать ставки, поскольку она живёт своей жизнью Цитата Jin X @ Доделал вроде как вполне приличную тестилку скорости кода прикольно получилось - зачёт! |
Сообщ.
#20
,
|
|
|
Цитата core-i7 @ Я там косякнул кое-где (с цифровыми параметрами для SpeedTestMsg) прикольно получилось - зачёт! Сейчас исправил, сообщение обновил |
Сообщ.
#21
,
|
|
|
И снова исправлен косячок, добавленный в результате предыдущего исправления: прога всегда показывала CPU migration
Файлы обновлены. Сообщения были разделены в тему "Определение микроархитектуры CPU" |
Сообщ.
#22
,
|
|
|
core-i7, ты знаешь, всё-таки QPC использует не HPET, даже при значениях QPF = 10 млн.
Я тут почитал кое-что. Во-первых, для HPET нужно идти в ядро, а QPC этого не делает (по крайней мере, у меня на 10-ке точно, да и на 7-ке, насколько я помню, было так же). Во-вторых, он читает RDTSCP и дальше выполняет какие-то хитрые арифметические операции, в результате чего преобразует это значение в QPC-счётчик. Причём, он выполняет не только деление (через умножение), но и зачем-то добавляет какие-то числа, ибо отношение RDTSCP/QPC постепенно растёт. |
Сообщ.
#23
,
|
|
|
Цитата Jin X @ Во-вторых, он читает RDTSCP и дальше выполняет какие-то хитрые арифметические операции тогда QPF должна быть привязана к частоте процессора чтоли? (ведь QPF и QPC работают синхронно) к примеру у меня CPU=1.1 GHz и QPF возвращает 10 MHz, ты говоришь, что у тебя тоже 10 MHz, а частота процессора какая? и почему тогда, если НРЕТ не поддерживается чипсетом, то QPF в аккурат равна частоте ACPI-таймера 3.579545 MHz - где параллель с TSC ??? |
Сообщ.
#24
,
|
|
|
Не исключено, что занижение частоты связано со всякими там Spectre. Хотя и верится несколько с трудом, т.к. занижение QPF выполнено гораздо раньше, чем сообщено о той же Spectre. Ну или о Spectre было уже давно известно, гораздо раньше публикаций.
|
Сообщ.
#25
,
|
|
|
Цитата core-i7 @ Нет.тогда QPF должна быть привязана к частоте процессора чтоли? Как я понял, винда на старте проверяет наличие invariant TSC. Если он присутствует, то вычисляет кол-во циклов в секунду и определяет делитель (обратный множитель). А вот время вызова QPC проверяется выбранный на старте режим (HPET или TSC), и если используется TSC, читает его, добавляет что-то ещё зачем-то и делит на этот делитель, подгоняя таким образом к частоте 10 МГц. Цитата core-i7 @ Подозреваю, что там, где используется APCI-таймер, винда не самая свежая, либо нет ни invariant TSC, ни HPET. и почему тогда, если НРЕТ не поддерживается чипсетом, то QPF в аккурат равна частоте ACPI-таймера 3.579545 MHz - где параллель с TSC ??? Добавлено Цитата Qraizer @ Сомневаюсь, что кто-то будет использовать QPC для тестов кэша Не исключено, что занижение частоты связано со всякими там Spectre. Ну и да, эта канитель никогда на частоте проца не работала, насколько я понимаю. |