· Начало · Статистика · WASM.RU · Noir.Ru ·

 WASM Phorum (Оффлайн - 24.11.2003) —› WASM.ASSEMBLER —› RDTSC рассчитать частоту

Посл.отвђт Сообщенiе


Дата: Мар 27, 2003 17:12:41

Привет!
как рассчитать частоту (количество тиков в секунду) для счетчика, значение которого возвращается инструкцией RDTSC.
Спасибо!


Дата: Мар 27, 2003 17:15:35

RDTSC возвращает не частоту, а кол-во тактов.


Дата: Мар 27, 2003 17:28:28

???


Дата: Мар 28, 2003 01:13:22

Ну эта комманда возвращает текущее количество тактов, которое процессор сделал с момента его включения.


Дата: Мар 28, 2003 04:09:56 · Поправил: P2M

andsin
Если речь о частоте процессора, то общая идея такая:
1. Выполнить RDTSC, сохранить EDX:EAX - old.
2. Сделать паузу - Sleep(500).
3. Выполнить RDTSC, сохранить EDX:EAX - cur.
4. Определить прошедшее число тактов cnt = cur - old.
5. Опередлить частоту (Гц) freq = cnt / 500.
Для более точного определения необходимо выполнить эти шаги несколько раз. Если делать их под win32, то приложение должно выполняться с высоким классом приоритета SetPriorityClass + SetThreadPriority.

Еще посмотрите Using the RDTSC Instruction for Performance Monitoring (73'944 байта)


Дата: Мар 28, 2003 10:11:43

Спасибо!
вопрос стоял именно в определении частоты процессора. сегодня пришла идея отмерить временной интервал, выпулив в СОМ порт пачку байтов (в моем драйвере обрабатываются прерывания порта и передача длится ровно 1с). получил довольно точное значение частоты(возможности использовать CPUID нет-старая машина).


Дата: Мар 28, 2003 10:36:38

Когда мне нужно было определить частоту процессора (в мегагерцах), я писал следующий код:

;------ биты регистра edx после cpuid (eax=1 - второй вызов)
bFPU equ 00000001h ;0
bVME equ 00000002h ;1
bDE equ 00000 004h ;2
bPSE equ 00000008h ;3
bTSC equ 00000010h ;4
bMSR equ 000 00020h ;5
bPAE equ 00000040h ;6
bMCE equ 00000080h ;7
bCX8 equ 0 0000100h ;8
bAPIC equ 00000200h ;9
bReserv equ 00000400h ;10
bSEP equ 00000800h ;11
bMTRR equ 00001000h ;12
bPGE equ 00002000h ;13
bMCA equ 00004000h ;14
bCMOV equ 00008000h ;15
bPAT equ 0001000 0h ;16
bPSE36 equ 00020000h ;17
bID equ 00040000h ;18
bMMX equ 0 0800000h ;23
bFXSR equ 01000000h ;24
bSIMD equ 02000000h ;25

.d ata
align 4
TSC_Start LARGE_INTEGER <> ;счетчик тактов начала теста
TSC_End LARGE_INTEGER <> ;счетчик тактов окончания теста
LI_Start LARGE_INTEGER <> ;время начала теста
LI_End LARGE_INTEGER <> ;время окончания теста
TickFreq LARGE_INTEGER <> ;частота обновления счетчика
temp DWORD ;временная переменная


.code
;------ определяем возможность использования команды CPUID
pushfd
pop eax
xor eax,00200000h ;изменить флаг ID
push eax
popfd
pushfd
pop ebx
.if eax==ebx ;команда CPUID поддерживается

xor eax,eax
cpuid ;первый вызов cpuid

;------ если при первом вызове cpuid в eax не ноль,
; эту команду можно вызывать еще раз
.if eax

mov eax,1
cpuid

;------ определить наличие бита TSC, необходимого
; для определения частоты процессора
test edx,bTSC
.if !ZERO?

;------ определить частоту обновления счетчика
invoke QueryPerformanceFrequency,offset TickFreq

invoke Sleep,1

.repeat
;------ определяем время начала теста
invoke QueryPerformanceCounter,offset LI_Start

;------ считываем счетчик тактов
rdtsc
mov TSC_Start.HighPart,edx
mov TSC_Start.LowPart,eax

invoke Sleep,1

;------ определяем время окончания теста
invoke QueryPerformanceCounter,offset LI_End

;------ считываем счетчик тактов
rdtsc
mov TSC_End.HighPart,edx
mov TSC_End.LowPart,eax

mov eax,LI_End.LowPart

;------ если перешагнули через границу между старшим
; и младшим словом, - повторяем операцию.
.until eax>LI_Start.LowPart

sub eax,LI_Start.LowPart

;------ теперь в eax находится чистое время между измерениями
push eax

mov temp,0FFFFFFFFh

fild TSC_End.HighPart
fld1
fiadd temp
fmulp st(1),st
fiadd TSC_End.LowPart

fild TSC_Start.HighPart
fld1
fiadd temp
fmulp st(1),st
fiadd TSC_Start.LowPart

fsubp st(1),st ;T2-T1
fimul TickFreq.LowPart

;------ т.к. меня интересует частота в мегагерцах,
; ввожу коэффициент 1/1000000
mov temp,1000000
fidiv temp

pop temp
fidiv temp

fistp temp ;в переменной temp - результат

.endif ;конец (!ZERO?)
.endif ;конец (eax) - первый вызов cpuid
.endif ;конец (eax==ebx)


Дата: Мар 28, 2003 11:14:44

наверное, я что-то не понял... если есть возможность вызвать QueryPerformanceXXX, которые возвращают именно частоту в МГц и кол-во системных тиков, то зачем RDTSC.


Дата: Мар 28, 2003 11:22:32

наверное, я что-то не понял... если есть возможность вызвать QueryPerformanceXXX, которые возвращают именно частоту в МГц и кол-во системных тиков, то зачем RDTSC.


Дата: Мар 28, 2003 14:06:03

Вот, выдрал из какого-то исходника.
Код достаточно ламерной, но работает, по крайней мере на незагруженной машине.
Что там будет если камень посильнее нагрузить не знаю.


.586p
.model flat, stdcall
option casemap:none

include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\user32.inc

includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\user32.lib

.data
szCaption db "CPU speed (MHz)", 0
szFormat db "%u", 0

.data?
timerHi dd ?
timerLo dd ?
szBuffer db 42 dup (?)

.const
; delay
delay dd 500
constant dd 1000

.code

determineSpeed proc
LOCAL prClass:DWORD, priority:DWORD

pushad
; save initial priority settings
invoke GetCurrentProcess
invoke GetPriorityClass, eax
mov [prClass], eax
invoke GetCurrentThread
invoke GetThreadPriority, eax
mov [priority], eax
; set new priority settings

invoke GetCurrentProcess
invoke SetPriorityClass, eax, REALTIME_PRIORITY_CLASS
invoke GetCurrentThread
invoke SetThreadPriority, eax, THREAD_PRIORITY_TIME_CRITICAL

; get speed
; revoke rest of our timeslice
invoke Sleep, 0

rdtsc
mov [timerLo], eax
mov [timerHi], edx

; --------
invoke Sleep, delay
; --------

;
; mostly for fun: serialize by using RDTSC
xor eax, eax
rdtsc

rdtsc
sub eax, [timerLo]
sbb edx, [timerHi]
mov [timerLo], eax
mov [timerHi], edx

; restore initial priority settings
invoke GetCurrentThread
invoke SetThreadPriority, eax, [priority]
invoke GetCurrentProcess
invoke SetPriorityClass, eax, [prClass]

; final calculations
finit
fild dword ptr [constant]
fild dword ptr [delay]
fmulp st(1), st
fild dword ptr [timerLo]
fxch
fdivp st(1), st
frndint
fistp dword ptr [esp + 28] ; EAX offset in PUSHAD block
wait
popad
ret
determineSpeed endp

start:
invoke Sleep, 100
call determineSpeed
invoke wsprintf, addr szBuffer, addr szFormat, eax
invoke MessageBox, NULL, addr szBuffer, addr szCaption, MB_OK

invoke ExitProcess, 0

end start


Дата: Мар 28, 2003 15:36:19

Ребята, большое спасибо!
наверное, я не сделал достаточный акцент на то, что это драйвер, хотя в (andsin Дата: Мар 28, 2003 10:11:43) я об этом писал. извините. из драйвера я не имею доступа к таймеру, который вызывается по Sleep, мало того, мне такой таймер необходим аки воздух. вчера я задал вам вопрос, основательно изломав голову над тем, как приостановить драйвер на какое-то время. сегодня утром понял - можно подождать пока по порту отправляется пакет, чем порт не таймер.
спасибо за помощь и содействие!


Дата: Мар 28, 2003 17:46:00

В ядре тоже можно таймер создать, принципиальной разницы никакой, только функции другие, а если поспать, то KeDelayExecutionThread.


Дата: Мар 28, 2003 18:54:45

Спасибо!
на счет KeDelayExecutionThread не знал. искал в DDK, но найти не смог


Powered by miniBB 1.6 © 2001-2002
Время загрузки страницы (сек.): 0.073