私のE8200ボックスではこれは発生しませんが、Atom N450ネットブック(両方ともOpenSuse 11.2を実行)では、CPUのTSCを読み取るたびに、戻り値はmod 10 == 0
、つまり、余りが10で割り切れない状態です。RDTSCを使用しています興味深いコードがかかる時間を測定するための値ですが、デモンストレーションの目的で、この小さなプログラムを作成しました。
.text
.global _start
_start: xorl %ebx,%ebx
xorl %ecx,%ecx
xorl %r14d,%r14d
movb $10,%cl
loop: xchgq %rcx,%r15 # save to reg
cpuid
rdtsc
shlq $32,%rdx
xorq %rax,%rdx # full 64 bit of RDTSC
movq %r14,%r13 # save the old value
movq %rdx,%r14 # copy current
movq %r14,%rsi # argv[1] of printf()
subq %r13,%rdx # argv[2] (delta)
leaq format(%rip),%rdi # argv[0]
xorl %eax,%eax # no stack varargs
call printf
xchgq %rcx,%r15
loop loop
0: xorl %eax,%eax
movb $0x3c,%al
syscall
.size _start, .-_start
.data
format: .asciz "rdtsc: %#018llx = %1$llu -- delta: %llu\n"
(私は通常、変換に独自のルーチンを使用しますが、読者がエラーが存在する可能性があることを示唆しないようにするために、ここではprintf()を使用しています。)
上記のコードでは、出力は(たとえば)次のようになります。
rdtsc: 0x000b88ef933ffd06 = 3246787292822790 -- delta: 3246787292822790
rdtsc: 0x000b88ef9342fcf4 = 3246787293019380 -- delta: 196590
rdtsc: 0x000b88ef93435dca = 3246787293044170 -- delta: 24790
rdtsc: 0x000b88ef9343b43c = 3246787293066300 -- delta: 22130
rdtsc: 0x000b88ef93440c34 = 3246787293088820 -- delta: 22520
rdtsc: 0x000b88ef9344604e = 3246787293110350 -- delta: 21530
rdtsc: 0x000b88ef9344b4d6 = 3246787293131990 -- delta: 21640
rdtsc: 0x000b88ef9345085a = 3246787293153370 -- delta: 21380
rdtsc: 0x000b88ef93455d96 = 3246787293175190 -- delta: 21820
rdtsc: 0x000b88ef9345b16a = 3246787293196650 -- delta: 21460
簡単にわかるように、デルタは妥当な量で変化します。しかし、目立つのは(共謀しているとは言えませんが;-)、最下位の10進数が常に0であるということです。
私はこの現象を2年以上観察してきましたが、StackOverflowはこの問題を公開する最初のアドレスではありません。しかし、私はまだどこにも合理的な答えを得ることができませんでした。私たち(私や他の人々)が思いついたアイデアは、
- TSCは10サイクルごとにのみインクリメントされますが、その後10ずつインクリメントされます。
- TSCは内部で正しく更新されますが、10サイクルごとにのみ外部に反映されます。
- TSCはサイクルごとに10ずつ増加します。
ただし、これらの点はどれも実際には意味がありません。E8200(現在は故障しています)でそのようなプログラムを実際に実行して、デルタの大きさのオーダーが上記の出力のオーダーと同じか、それとも10分の1にすぎないかを確認する必要があります。(ボランティアはいますか?)
グーグルは役に立たなかった、インテルのマニュアルも役に立たなかった。
他の人と話し合うとき、同じ行動を経験した人は他にいませんでした。カーネルと関係がある場合、少なくとも3つのバージョンが影響を受けましたが、カーネルはそれと何の関係がありますか?
ネットブックも稼働していて、新しいマザーボードが戻ってきました。これは、新しいCPUを意味するため、N450の少なくとも2つの個別のエンティティが影響を受ける必要があります。
また、クロック周波数の変化に対する対策を講じ(クロックを固定した周波数に関係なく、値は予想される範囲でのみ変化しました(図と同じ))、HTをオフにしましたが、これらは実際にそれらを防ぐのではなく、他のいくつかの最下位桁。しかし、念のために。
さて、誰かが自分のマシンでプログラムを実行したい場合、コマンドラインは次のとおりです(ソースをファイルに保存する場合rdtsc.s
):
as rdtsc.s -o rdtsc.o
ld --dynamic-linker=/lib64/ld-linux-x86-64.so.2 rdtsc.o -L /lib64 -l c -o rdtsc
gccフロントエンドでビルドするには、つまり
gcc -l c rdtsc.s -o rdtsc
_start:
ラベルを追加(またはラベルを置き換える)しmain:
て、グローバルにする必要があります。
[更新(2012-09-15〜21:15 UTC):実際には以前にもこれを行うことができました:の前後にTSCを取得させるだけでsleep(1)
、1,666,000,000をわずかに超えるデルタが得られます。上記のリストのポイントが間違っています。しかし、それでも私は完全な精度が得られない理由がわかりません。/アップデート]