#include #include #include #include #include #include #include #include #include #include "perf_counter.h" #ifdef __x86_64__ # define __NR_perf_counter_open 295 #endif #ifdef __i386__ # define __NR_perf_counter_open 333 #endif #ifdef __powerpc__ # define __NR_perf_counter_open 319 #endif #define PR_TASK_PERF_COUNTERS_DISABLE 31 #define PR_TASK_PERF_COUNTERS_ENABLE 32 int sys_perf_counter_open(struct perf_counter_hw_event *hw_event, pid_t pid, int cpu, int group_fd, unsigned long flags) { return syscall(__NR_perf_counter_open, hw_event, pid, cpu, group_fd, flags); } #define MAX_CTRS 50 #define LOOPS 1000000000 void do_work(void) { int i; for (i = 0; i < LOOPS; ++i) asm volatile("" : : "g" (i)); } main(int ac, char **av) { int tsk0; int hwfd[MAX_CTRS], tskfd[MAX_CTRS]; struct perf_counter_hw_event tsk_event; struct perf_counter_hw_event hw_event; unsigned long long vt0, vt[MAX_CTRS], vh[MAX_CTRS], vtsum, vhsum; int i, n, nhw; int verbose = 0; double ratio; nhw = 8; while ((i = getopt(ac, av, "c:v")) != -1) { switch (i) { case 'c': n = atoi(optarg); break; case 'v': verbose = 1; break; case '?': fprintf(stderr, "Usage: %s [-c #hwctrs] [-v]\n", av[0]); exit(1); } } if (nhw < 0 || nhw > MAX_CTRS - 4) { fprintf(stderr, "invalid number of hw counters specified: %d\n", nhw); exit(1); } n = nhw + 4; memset(&tsk_event, 0, sizeof(tsk_event)); tsk_event.type = PERF_COUNT_TASK_CLOCK; tsk_event.disabled = 1; memset(&hw_event, 0, sizeof(hw_event)); hw_event.disabled = 1; hw_event.type = PERF_COUNT_INSTRUCTIONS; tsk0 = sys_perf_counter_open(&tsk_event, 0, -1, -1, 0); if (tsk0 == -1) { perror("perf_counter_open"); exit(1); } tsk_event.disabled = 0; for (i = 0; i < n; ++i) { hwfd[i] = sys_perf_counter_open(&hw_event, 0, -1, -1, 0); tskfd[i] = sys_perf_counter_open(&tsk_event, 0, -1, hwfd[i], 0); if (tskfd[i] == -1 || hwfd[i] == -1) { perror("perf_counter_open"); exit(1); } } prctl(PR_TASK_PERF_COUNTERS_ENABLE); do_work(); prctl(PR_TASK_PERF_COUNTERS_DISABLE); if (read(tsk0, &vt0, sizeof(vt0)) != sizeof(vt0)) { fprintf(stderr, "error reading task clock counter\n"); exit(1); } vtsum = vhsum = 0; for (i = 0; i < n; ++i) { if (read(tskfd[i], &vt[i], sizeof(vt[i])) != sizeof(vt[i]) || read(hwfd[i], &vh[i], sizeof(vh[i])) != sizeof(vh[i])) { fprintf(stderr, "error reading counter(s)\n"); exit(1); } vtsum += vt[i]; vhsum += vh[i]; } printf("overall task clock: %lld\n", vt0); printf("hw sum: %lld, task clock sum: %lld\n", vhsum, vtsum); if (verbose) { printf("hw counters:"); for (i = 0; i < n; ++i) printf(" %lld", vh[i]); printf("\ntask clock counters:"); for (i = 0; i < n; ++i) printf(" %lld", vt[i]); printf("\n"); } ratio = (double)vtsum / vt0; printf("ratio: %.2f\n", ratio); if (ratio > nhw + 0.0001) { fprintf(stderr, "test failed\n"); exit(1); } fprintf(stderr, "test passed\n"); exit(0); }