cpufreq.as [CPU周波数モジュール]
;*******************************************************************************
; CPU Frequency module [2007.02.23]
; CPUID module, CPUFREQ module
; Programmed in HSP Ver3.1 ONION software (http://hsp.tv/)
; Copyright (C) 2007 by abo, all rights reserved.
;*******************************************************************************
#ifdef __hsp30__
#ifndef __CPUFREQ__
#define global __CPUFREQ__
#module "cpufreq"
/************************************************************************
CPUID p1,p2 ・・・CPU情報を取得
p1:情報を受け取る変数
p2:EAXの初期値(省略時=0)
---------------------------
・p2をEAXにセットしてcpuidを実行し、EAX,EBX,ECX,EDXの値をp1.0〜3にセット
します
・p2を0にして実行すると、まずcpuidが使用できるか(EFLAGSのbit21を変更できるか)
をチェックします
このときp1に0がセットされると、CPUIDは使用できません
RDTSC p1 ・・・TSC(タイムスタンプ・カウンタ)を取得
p1:情報を受け取る変数(符号なし64bit整数)
---------------------------
・p1は符号なし32bit整数、TSCは符号なし64bit整数として扱われます
・TSCは64bitの大きさを持ち、CPUがリセット時に0から始まり、クロック・
サイクルごとに+1されるカウンタです
・この命令が使用できるかをCPUIDであらかじめ調べておく必要があります
調べ方:
flag=0
CPUID reg,0
if reg{
CPUID reg,1
flag=reg.3>>4&1
}
if flag==1:mes "使用可能" :else :mes "使用不可能"
**********************************************************************/
#deffunc __init_cpuid
#define global CPUID(%1,%2=0) prm@cpufreq=varptr(%1),%2 :\
res=callfunc( prm@cpufreq, varptr(fnCpuid@cpufreq), 2 )
#define global RDTSC(%1) prm@cpufreq=varptr(%1) :\
res=callfunc( prm@cpufreq, varptr(fnRDTSC@cpufreq), 1)
; ****************************************************************************
; asmlist
xdim fnCpuid,16
asm fnCpuid,{"
ORG 0
PUSH EBP
MOV EBP,ESP
PUSH EBX
PUSH ESI
MOV EAX,[EBP+0x0C] ;EAX <- p2
OR EAX,EAX
JNZ L0 ;if p2!0
PUSHFD
POP EAX ;EFLAGS Register
MOV EBX,EAX ;EBX <- pre EFLAGS
XOR EAX,0x00200000 ;Reverse ID Flag(bit21)
PUSH EAX
POPFD
PUSHFD
POP ECX ;ECX <- new EFLAGS
XOR EAX,EAX ;EAX <- 0[Initial setting]
CMP ECX,EBX
JZ L1 ; if pre = new : not CPUID
L0:
CPUID
MOV ESI,[EBP+08] ; varptr(p1)
MOV [ESI],EAX ; p1(0) <- EAX
MOV [ESI+04],EBX ; p1(1) <- EBX
MOV [ESI+08],ECX ; p1(2) <- ECX
MOV [ESI+0x0C],EDX ; p1(3) <- EDX
L1:
POP ESI
POP EBX
LEAVE
RET
END
"}
; ****************************************************************************
xdim fnRdtsc,4
asm fnRdtsc,{"
ORG 0
MOV ECX,[ESP+04] ; ECX <- varptr(p1)
RDTSC ; EDX,EAX <- TSC
MOV [ECX],EAX ; p1(0) <- EAX
MOV [ECX+04],EDX ; p1(1) <- EDX
RET
END
"}
dim prm,2 : dim reg,4 : fCpuid@=0 : fRdtsc@=0
CPUID reg
if reg {
fCpuid@=1
CPUID reg,1
fRdtsc@=reg.3>>4&1
}
return
// getms.dll HSP3移植版
#define global FREQ_TERM 1000
#deffunc __init_cpufreq
dim PreQPC,2 : dim StrQPC,2 : dim EndQPC,2 : dim QPF,2
dim PreTSC,2 : dim StrTSC,2 : dim EndTSC,2
dim NowQPC,2 : dim OldQPC,2
dim ER0,2 : dim ER1,2 : dim ER2,2 : dim ER3,2
dim TIMECAPS,2 ;TIMECAPS構造体
timeGetDevCaps varptr(TIMECAPS),8 ;&tc , sizeof(TIMECAPS)
return
; -----------------------------------------------------------------------------
; aSleep - Sleep関数1msのwait (CPU使用率13%)
; -----------------------------------------------------------------------------
#deffunc aSleep int time
timeBeginPeriod 1 ;tc.wPeriodMin
repeat time
await
Sleep 1
loop
timeEndPeriod 1
return
; -----------------------------------------------------------------------------
; qpctime - 高分解能パフォーマンスカウンタで時間を計る
;
; 戻り値:前回呼び出されてからの経過時間[sec]
; -----------------------------------------------------------------------------
#defcfunc Qpctime
; timeGetDevCaps varptr(TIMECAPS),8 ;&tc , sizeof(TIMECAPS)
timeBeginPeriod 1 ;tc.wPeriodMin
QueryPerformanceCounter varptr(NowQPC)
QueryPerformanceFrequency varptr(QPF)
ER0=LLSUB(NowQPC,OldQPC)
OldQPC=LLCOPY(NowQPC)
timeEndPeriod 1
return LLTOD(ER0)/LLTOD(QPF)
; -----------------------------------------------------------------------------
; Getfreq - CPUのクロック周波数を得る
;
; Getfreq(p1, p2)
; p1: 測定モード
; -----------------------------------------------------------
; 0 高分解能パフォーマンスカウンタ[QueryPerformanceCounter]
; 1 マルチメディアタイマ[MultiMediaTimer]
; 2 ms 単位でスレッドの実行を中断する[Sleep]
; -----------------------------------------------------------
; p2: 測定時間[ms]
; -----------------------------------------------------------------------------
#define global ctype Getfreq(%1,%2=FREQ_TERM) _Getfreq(%1,%2)
#defcfunc _Getfreq int flg,int p3
if (flg<0 || flg>2) : return -1 ;error
timeBeginPeriod 1 ;tc.wPeriodMin
aSleep 100
if (flg==0) { ;----- Sleep -----
RDTSC PreTSC
RDTSC StrTSC
Sleep p3; // ミリ秒
RDTSC EndTSC
ER0=LLSUB(EndTSC,StrTSC)
ER1=LLSUB(StrTSC,PreTSC)
cpuclock=(LLTOD(ER0)-LLTOD(ER1))/p3/1000
}
if (flg==1) { ;----- MultiMediaTimer -----
StrTime=_timeGetTime() : TrgTime=StrTime
repeat
StrTime=_timeGetTime() : if StrTime>TrgTime : break; // ミリ秒
loop
TrgTime=StrTime
repeat
StrTime=_timeGetTime() : if StrTime>TrgTime : break; // ミリ秒
loop
TrgTime=StrTime+p3
RDTSC PreTSC
RDTSC StrTSC
repeat
StrTime=_timeGetTime() : if StrTime>=TrgTime : break
loop; // ミリ秒
RDTSC EndTSC
EndTime=StrTime : StrTime=TrgTime-p3
ER0=LLSUB(EndTSC,StrTSC)
ER1=LLSUB(StrTSC,PreTSC)
cpuclock=(LLTOD(ER0)-LLTOD(ER1))/(Endtime-StrTime)/1000
}
if (flg==2) { ;----- QueryPerformanceCounter -----
StrTime=_timeGetTime() : TrgTime=StrTime
repeat
StrTime=_timeGetTime() : if StrTime>TrgTime : break; // ミリ秒
loop
TrgTime=StrTime
repeat
StrTime=_timeGetTime() : if StrTime>TrgTime : break; // ミリ秒
loop
TrgTime=StrTime+p3
QueryPerformanceCounter varptr(PreQPC)
QueryPerformanceCounter varptr(StrQPC)
RDTSC StrTSC
repeat
StrTime=_timeGetTime() : if StrTime>=TrgTime : break
loop; // ミリ秒
QueryPerformanceCounter varptr(EndQPC)
RDTSC EndTSC
QueryPerformanceFrequency varptr(QPF)
ER0=LLSUB(EndTSC,StrTSC)
ER1=LLSUB(EndQPC,StrQPC)
ER2=LLSUB(StrQPC,PreQPC)
cpuclock=LLTOD(ER0)*LLTOD(QPF)/(LLTOD(ER1)-LLTOD(ER2))/1000000
}
timeEndPeriod 1
return cpuclock
#global
__init_cpuid
__init_cpufreq
#endif ; __CPUFREQ__
#endif ; __hsp30__