C言語: 実行時間測定の方法
Kazuki Ohta, 2005/12/30
C言語において実行時間を測定する為の方法はいくつかある。clock, gettimeofday, getrusage, timesを利用する方法である。ここではこれらの方法について検証してみる。これは2005/12/30時点での情報であり、古い亊が考えられるので注意して頂きたい。さらに、内容のほとんどはmanを移しただけなので、正確な情報を得るためにそれぞれの関数のmanを見ることを強く推奨する。
System: Linux 2.6.12
glibc: glibc 2.3.5-1ubuntu12
clockを使用する方法
clockはANSI Cで定義されている。返り値の型はclock_tとなっており、その精度はCPU時間で有る。秒単位での値を得る為には、CLOCKS_PER_SECで割る必要が有る。POSIXではCLOCKS_PER_SECが1000000である亊を要求している。
#include <time.h>
#include <stdio.h>
int main(void)
{
int i;
int n = 0;
clock_t t1;
clock_t t2;
printf("CLOCKS_PER_SEC = %f\n", (double)CLOCKS_PER_SEC);
t1 = clock();
for (i = 0; i < 100000; i++)
n *= i;
t2 = clock();
printf("time = %10.30f\n", (double)t2 - t1);
t1 = clock();
for (i = 0; i < 10000000; i++)
n *= i;
t2 = clock();
printf("time = %10.30f\n", (double)t2 - t1);
}
ubuntu% ruby -e '5.times { puts `./a.out` }'
CLOCKS_PER_SEC = 1000000.000000
time = 0.000000000000000000000000000000
time = 110000.000000000000000000000000000000
CLOCKS_PER_SEC = 1000000.000000
time = 0.000000000000000000000000000000
time = 110000.000000000000000000000000000000
CLOCKS_PER_SEC = 1000000.000000
time = 0.000000000000000000000000000000
time = 120000.000000000000000000000000000000
CLOCKS_PER_SEC = 1000000.000000
time = 0.000000000000000000000000000000
time = 120000.000000000000000000000000000000
CLOCKS_PER_SEC = 1000000.000000
time = 0.000000000000000000000000000000
time = 120000.000000000000000000000000000000
gettimeofdayを使用する方法
gettimeofdayはSVr4, BSD 4.3準拠である。返り値の型はsys/time.hに定義されるstruct timevalで有る。
struct timeval {
time_t tv_sec; /* 秒 */
suseconds_t tv_usec; /* マイクロ秒 */
}
#include <time.h>
#include <sys/time.h>
#include <stdio.h>
double gettimeofday_sec()
{
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec + (double)tv.tv_usec*1e-6;
}
int main()
{
int i;
int n = 0;
double t1,t2;
t1 = gettimeofday_sec();
for (i = 0; i < 100000; i++)
n *= i;
t2 = gettimeofday_sec();
printf("time = %10.30f\n", t2 - t1);
t1 = gettimeofday_sec();
for (i = 0; i < 10000000; i++)
n *= i;
t2 = gettimeofday_sec();
printf("time = %10.30f\n", t2 - t1);
}
ubuntu% ruby -e '5.times { puts `./a.out` }'
time = 0.001516103744506835937500000000
time = 0.209121942520141601562500000000
time = 0.002206087112426757812500000000
time = 0.284270048141479492187500000000
time = 0.001529216766357421875000000000
time = 0.216418027877807617187500000000
time = 0.001517057418823242187500000000
time = 0.211354017257690429687500000000
time = 0.001515865325927734375000000000
time = 0.209794998168945312500000000000
getrusageを使用する方法
getrusageはSVr4, BSD 4.3に準拠する。本来は資源の使用量を返す関数で有る。RUSAGE_CHILDRENを指定すれば子プロセスの使用する時間も計測出来る。
#include <time.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <stdio.h>
double getrusage_sec()
{
struct rusage t;
struct timeval tv;
getrusage(RUSAGE_SELF, &t);
tv = t.ru_utime;
return tv.tv_sec + (double)tv.tv_usec*1e-6;
}
int main(void)
{
int i;
int n = 0;
double t1,t2;
t1 = getrusage_sec();
for (i = 0; i < 100000; i++)
n *= i;
t2 = getrusage_sec();
printf("time = %10.70f\n", t2 - t1);
t1 = getrusage_sec();
for (i = 0; i < 10000000; i++)
n *= i;
t2 = getrusage_sec();
printf("time = %10.70f\n", t2 - t1);
}
ubuntu% ruby -e '5.times { puts `./a.out` }'
time = 0.0010000000000000000208166817117216851329430937767028808593750000000000
time = 0.1169819999999999887707602397313166875392198562622070312500000000000000
time = 0.0010000000000000000208166817117216851329430937767028808593750000000000
time = 0.1169819999999999887707602397313166875392198562622070312500000000000000
time = 0.0010000000000000000208166817117216851329430937767028808593750000000000
time = 0.1169819999999999887707602397313166875392198562622070312500000000000000
time = 0.0009989999999999998880895191177842207252979278564453125000000000000000
time = 0.1199819999999999914352954988316923845559358596801757812500000000000000
time = 0.0019989999999999999089062008295059058582410216331481933593750000000000
time = 0.1189819999999999905471170791315671522170305252075195312500000000000000
timesを使用する方法
timesはSVr4, SVID, POSIX, X/OPEN, BSD 4.3に準拠している。返り値の型はstruct tmsであり、クロック数を返す。
struct tms {
clock_t tms_utime; /* user time */
clock_t tms_stime; /* system time */
clock_t tms_cutime; /* user time of children */
clock_t tms_cstime; /* system time of children */
};
#include <time.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/times.h>
#include <stdio.h>
clock_t times_clock()
{
struct tms t;
return times(&t);
}
int main(void)
{
int i;
int n = 0;
clock_t t1;
clock_t t2;
printf("sysconf(_SC_CLK_TCK) = %f\n", (double)sysconf(_SC_CLK_TCK));
t1 = times_clock();
for (i = 0; i < 100000; i++)
n *= i;
t2 = times_clock();
printf("time = %10.30f\n", (double)t2 - t1);
t1 = times_clock();
for (i = 0; i < 10000000; i++)
n *= i;
t2 = times_clock();
printf("time = %10.30f\n", (double)t2 - t1);
}
ubuntu% ruby -e '5.times { puts `./a.out` }'
sysconf(_SC_CLK_TCK) = 100.000000
time = 0.000000000000000000000000000000
time = 15.000000000000000000000000000000
sysconf(_SC_CLK_TCK) = 100.000000
time = 0.000000000000000000000000000000
time = 15.000000000000000000000000000000
sysconf(_SC_CLK_TCK) = 100.000000
time = 0.000000000000000000000000000000
time = 15.000000000000000000000000000000
sysconf(_SC_CLK_TCK) = 100.000000
time = 0.000000000000000000000000000000
time = 15.000000000000000000000000000000
sysconf(_SC_CLK_TCK) = 100.000000
time = 0.000000000000000000000000000000
time = 15.000000000000000000000000000000
まとめ
CPU時間を測る場合、短い時間測定にはgetrusageを使うのが良いと思われる。長いのにはclockを使うのが良いと思われる。ただし実際にはI/O等も含めたプログラム全体の測定するために、gettimeofdayを使う。
[ return ]