/* changed perf_examples/self_basic.c from perfmon2 library.
the purpose is to demonstrate how one can count events for
a binary within a c program. */
#include <sys/types.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <locale.h>
#include <sys/ioctl.h>
#include <err.h>
#include <sys/wait.h>
#include <perfmon/pfmlib_perf_event.h>
#define N 30
int
main(int argc, char **argv)
{
struct perf_event_attr attr;
int fd, ret;
uint64_t count = 0, values[3];
pid_t child_pid;
int status;
setlocale(LC_ALL, "");
/*
* Initialize libpfm library (required before we can use it)
*/
ret = pfm_initialize();
if (ret != PFM_SUCCESS)
errx(1, "cannot initialize library: %s", pfm_strerror(ret));
memset(&attr, 0, sizeof(attr));
/*
* 1st argument: event string
* 2nd argument: default privilege level (used if not specified in the event string)
* 3rd argument: the perf_event_attr to initialize
*/
ret = pfm_get_perf_event_encoding("cycles,PM_RUN_CYC", PFM_PLM0|PFM_PLM3, &attr, NULL, NULL);
if (ret != PFM_SUCCESS)
errx(1, "cannot find encoding: %s", pfm_strerror(ret));
/*
* request timing information because event may be multiplexed
* and thus it may not count all the time. The scaling information
* will be used to scale the raw count as if the event had run all
* along
*/
attr.read_format = PERF_FORMAT_TOTAL_TIME_ENABLED|PERF_FORMAT_TOTAL_TIME_RUNNING;
/* do not start immediately after perf_event_open() */
attr.disabled = 1;
if( (child_pid = fork()) == 0) //child
{
printf("child is running, pid is %d\n", getpid());
char *cmd[] = {"ls", "/", "-l", (char *)0};
execv("/bin/ls", cmd);
exit(0);
}else if(child_pid < 0){ //failed
err(1, "Failed to fork");
exit(0);
}else { //parent
printf("Back to parent, child pid is: %d\n", child_pid);
/*
* create the event and attach to self
* Note that it attaches only to the main thread, there is no inheritance
* to threads that may be created subsequently.
*
* if mulithreaded, then getpid() must be replaced by gettid()
*/
fd = perf_event_open(&attr, child_pid, -1, -1, 0);
if (fd < 0)
err(1, "cannot create event");
/*
* start counting now
*/
ret = ioctl(fd, PERF_EVENT_IOC_ENABLE, 0);
if (ret)
err(1, "ioctl(enable) failed");
wait(&status); //wait for the child to exit
/*
* stop counting
*/
ret = ioctl(fd, PERF_EVENT_IOC_DISABLE, 0);
if (ret)
err(1, "ioctl(disable) failed");
/*
* read the count + scaling values
*
* It is not necessary to stop an event to read its value
*/
ret = read(fd, values, sizeof(values));
if (ret != sizeof(values))
err(1, "cannot read results: %s", strerror(errno));
/*
* scale count
*
* values[0] = raw count
* values[1] = TIME_ENABLED
* values[2] = TIME_RUNNING
*/
if (values[2])
count = (uint64_t)((double)values[0] * values[1]/values[2]);
printf("this is a test");
printf("count=%'"PRIu64"\n", count);
printf("count=%'"PRIu64"\n", values[0]);
printf("count=%'"PRIu64"\n", values[1]);
printf("count=%'"PRIu64"\n", values[2]);
printf("count=%'"PRIu64"\n", values[3]);
close(fd);
}
/* free libpfm resources cleanly */
pfm_terminate();
return 0;
}