This is the mail archive of the systemtap@sourceware.org mailing list for the systemtap project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

incorrect perf counters


Hi,

I'm trying to collect perf counters using systemtap. I followed
systemtap/EXAMPLES/profiling/perf.stp to create a script to monitor a
user process, enable counters on function entry, and spew out counters
on function return. Please find the script (perf.stp) attached.

I use the stap script described above to monitor function func()'s
entry and exit.

void func(void)
{
    printf("Measuring instruction count for this printf\n");
}

Just to verify systemtap reported counters, I created a program
(test.c) that uses perf_event_open() syscall to monitor func()'s
entry/exit and spew out counters. Please find it attached as well.

However, the counters reported by perf.stp are very different from
what is reported by test.c. For example, instruction count reported by
test.c and perf.stp are 593 and 10610-10690.

This is how I launch perf.stp to monitor func() in test.c:

sudo /usr/local/bin/stap -s1 perf.stp test func

Why such a difference? Am I missing something?

Thanks,
Riya

Attachment: perf.stp
Description: Binary data

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include <linux/perf_event.h>
#include <asm/unistd.h>
#include <stdint.h>
#include <errno.h>

struct perf_event {
	const char *name;
	uint64_t type;
	uint64_t config;
};

#define NUM_REQ_HW_CNTRS 6
static const struct perf_event events[] =
{
	{ "Cycles",					PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES },
	{ "Instrs",					PERF_TYPE_HARDWARE, PERF_COUNT_HW_INSTRUCTIONS },
	{ "Cache-Refs",				PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_REFERENCES },
	{ "Cache-Misses",			PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_MISSES },
	{ "Branches",				PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_INSTRUCTIONS },
};

static long perf_event_open(struct perf_event_attr *hw_event, pid_t pid,
               int cpu, int group_fd, unsigned long flags)
{
   int ret;

   ret = syscall(__NR_perf_event_open, hw_event, pid, cpu,
                  group_fd, flags);
   return ret;
}

static int open_event(uint64_t config, uint64_t type, int group_leader)
{
  static struct perf_event_attr pe;
  pe.size = sizeof(struct perf_event_attr);
  pe.type = type;
  pe.config = config;
  if (group_leader == -1)
    pe.disabled = 1;
  pe.mmap = 1;
  pe.comm = 1;

  pe.read_format = PERF_FORMAT_GROUP;
  pe.exclude_kernel = 1;
  pe.exclude_hv = 1;

  return perf_event_open(&pe, 0, -1, group_leader, 0);
}

void perf_enable_perf(int fd)
{
	if (fd > 0) {
		ioctl(fd, PERF_EVENT_IOC_RESET, PERF_IOC_FLAG_GROUP);
		ioctl(fd, PERF_EVENT_IOC_ENABLE, PERF_IOC_FLAG_GROUP);
	} else
		fprintf(stderr, "enable failed fd: %d", fd);
}

void perf_disable_perf(int fd)
{
	if (fd > 0) {
		ioctl(fd, PERF_EVENT_IOC_DISABLE, PERF_IOC_FLAG_GROUP);

		int num_events = sizeof(events) / sizeof(events[0]);
		uint64_t buf[num_events + 1];

		memset(buf, 0, ((num_events + 1) * sizeof(uint64_t)));
		if (read(fd, &buf, ((num_events + 1) * sizeof(uint64_t))) < 0) {
			fprintf(stderr, "fd: %d read failed: %s", fd, strerror(errno));
		} else {
			//fprintf(stdout, "fd: %d nr_events %ld\n", fd, buf[0]);
			int idx;
			for (idx = 0; idx < buf[0]; idx++)
				fprintf(stdout, "%s: %ld\n", events[idx].name, buf[idx + 1]);
		}
	 } else
			fprintf(stderr, "disable failed fd: %d", fd);
}

int perf_init_perf(void)
{
	int idx, fd, group_fd = -1;
	int num_events = sizeof(events) / sizeof(events[0]);

	for (idx = 0; idx < num_events; idx++) {

		fd = open_event(events[idx].config, events[idx].type, group_fd);
		if (fd == -1) {
			fprintf(stderr, "Error opening event %s : %s\n",
					events[idx].name, strerror(errno));
			return -1;
		} else {
			//fprintf(stdout, "event %d open fd %d", idx, fd);
		}

		if (group_fd == -1)
			group_fd = fd;
	}

	return group_fd;
}

void perf_exit_perf(int fd)
{
	if (fd > 0)
		close(fd);
}

void func(void)
{
   	printf("Measuring instruction count for this printf\n");
}

int main(void)
{
#if DISABLE_PERF
	while (1) {
		func();
		sleep(5);
	}
#else
	int fd = perf_init_perf();
	if (fd < 0)
		return -1;

	while (1) {
		perf_enable_perf(fd);
		func();
		perf_disable_perf(fd);
		sleep(5);
	}

	perf_exit_perf(fd);
#endif
	return 0;
}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]