読者です 読者をやめる 読者になる 読者になる

clcok_gettime(2)で実時間とかcpu時間を計る

linux

Linuxclock_gettime(2)を見ると実時間、プロセスのcpu時間、スレッド毎のcpu時間を計測できるらしいので使ってみる。includeするのはtime.h。

#include <unistd.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <assert.h>

static inline double 
timespec2msec(const struct timespec *st)
{
	return (double) st->tv_sec + (double) st->tv_nsec * 1e-9;
}

static void
test_common(const char *name, clockid_t clk_id)
{
	struct timespec start, end;

	clock_gettime(clk_id, &start);

	sleep(1);

	clock_gettime(clk_id, &end);

	printf("%s: %f msec\n", name, timespec2msec(&end) - timespec2msec(&start));
}

static void *
test_func(void *data)
{
	test_common(__FUNCTION__, CLOCK_THREAD_CPUTIME_ID);
	return NULL;
}

#define NUM_TEST_THREADS 8
static void
test_clock_thread_cputime_id(void)
{
	struct timespec start, end;

	pthread_t ths[NUM_TEST_THREADS];
	int i, ret;

	printf("Test CLOCK_THREAD_CPUTIME_ID\n");
	clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start);

	for (i = 0; i < NUM_TEST_THREADS; i++) {
		ret = pthread_create(&ths[i], NULL, test_func, NULL);
		assert(ret == 0);
	}

	for (i = 0; i < NUM_TEST_THREADS; i++)
		pthread_join(ths[i], NULL);

	clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end);

	printf("%s: %f msec\n", __FUNCTION__, timespec2msec(&end) - timespec2msec(&start));
}

static void
test_clock_process_cputime_id(void)
{
	printf("Test CLOCK_PROCESS_CPUTIME_ID\n");
	test_common(__FUNCTION__, CLOCK_PROCESS_CPUTIME_ID);
}

static void
test_clock_realtime(void)
{
	printf("Test CLOCK_REALTIME\n");
	test_common(__FUNCTION__, CLOCK_REALTIME);
}

static void 
usage(char *name)
{
	fprintf(stderr, "%s option\n", name);
	fprintf(stderr, "0: test CLOCK_REALTIME\n");
	fprintf(stderr, "1: test CLOCK_PROCESS_CPUTIME_ID\n");
	fprintf(stderr, "2: test CLOCK_THREAD_CPUTIME_ID\n");
	exit(-1);
}

int
main(int argc, char **argv)
{
	int testcase = 0;

	if (argc > 1) {
		testcase = atoi(argv[1]);
	};

	switch (testcase) {
	case 0:
		test_clock_realtime();
		break;
	case 1:
		test_clock_process_cputime_id();
		break;
	case 2:
		test_clock_thread_cputime_id();
		break;
	default:
		usage(argv[0]);
	}

	return 0;
}

CLOCK_REALTIMEで実時間計測。1秒のスリープを挟んでいるので大体こんなもんですかね。

masami@saga:~$ ./a.out 0
Test CLOCK_REALTIME
test_clock_realtime: 1.000060 msec

プロセスのcpu時間計測。

masami@saga:~$ ./a.out 1
Test CLOCK_PROCESS_CPUTIME_ID
test_clock_process_cputime_id: 0.000017 msec

スレッド毎のcpu時間とプロセスのcpu時間計測。

masami@saga:~$ ./a.out 2
Test CLOCK_THREAD_CPUTIME_ID
test_func: 0.000018 msec
test_func: 0.000023 msec
test_func: 0.000089 msec
test_func: 0.000037 msec
test_func: 0.000017 msec
test_func: 0.000006 msec
test_func: 0.000004 msec
test_func: 0.000003 msec
test_clock_thread_cputime_id: 0.001067 msec

と、こんな感じですがclk_idはlinuxに特有ものも多いです。
clock_gettime(2)はBSDにもありますが、manを見るとこちらもBSD固有ものが結構あります。なので両方の環境で使いたい場合はCLOCK_REALTIMEのように両方にあるものを使うかifdef等で切り替えが必要ですね。

プロのための Linuxシステム・10年効く技術 (Software Design plus)

プロのための Linuxシステム・10年効く技術 (Software Design plus)