Linux 2.6 では、clock_gettime() も用いることができる。 clock_gettime() では、第一引数でクロックを指定することにより、 共通のインタフェースでREALTIMEクロック(システム時計)やPROCESS_CPUTIME(TSC)を使い分けることができる。 glibc-2.5 では、CLOCK_REALTIME の実体は gettimeofday() であり、一方、PROCESS_CPUTIME では RDTSC を用いている。
一方、通常の gettimeofday() で用いている struct timeval では、マイクロ秒までの解像度しか得られない。 しかも、RDTSC命令は、アセンブラにより、ユーザプロセス内で呼出すことができるため、変動も少ない。
このように優れたRDTSC であるが、 PCの起動時にゼロリセットされ、しかも温度補償されていない水晶の発振周波数を直接利用 しているため、 現実世界の時刻(JST:日本標準時あるいはUTC:協定世界時)との対応付けは困難である。 NICTでは、RDTSC をベースに、国際原子時(TAI)と同期させ、ユーザランドで時刻を取得できるnst_gettai()関数を 公開している。
ところで、近年のPC では、デュアルコアなどマルチCPUを使用している。 マルチCPUシステムでは、TSCレジスタはCPU毎に存在しており、同一時刻でもTSC毎に値が若干異っている。 また、省電力化に伴い、CPU動作周波数を動的に変化させる場合もあり、 その場合、TSC値と時刻は比例しなくなる。 このように、TSCを時刻源として利用することが困難な場合が増えてきているため、 HPET (High Precision Event Timer) の導入が進められている。 しかし、チップセットにあるHPETのカウンタをI/O命令で参照するため、 オーバヘッドが大きく、マイクロ秒以下の計測には適していない。
次に、これらの時刻取得関数の特徴をまとめる。
Function | EPOC | Resolution | Latency (Overhead) | SMP, Dynamic CPU clock |
---|---|---|---|---|
gettimeofday() | UNIX time | 1 micro second | 1 micro second | △ |
clock_gettime(CLOCK_REALTIME) | UNIX time | 1/HZ | 1 micro second | ○ |
clock_gettime(CLOCK_MONOTONIC) | Hardware Boot | 1/HZ | 1 micro second | ○ |
clock_gettime(CLOCK_PROCESS_CPUTIME_ID) | Process starts | 1 nano second | tens of nano second | × |
RDTSC | Hardware Boot | 1 / CPUclock | tens of nano second | × |
nst_gettai() | UNIX time | 1 nano second | tens of nano second | × |
HPET | Hardware Boot | tens of nano second | 0.5 micro second | ○ |
ioctl(netPath->eventSock, SIOCGSTAMPNS, &ts))
[Advanced]-[Jumperfree Configuration]-[Spread Spectrum]: Disable [Advanced]-[CPU Configuration]-[Intel(R) SpeedStep Technology]: Disableまた、linux カーネル設定で、
# CONFIG_SMP is not set # CONFIG_CPU_FREQ is not setなどとして、SMPやCPU動作周波数の変動を抑える。
これらの設定は、処理能力や消費電力などに関しては性能を低下させるので、 サブマイクロ秒精度が必要な場合に限って設定しましょう。