clock_gettime
函數
clock_gettime
函數可以取得 wall-clock time 或程式的 CPU time,其所傳回的時間是用 timespec
這個結構(struct)所儲存的:
struct timespec { time_t tv_sec; /* seconds */ long tv_nsec; /* nanoseconds */ };
使用 timespec
來儲存時間的話,其精準度最高可達十億分之一秒(nanosecond),若要查詢實際的精確度,可以使用 clock_getres
函數:
#include <time.h> #include <stdio.h> int main() { struct timespec t; clock_getres(CLOCK_MONOTONIC, &t); printf("Resolution: %ld nanosecond\n", t.tv_nsec); return 0; }
gcc -o getres getres.c
./getres
Resolution: 1 nanosecond
clock_getres
的第一個參數是指定時間的類型,常見的類型有:
CLOCK_REALTIME
:系統的實際時間(wall-clock time)。CLOCK_REALTIME_COARSE
:系統的實際時間(wall-clock time),取得速度快,但精確度校低。CLOCK_MONOTONIC
:單調遞增時間(monotonic time),這個時間會非常穩定的持續遞增,不會因為系統時間改變而有變動,適合用於測量程式執行效能。CLOCK_MONOTONIC_COARSE
:與CLOCK_MONOTONIC
類似,取得速度快,但精確度校低。CLOCK_MONOTONIC_RAW
:與CLOCK_MONOTONIC
類似,但是它是從硬體時鐘所讀取出來的值。CLOCK_PROCESS_CPUTIME_ID
:程式行程的 CPU time,這個時間包含所有的執行序所花費的時間。CLOCK_THREAD_CPUTIME_ID
:程式單一執行序所耗費的時間。
#include <stdlib.h> #include <stdio.h> #include <math.h> #include <time.h> // clock_gettime 函數所需之標頭檔 double pi(int n) { srand(5); int count = 0; double x, y; for (int i = 0; i < n; ++i) { x = (double) rand() / RAND_MAX; y = (double) rand() / RAND_MAX; if (x * x + y * y <= 1) ++count; } return (double) count / n * 4; } struct timespec diff(struct timespec start, struct timespec end) { struct timespec temp; if ((end.tv_nsec-start.tv_nsec)<0) { temp.tv_sec = end.tv_sec-start.tv_sec-1; temp.tv_nsec = 1000000000+end.tv_nsec-start.tv_nsec; } else { temp.tv_sec = end.tv_sec-start.tv_sec; temp.tv_nsec = end.tv_nsec-start.tv_nsec; } return temp; } int main() { // 儲存時間用的變數 struct timespec start, end; double time_used; // 計算開始時間 clock_gettime(CLOCK_MONOTONIC, &start); // 主要計算 double result = pi(1e8); // 計算結束時間 clock_gettime(CLOCK_MONOTONIC, &end); // 計算實際花費時間 struct timespec temp = diff(start, end); time_used = temp.tv_sec + (double) temp.tv_nsec / 1000000000.0; printf("PI = %f\n", result); printf("Time = %f\n", time_used); }
用 gcc
編譯:
gcc -o pi pi.c
執行:
./pi
PI = 3.142172 Time = 2.145160
在 CPU 滿載(使用 stress
)的狀況下,測試的結果:
./pi
PI = 3.142172 Time = 3.773047
getrusage
函數
getrusage
函數可以取得程式所使用的各種系統資源統計數據,包含 CPU、記憶體、I/O 等,所以我們也可以利用這個函數來測量程式的 CPU time:
#include <stdlib.h> #include <stdio.h> #include <math.h> #include <time.h> #include <stdint.h> #include <sys/time.h> #include <sys/resource.h> double pi(int n) { srand(5); int count = 0; double x, y; for (int i = 0; i < n; ++i) { x = (double) rand() / RAND_MAX; y = (double) rand() / RAND_MAX; if (x * x + y * y <= 1) ++count; } return (double) count / n * 4; } int main(int argc, char *argv[]) { struct rusage ru; struct timeval utime; struct timeval stime; // 主要計算 double result = pi(1e8); // 取得程式的 user time 與 system time getrusage(RUSAGE_SELF, &ru); printf("PI = %f\n", result); utime = ru.ru_utime; stime = ru.ru_stime; double utime_used = utime.tv_sec + (double) utime.tv_usec / 1000000.0; double stime_used = stime.tv_sec + (double) stime.tv_usec / 1000000.0; printf("User Time = %f\n", utime_used); printf("System Time = %f\n", stime_used); return 0; }
getrusage
函數可以分別取得程式的 user CPU time 與 system CPU time,有類似 time
指令的效果。
用 gcc
編譯:
gcc -o pi pi.c
執行:
./pi
PI = 3.142172 User Time = 2.258956 System Time = 0.000999
在 CPU 滿載(使用 stress
)的狀況下,測試的結果:
./pi
PI = 3.142172 User Time = 3.670714 System Time = 0.001000
gettimeofday
函數
gettimeofday
函數可以取得很精確的 wall-clock time。
#include <stdlib.h> #include <stdio.h> #include <math.h> #include <sys/time.h> double pi(int n) { srand(5); int count = 0; double x, y; for (int i = 0; i < n; ++i) { x = (double) rand() / RAND_MAX; y = (double) rand() / RAND_MAX; if (x * x + y * y <= 1) ++count; } return (double) count / n * 4; } int main(int argc, char *argv[]) { struct timeval start, end, diff; // 開始計算時間 gettimeofday(&start, NULL); // 主要計算 double result = pi(1e8); // 結束計算時間 gettimeofday(&end, NULL); // 計算實際花費時間 timersub(&end, &start, &diff); double time_used = diff.tv_sec + (double) diff.tv_usec / 1000000.0; printf("PI = %f\n", result); printf("Time = %f\n", time_used); return 0; }
用 gcc
編譯:
gcc -o pi pi.c
執行:
./pi
PI = 3.142172 Time = 2.258592
在 CPU 滿載(使用 stress
)的狀況下,測試的結果:
./pi
PI = 3.142172 Time = 3.760840
後記
我原本想要找一個比較穩定的測試方式,但是透過 stress
的測試結果來看,幾乎每一種方式都會受到系統負載的影響,若未來有看到比較好的方式,再補上來。
參考資料:StackOverflow、charles620016、Guy Rutenberg、程式扎記、Edison.X. Blog、CodingUnit
繼續閱讀: 12