調べる機会があったので、ちょっと詳しくまとめました。
プロセスのCPU時間の取得
clock_gettime (CLOCK_PROCESS_CPUTIME_ID)
使用例
struct timespec ts;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts)
getrusage (RUSAGE_SELF)
呼び出したプロセスの資源使用量、 そのプロセス内の全スレッドが使用している資源の合計を返す。
使用例
struct rusage usg;
getrusage(RUSAGE_THREAD, &usg);
スレッドのCPU時間の取得
clock_gettime (CLOCK_THREAD_CPUTIME_ID)
使用例
struct timespec ts;
clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts)
上記の取得の場合は、各スレッド内で自身のCPU時間のみしか取得できない。
スレッド外部から所得する場合は以下の pthread_getcpuclockid
と組み合わせて取得する。
pthread_getcpuclockid + clock_gettime
使用例
// スレッド作成
pthread_t thread;
pthread_create(&thread, NULL, thread_start, NULL);
clockid_t cid;
pthread_getcpuclockid(pthread_self(), &cid); // メインスレッドのclockidを取得する場合
pthread_getcpuclockid(thread, &cid); // 特定スレッドのclockidを取得する場合
struct timespec ts;
clock_gettime(cid, &ts)
getrusage (RUSAGE_THREAD)
呼び出したスレッドに関する資源使用量の統計を返す
使用例
struct rusage usg;
getrusage(RUSAGE_THREAD, &usg);
使用例
実装例です。下記のMan Pageのサンプルコードを若干修正したものになります。
Man page of PTHREAD_GETCPUCLOCKID
アトミック変数が使いたかったので(stdatomic.h)、C11でビルドする必要があります。
実装例
// to use RUSAGE_THREAD
# define _GNU_SOURCE
# include <sys/resource.h>
# include <time.h>
# include <stdio.h>
# include <stdlib.h>
# include <unistd.h>
# include <pthread.h>
# include <string.h>
# include <errno.h>
// C11 only
# include <stdatomic.h>
# define handle_error(msg) \
do { perror(msg); exit(EXIT_FAILURE); } while (0)
# define handle_error_en(en, msg) \
do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)
_Atomic int thread_end_flag = ATOMIC_VAR_INIT(0);
static void
pclock(char *msg, clockid_t cid)
{
struct timespec ts;
printf("%s", msg);
if (clock_gettime(cid, &ts) == -1)
handle_error("clock_gettime");
printf("%4ld.%03ld\n", ts.tv_sec, ts.tv_nsec / 1000000);
}
static void *
thread_start(void *arg)
{
printf("Subthread starting infinite loop\n");
for (;;)
{
if (thread_end_flag) break;
continue;
}
pclock("SubThread CPU time: ", CLOCK_PROCESS_CPUTIME_ID);
// rusage
int s;
struct rusage usg;
s = getrusage(RUSAGE_THREAD, &usg);
if (s != 0)
handle_error_en(s, "getrusage(thread)");
printf("getrusage(thread) : user ");
printf("%4ld.%03ld, ", usg.ru_utime.tv_sec, usg.ru_utime.tv_usec / 1000);
printf("system ");
printf("%4ld.%03ld\n", usg.ru_stime.tv_sec, usg.ru_stime.tv_usec / 1000);
}
int
main(int argc, char *argv[])
{
pthread_t thread;
clockid_t cid;
int j, s;
s = pthread_create(&thread, NULL, thread_start, NULL);
if (s != 0)
handle_error_en(s, "pthread_create");
printf("Main thread sleeping\n");
sleep(1);
printf("Main thread consuming some CPU time...\n");
for (j = 0; j < 2000000; j++)
getppid();
pclock("Process total CPU time: ", CLOCK_PROCESS_CPUTIME_ID);
s = pthread_getcpuclockid(pthread_self(), &cid);
if (s != 0)
handle_error_en(s, "pthread_getcpuclockid");
pclock("Main thread CPU time: ", cid);
/* The preceding 4 lines of code could have been replaced by:
pclock("Main thread CPU time: ", CLOCK_THREAD_CPUTIME_ID); */
s = pthread_getcpuclockid(thread, &cid);
if (s != 0)
handle_error_en(s, "pthread_getcpuclockid");
pclock("Subthread CPU time: 1 ", cid);
// rusage
struct rusage usg;
s = getrusage(RUSAGE_SELF, &usg);
if (s != 0)
handle_error_en(s, "getrusage(process)");
printf("getrusage(process) : user ");
printf("%4ld.%03ld, ", usg.ru_utime.tv_sec, usg.ru_utime.tv_usec / 1000);
printf("system ");
printf("%4ld.%03ld\n", usg.ru_stime.tv_sec, usg.ru_stime.tv_usec / 1000);
thread_end_flag = 1;
pthread_join(thread, NULL);
}
実行
koara@ubuntu:~/work$ gcc -pthread -std=c11 test.c
koara@ubuntu:~/work$ ./a.out
Main thread sleeping
Subthread starting infinite loop
Main thread consuming some CPU time...
Process total CPU time: 1.143
Main thread CPU time: 0.078
Subthread CPU time: 1 1.064
getrusage(process) : user 1.076, system 0.064
SubThread CPU time: 1.143
getrusage(thread) : user 1.060, system 0.004
※1000で割ってたりしてるのは、Man Pageのサンプルに合わせたからです。桁落としをしてるっぽいです。
参考
Man page of CLOCK_GETRES
Man page of PTHREAD_GETCPUCLOCKID
Man page of GETRUSAGE
アトミック - C言語入門
atomic変数間のatomicなコピー - yohhoyの日記