Re: [patch 0/3] [Announcement] Performance Counters for Linux

Ingo Molnar
2008-12-05T07:03:59Z

* Ingo Molnar <mingo@elte.hu> wrote:

> This can be done in a very natural way with our abstraction, and the
> "hello.c" example happens to do exactly that:

multiple people pointed out that we have not posted hello.c :-/

Here's a simple standalone example (full working code attached below):

int main(void)
{
unsigned long long count1, count2;
int fd1, fd2, ret;

fd1 = perf_counter_open(PERF_COUNT_INSTRUCTIONS, 0, 0, 0, -1);
assert(fd1 >= 0);
fd2 = perf_counter_open(PERF_COUNT_CACHE_MISSES, 0, 0, 0, -1);
assert(fd1 >= 0);

for (;;) {
ret = read(fd1, &count1, sizeof(count1));
assert(ret == 8);
ret = read(fd2, &count2, sizeof(count2));
assert(ret == 8);

printf("counter1 value: %Ld instructions\n", count1);
printf("counter2 value: %Ld cachemisses\n", count2);
sleep(1);
}
return 0;
}

which gives this output (one readout per second):

titan:~/perf-counter-test> ./simple
counter1 value: 0 instructions
counter2 value: 0 cachemisses
counter1 value: 23 instructions
counter2 value: 0 cachemisses
counter1 value: 2853 instructions
counter2 value: 6 cachemisses
counter1 value: 5736 instructions
counter2 value: 7 cachemisses
counter1 value: 8619 instructions
counter2 value: 8 cachemisses
counter1 value: 11502 instructions
counter2 value: 8 cachemisses
^C

You need our patchset but then the code below will work just fine. No
libraries, no context setup, nothing - just what is more interesting: the
counter and profiling data.

Ingo

----------------->
/*
* Very simple performance counter testcase.
*/
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/uio.h>

#include <linux/unistd.h>

#include <assert.h>
#include <unistd.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>

#ifdef __x86_64__
# define __NR_perf_counter_open 295
#endif

#ifdef __i386__
# define __NR_perf_counter_open 333
#endif

int
perf_counter_open(int hw_event_type,
unsigned int hw_event_period,
unsigned int record_type,
pid_t pid,
int cpu)
{
return syscall(__NR_perf_counter_open, hw_event_type, hw_event_period,
record_type, pid, cpu);
}

enum hw_event_types {
PERF_COUNT_CYCLES,
PERF_COUNT_INSTRUCTIONS,
PERF_COUNT_CACHE_REFERENCES,
PERF_COUNT_CACHE_MISSES,
PERF_COUNT_BRANCH_INSTRUCTIONS,
PERF_COUNT_BRANCH_MISSES,
};

int main(void)
{
unsigned long long count1, count2;
int fd1, fd2, ret;

fd1 = perf_counter_open(PERF_COUNT_INSTRUCTIONS, 0, 0, 0, -1);
assert(fd1 >= 0);
fd2 = perf_counter_open(PERF_COUNT_CACHE_MISSES, 0, 0, 0, -1);
assert(fd1 >= 0);

for (;;) {
ret = read(fd1, &count1, sizeof(count1));
assert(ret == 8);
ret = read(fd2, &count2, sizeof(count2));
assert(ret == 8);

printf("counter1 value: %Ld instructions\n", count1);
printf("counter2 value: %Ld cachemisses\n", count2);
sleep(1);
}
return 0;
}