unit Unit2; interface uses Windows, SysUtils; function GetCPUClock: Double; implementation 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; 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; initialization InitCPUClock; end.