今回はちょっとお遊びです(^^;
インテルのWebサイトからダウンロードしてきたデベロッパーズマニュアルを覗いていたら、「クロック周波数を計算できねーかな?」と思って作ってみました。興味がない方は時間の無駄ですので、他のページに飛んだ方がいいです(笑)
さて能書きはこれくらいにして...まず、クロック周波数の計算を行う前にやっておかなければならないことがあります。CPUID命令が使えるか調べ、CPUID命令を実行してRDTSC命令が使えるか調べなくてはなりません。そのための関数を二つ作成します。
CPUID命令が使えるかどうかを調べるには、EFLAGSのビット21を設定できるか否かで判断できます。それを調べるのがEnabledCPUID関数です。
RDTSC命令が使えるかを調べるにはEAXレジスタに$01を設定しCPUID命令を実行します。EDXレジスタにはCPUの機能情報が入ります。RDTSCが使える場合EDXレジスタのビット4が1に設定されるので、それを調べればよいわけです。
function EnabledCPUID: Boolean; assembler;
//CPUID命令が使えるか調べる関数
asm
PUSH EDX //念のために退避
PUSH ECX //念のために退避
XOR EAX, EAX //ゼロクリア
PUSHFD //EFLAGSをスタックにプッシュ
POP EDX //EDXにロード
MOV ECX, EDX //比較のためにECXに退避
XOR EDX, $200000 //ビット21を設定
PUSH EDX //スタックにプッシュ
POPFD //EFLAGSに読み込ませる
PUSHFD //EFLAGSをスタックにプッシュ
POP EDX //EDXにロード
XOR EDX, ECX //ビット21がクリアされているか調べる
SETNZ AL //ZF = 0の場合CPUIDが使える
POP ECX //元の内容に戻す
POP EDX //元の内容に戻す
end;
function EnabledRDTSC: Boolean; assembler;
//RDTSC命令が使えるか調べる関数
asm
CALL EnabledCPUID //CPUIDは使える?(上の関数を呼び出す)
CMP EAX, $01 //戻り値を比較
JE @@1 //Trueの場合@@1にジャンプ
XOR EAX, EAX //使えねー
RET //ここで関数を終了
@@1://CPUIDが使える
PUSH ECX //念のために退避
PUSH EDX //念のために退避
PUSH EBX //EBXは保護しないといけないので退避
XOR EAX, EAX //EAXをゼロクリア
DW $A20F //CPUID
CMP EAX, $01 //最大入力値が1以上あるか?
JB @@2 //ない(つまりEAX=0ちゅーこと)
MOV EAX, $01 //あるのでEAXを1にして...
DW $A20F //CPUIDを実行
XOR EAX, EAX //EAXをゼロクリア(戻り値として使う)
TEST EDX, $10 //ビット4が設定されてる?
SETNZ AL //ZFを反転して転送
JMP @@3 //終わり
@@2://RDTSCは使えない
XOR EAX, EAX
@@3://後始末
POP EBX //スタックに退避したEBXを戻す
POP EDX //元の内容に戻す
POP ECX //元の内容に戻す
end;
次にCPUクロックを計算する関数です。InitCPUClockはアプリケーションに起動時にでも呼び出してください。
var
StartTime: Cardinal = 0;
StartTSC : Int64Rec;
StartTSC64: Int64 absolute StartTSC;
function InitCPUClock: Boolean;
//CPUクロックの計算に必要な変数などを初期化する
begin
Result := EnabledRDTSC;
if Result then
begin
StartTime := GetTickCount;
asm
PUSH EDX //念のために退避
PUSH EAX //念のために退避
DW $310F //RDTSC
MOV DWORD PTR [StartTSC.Hi], EDX
MOV DWORD PTR [StartTSC.Lo], EAX
POP EAX //元の内容に戻す
POP EDX //元の内容に戻す
end;
end;
end;
function GetCPUClock: Double;
//CPUクロックを計算する
var
CurrTSC: Int64Rec;
CurrTSC64: Int64 absolute CurrTSC;
begin
if StartTime > 0 then
begin
asm
PUSH EDX //念のために退避
PUSH EAX //念のために退避
DW $310F //RDTSC
MOV DWORD PTR [CurrTSC.Hi], EDX
MOV DWORD PTR [CurrTSC.Lo], EAX
POP EAX //元の内容に戻す
POP EDX //元の内容に戻す
end;
Result := ((CurrTSC64 - StartTSC64) /
(GetTickCount - StartTime)) / 1000; // MHz
end else
Result := 0;
end;
|