C言語で正確にミリ秒マイクロ秒単位まで計測する方法
C標準ライブラリには多数の時間に関するライブラリがある.
注目すべきはtime.h
とsys/time.h
である.よくあるのはtime.h
のstruct time_t
に1970年1月1日からの秒数を格納し,それを年月日時分秒をメンバ変数として持つ構造体struct tm
に変換して得る方法である.
しかし,sys/time.h
ではさらに上位の(?)構造体timevalが定義されており,メンバ変数としてtime_t型のtv_sec
とマイクロ秒単位で時刻を格納するsuseconds_t型のtv_usec
が定義されている:
/* <time.h>および<sys/time.h>から構造体の定義を抜粋 */ // timevalは基準年からの秒数とマイクロ秒を格納 struct timeval { time_t tv_sec; /* 秒 */ suseconds_t tv_usec; /* マイクロ秒 */ }; // time_t型は基準年からの秒数 // time_tのままでは使いにくい.time_tはtm構造体に相互に変換できる struct tm { int tm_sec; /* 秒 (0-60) */ int tm_min; /* 分 (0-59) */ int tm_hour; /* 時間 (0-23) */ int tm_mday; /* 月内の日付 (1-31) */ int tm_mon; /* 月 (0-11) */ int tm_year; /* 年 - 1900 */ int tm_wday; /* 曜日 (0-6, 日曜 = 0) */ int tm_yday; /* 年内通算日 (0-365, 1 月 1 日 = 0) */ int tm_isdst; /* 夏時間 */ };
これらを用いて現在日時時刻を取得&表示する例
#include <stdio.h> #include <time.h> #include <sys/time.h> // time.hとsys/time.hは別物なので注意! int main() { /* まず,日時・時刻情報を格納するための変数を宣言 */ struct timeval myTime; // time_t構造体を定義.1970年1月1日からの秒数を格納するもの struct tm *time_st; // tm構造体を定義.年月日時分秒をメンバ変数に持つ構造体 const char weekName[7][4] = { // 曜日は数字としてしか得られないので,文字列として用意 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; /* 時刻取得 */ gettimeofday(&myTime, NULL); // 現在時刻を取得してmyTimeに格納.通常のtime_t構造体とsuseconds_tに値が代入される time_st = localtime(&myTime.tv_sec); // time_t構造体を現地時間でのtm構造体に変換 printf("Date : %d/%02d/%02d(%s) %02d:%02d:%02d.%06d\n", // 現在時刻 time_st->tm_year+1900, // 年 time_st->tm_mon+1, // 月 time_st->tm_mday, // 日 weekName[time_st->tm_wday],// 曜日 time_st->tm_hour, // 時 time_st->tm_min, // 分 time_st->tm_sec, // 秒 myTime.tv_usec // マイクロ秒 ); }
これを実行すると
Date : 2015/02/03(Tue) 00:27:10.386185
といった感じで表示される. ちなみに,マイクロ秒単位まで時刻を取得する方法として,
#include <time.h> (略) clock_t microSec; microSec = clock(); printf("%d\n", microSec/CLOCKS_PER_SEC);
などとする方法が見受けられるが,これは間違いである.これはCPU時間なのでCPU稼働率が100%なら正しい時刻を示すが,そうでない場合は時計の時間とは異なる.特にopenmpなどを用いて並列化すると(CPU稼働率が数百パーセントなどとなるので)意味がない.
逆にこれを利用して、簡易的に該当プログラムのCPU占有率を調べることもできる:
#include <stdio.h> #include <stdlib.h> #include <time.h> #include <sys/time.h> int main() { struct timeval startTime, endTime; // 構造体宣言 clock_t startClock, endClock; // clock_t型変数宣言 gettimeofday(&startTime, NULL); // 開始時刻取得 startClock = clock(); // 開始時刻のcpu時間取得 // (何らかの処理) gettimeofday(&endTime, NULL); // 開始時刻取得 endClock = clock(); // 開始時刻のcpu時間取得 time_t diffsec = difftime(endTime.tv_sec, startTime.tv_sec); // 秒数の差分を計算 suseconds_t diffsub = endTime.tv_usec - startTime.tv_usec; // マイクロ秒部分の差分を計算 //以下の処理は不要(15/10/28) //if (diffsub < 0) { // マイクロ秒が負になったとき // diffsec -= 1; // 秒部分を繰り下げ // diffsub = 1000000 + diffsub; // 1秒との差 //} double realsec = diffsec+diffsub*1e-6; // 実時間を計算 double cpusec = (endClock - startClock)/(double)CLOCKS_PER_SEC; // cpu時間を計算 double percent = 100.0*cpusec/realsec; // 使用率を100分率で計算 printf("CPU使用率%f %%\n", percent); // 表示 return 0; }