しかしながら,Delphi5のインラインアセンブラではRDTSC命令はサポートされていないらしく, コンパイル時にエラーとなる. いろいろ調べてみると,DW命令にアドレス$310Fを指定することで, RDTSCの擬似命令を発行することができるようだ.
総クロック数の引き算を行うためには,読み出したeaxレジスタとedxレジスタの値を 二つの4バイト変数にコピーし,これらからInt64型の変数を生成する必要がある.
ある時点の総クロック数を得るには,例えば以下のようにする.
var
CurrentLo, CurrentHi: DWORD;
Current: Int64;
......
asm
DW $310F // RDTSC
mov CurrentLo, eax
mov CurrentHi, edx
end;
Current := CurrentHi;
Current := CurrentLo or Current shl 32;
与えられた測定時間内のクロック数を得るために,以下のような関数GetCPUClockを作った.
function GetCPUClock( iWait: DWORD ): DWORD;
var
TickTime, StartLo, StartHi, CurrentLo, CurrentHi: DWORD;
Start, Current, Clock: Int64;
begin
if iWait > 1000 then iWait := 1000;
TickTime := GetTickCount;
asm
DW $310F
mov StartLo, eax
mov StartHi, edx
end;
while ( GetTickCount > TickTime + iWait ) do begin end;
asm
DW $310F
mov CurrentLo, eax
mov CurrentHi, edx
end;
Start := StartHi;
Start := StartLo or Start shl 32;
Current := CurrentHi;
Current := CurrentLo or Current shl 32;
Clock := Current - Start;
if Clock > $FFFFFFFF then Clock := $FFFFFFFF;
Result := Clock;
end;
本来ならば,CPUID命令などを使ってRDTSC命令がサポートされているか(Pentium以降のCPUであるか)を 事前に調べた方がいいだろう. サポートされていない命令を発行すると,最悪の場合マシンが落ちる可能性がある. また,eaxやedxの内容をどこかに退避させておいた方がいいかも知れない. この辺りの情報はここやここにある.
PentiumIII 600MHzのマシン(Win2K)での実行結果を以下に示す.
procedure TForm1.Button1Click(Sender: TObject);
var
Clock: DWORD;
begin
Clock := GetCPUClock( 500 );
Edit1.Text := FormatFloat( '###.00', Clock * 2 / 1000000 );
end;
BIOS設定の値とは数クロックの誤差があるが,時間測定やタスクスイッチングによるものだろう. AthlonやCyrixIIIでも試してみたが,両者とも一応測定できた.
全く同じコードをCでも書いてみた.
DLLからエクスポートするための関数である.
#include <windows.h>
DWORD __declspec( dllexport ) __stdcall GetCPUClock( DWORD iWait ){
__int64 start, current, clock;
unsigned long start_lo, start_hi, current_lo, current_hi;
DWORD TickCount, result;
if ( iWait > 1000 ) iWait = 1000;
TickCount = GetTickCount();
__asm{
rdtsc
mov start_lo, eax
mov start_hi, edx
}
while ( 1 ) {
if ( GetTickCount() - TickCount > iWait ) break;
}
__asm{
rdtsc
mov current_lo, eax
mov current_hi, edx
}
start = start_hi;
start = start_lo | start << 32;
current = current_hi;
current = current_lo | current << 32;
clock = current - start;
if ( clock > 0xffffffff ) clock = 0xffffffff;
result = clock;
return result;
}
#define rdtsc __asm __emit 0fh __asm __emit 031h
EXPORTS
GetCPUClock = _GetCPUClock@4
SEO | [PR] 爆速!無料ブログ 無料ホームページ開設 無料ライブ放送 | ||