経過時間をミリ秒単位で測るコードを書く際、以前からある標準関数のtime()は秒までしか分からなかったり、Win32のtimeGetTime()はgccでは使えなったりして不便でした。
OSに依存せずミリ秒単位まで測れる方法を探していたところ、ナノ秒まで測れるtimespec_get()がC11で追加されたとのこと。
今更C11非対応のCコンパイラーはないだろうと思い、試してみました。
使い方
コピー先のポインターを渡します。
tv_secはtime()と共通なのでlocaltime()で日付や時刻へ変換出来ます。
#include <time.h>
struct timespec {
time_t tv_sec;
long tv_nsec;
};
int timespec_get (struct timespec *ts, TIME_UTC);
実装例
具体的には以下のように活用しています。WindowsでもLinuxでもビルド可能です。
TimeTest.c
#include <stdio.h>
#include <time.h>
unsigned long GetTime(void);
unsigned long DiffTime(unsigned long lVal, unsigned long lRef);
int main(int argc, char argv[])
{
unsigned long lTmStart, lTmNow, lTmDiff;
unsigned long lCounter = 0;
lTmStart = GetTime();
for(int nLoop4=0; nLoop4<3; nLoop4++) {
for(int nLoop3=0; nLoop3<1000; nLoop3++) {
for(int nLoop2=0; nLoop2<1000; nLoop2++) {
for(int nLoop1=0; nLoop1<1000; nLoop1++) {
lCounter ++;
}
}
}
//--------
lTmNow = GetTime();
lTmDiff = DiffTime(lTmNow, lTmStart);
printf("%d %ld %ldmsec\n", (nLoop4+1), lCounter, lTmDiff);
}
return(0);
}
unsigned long GetTime(void)
{
unsigned long lRet;
struct timespec ts;
timespec_get(&ts, TIME_UTC);
lRet = (unsigned long)((((ts.tv_sec) % (24 * 60 * 60)) * 1000) +
((ts.tv_nsec) / (1000 * 1000)));
return(lRet);
}
unsigned long DiffTime(unsigned long lVal, unsigned long lRef)
{
unsigned long lDiff = 0;
if(lVal<lRef) {
lDiff = (24 * 60 * 60 * 1000) + lVal - lRef;
}
else {
lDiff = lVal - lRef;
}
return(lDiff);
}
実行例
最適化を指定しないでビルドすると、筆者の年代物のポンコツPCでは
10億回ループするのに2秒近くかかります。
$ gcc -o TimeTest TimeTest.c
$ ./TimeTest
1 1000000000 1987msec
2 2000000000 3948msec
3 3000000000 5909msec
最適化すると、あっという間に終了します。
$ gcc -o TimeTest TimeTest.c -O2
$ ./TimeTest
1 1000000000 0msec
2 2000000000 0msec
3 3000000000 0msec