Blame src/libpfm4/perf_examples/task.c

Packit 577717
/*
Packit 577717
 * task_inherit.c - example of a task counting event in a tree of child processes
Packit 577717
 *
Packit 577717
 * Copyright (c) 2009 Google, Inc
Packit 577717
 * Contributed by Stephane Eranian <eranian@gmail.com>
Packit 577717
 *
Packit 577717
 * Permission is hereby granted, free of charge, to any person obtaining a copy
Packit 577717
 * of this software and associated documentation files (the "Software"), to deal
Packit 577717
 * in the Software without restriction, including without limitation the rights
Packit 577717
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
Packit 577717
 * of the Software, and to permit persons to whom the Software is furnished to do so,
Packit 577717
 * subject to the following conditions:
Packit 577717
 *
Packit 577717
 * The above copyright notice and this permission notice shall be included in all
Packit 577717
 * copies or substantial portions of the Software.
Packit 577717
 *
Packit 577717
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
Packit 577717
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
Packit 577717
 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
Packit 577717
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
Packit 577717
 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
Packit 577717
 * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Packit 577717
 */
Packit 577717
#include <sys/types.h>
Packit 577717
#include <inttypes.h>
Packit 577717
#include <stdio.h>
Packit 577717
#include <stdlib.h>
Packit 577717
#include <unistd.h>
Packit 577717
#include <string.h>
Packit 577717
#include <stdarg.h>
Packit 577717
#include <signal.h>
Packit 577717
#include <sys/wait.h>
Packit 577717
#include <locale.h>
Packit 577717
#include <err.h>
Packit 577717
Packit 577717
#include "perf_util.h"
Packit 577717
Packit 577717
#define MAX_GROUPS 256
Packit 577717
Packit 577717
typedef struct {
Packit 577717
	const char *events[MAX_GROUPS];
Packit 577717
	int num_groups;
Packit 577717
	int format_group;
Packit 577717
	int inherit;
Packit 577717
	int print;
Packit 577717
	int pin;
Packit 577717
	pid_t pid;
Packit 577717
} options_t;
Packit 577717
Packit 577717
static options_t options;
Packit 577717
static volatile int quit;
Packit 577717
Packit 577717
int
Packit 577717
child(char **arg)
Packit 577717
{
Packit 577717
	/*
Packit 577717
	 * execute the requested command
Packit 577717
	 */
Packit 577717
	execvp(arg[0], arg);
Packit 577717
	errx(1, "cannot exec: %s\n", arg[0]);
Packit 577717
	/* not reached */
Packit 577717
}
Packit 577717
Packit 577717
static void
Packit 577717
read_groups(perf_event_desc_t *fds, int num)
Packit 577717
{
Packit 577717
	uint64_t *values = NULL;
Packit 577717
	size_t new_sz, sz = 0;
Packit 577717
	int i, evt;
Packit 577717
	ssize_t ret;
Packit 577717
Packit 577717
	/*
Packit 577717
	 * 	{ u64		nr;
Packit 577717
	 * 	  { u64		time_enabled; } && PERF_FORMAT_ENABLED
Packit 577717
	 * 	  { u64		time_running; } && PERF_FORMAT_RUNNING
Packit 577717
	 * 	  { u64		value;
Packit 577717
	 * 	    { u64	id;           } && PERF_FORMAT_ID
Packit 577717
	 * 	  }		cntr[nr];
Packit 577717
	 * 	} && PERF_FORMAT_GROUP
Packit 577717
	 *
Packit 577717
	 * we do not use FORMAT_ID in this program
Packit 577717
	 */
Packit 577717
Packit 577717
	for (evt = 0; evt < num; ) {
Packit 577717
		int num_evts_to_read;
Packit 577717
Packit 577717
		if (options.format_group) {
Packit 577717
			num_evts_to_read = perf_get_group_nevents(fds, num, evt);
Packit 577717
			new_sz = sizeof(uint64_t) * (3 + num_evts_to_read);
Packit 577717
		} else {
Packit 577717
			num_evts_to_read = 1;
Packit 577717
			new_sz = sizeof(uint64_t) * 3;
Packit 577717
		}
Packit 577717
Packit 577717
		if (new_sz > sz) {
Packit 577717
			sz = new_sz;
Packit 577717
			values = realloc(values, sz);
Packit 577717
		}
Packit 577717
Packit 577717
		if (!values)
Packit 577717
			err(1, "cannot allocate memory for values\n");
Packit 577717
Packit 577717
		ret = read(fds[evt].fd, values, new_sz);
Packit 577717
		if (ret != (ssize_t)new_sz) { /* unsigned */
Packit 577717
			if (ret == -1)
Packit 577717
				err(1, "cannot read values event %s", fds[evt].name);
Packit 577717
Packit 577717
			/* likely pinned and could not be loaded */
Packit 577717
			warnx("could not read event %d, tried to read %zu bytes, but got %zd",
Packit 577717
				evt, new_sz, ret);
Packit 577717
		}
Packit 577717
Packit 577717
		/*
Packit 577717
		 * propagate to save area
Packit 577717
		 */
Packit 577717
		for (i = evt; i < (evt + num_evts_to_read); i++) {
Packit 577717
			if (options.format_group)
Packit 577717
				values[0] = values[3 + (i - evt)];
Packit 577717
			/*
Packit 577717
			 * scaling because we may be sharing the PMU and
Packit 577717
			 * thus may be multiplexed
Packit 577717
			 */
Packit 577717
			fds[i].values[0] = values[0];
Packit 577717
			fds[i].values[1] = values[1];
Packit 577717
			fds[i].values[2] = values[2];
Packit 577717
		}
Packit 577717
		evt += num_evts_to_read;
Packit 577717
	}
Packit 577717
	if (values)
Packit 577717
		free(values);
Packit 577717
}
Packit 577717
Packit 577717
static void
Packit 577717
print_counts(perf_event_desc_t *fds, int num)
Packit 577717
{
Packit 577717
	double ratio;
Packit 577717
	uint64_t val, delta;
Packit 577717
	int i;
Packit 577717
Packit 577717
	read_groups(fds, num);
Packit 577717
Packit 577717
	for(i=0; i < num; i++) {
Packit 577717
Packit 577717
		val   = perf_scale(fds[i].values);
Packit 577717
		delta = perf_scale_delta(fds[i].values, fds[i].prev_values);
Packit 577717
		ratio = perf_scale_ratio(fds[i].values);
Packit 577717
Packit 577717
		/* separate groups */
Packit 577717
		if (perf_is_group_leader(fds, i))
Packit 577717
			putchar('\n');
Packit 577717
Packit 577717
		if (options.print)
Packit 577717
			printf("%'20"PRIu64" %'20"PRIu64" %s (%.2f%% scaling, ena=%'"PRIu64", run=%'"PRIu64")\n",
Packit 577717
				val,
Packit 577717
				delta,
Packit 577717
				fds[i].name,
Packit 577717
				(1.0-ratio)*100.0,
Packit 577717
				fds[i].values[1],
Packit 577717
				fds[i].values[2]);
Packit 577717
		else
Packit 577717
			printf("%'20"PRIu64" %s (%.2f%% scaling, ena=%'"PRIu64", run=%'"PRIu64")\n",
Packit 577717
				val,
Packit 577717
				fds[i].name,
Packit 577717
				(1.0-ratio)*100.0,
Packit 577717
				fds[i].values[1],
Packit 577717
				fds[i].values[2]);
Packit 577717
Packit 577717
		fds[i].prev_values[0] = fds[i].values[0];
Packit 577717
		fds[i].prev_values[1] = fds[i].values[1];
Packit 577717
		fds[i].prev_values[2] = fds[i].values[2];
Packit 577717
	}
Packit 577717
}
Packit 577717
Packit 577717
static void sig_handler(int n)
Packit 577717
{
Packit 577717
	quit = 1;
Packit 577717
}
Packit 577717
Packit 577717
int
Packit 577717
parent(char **arg)
Packit 577717
{
Packit 577717
	perf_event_desc_t *fds = NULL;
Packit 577717
	int status, ret, i, num_fds = 0, grp, group_fd;
Packit 577717
	int ready[2], go[2];
Packit 577717
	char buf;
Packit 577717
	pid_t pid;
Packit 577717
Packit 577717
	go[0] = go[1] = -1;
Packit 577717
Packit 577717
	if (pfm_initialize() != PFM_SUCCESS)
Packit 577717
		errx(1, "libpfm initialization failed");
Packit 577717
Packit 577717
	for (grp = 0; grp < options.num_groups; grp++) {
Packit 577717
		int ret;
Packit 577717
		ret = perf_setup_list_events(options.events[grp], &fds, &num_fds);
Packit 577717
		if (ret || !num_fds)
Packit 577717
			exit(1);
Packit 577717
	}
Packit 577717
Packit 577717
	pid = options.pid;
Packit 577717
	if (!pid) {
Packit 577717
		ret = pipe(ready);
Packit 577717
		if (ret)
Packit 577717
			err(1, "cannot create pipe ready");
Packit 577717
Packit 577717
		ret = pipe(go);
Packit 577717
		if (ret)
Packit 577717
			err(1, "cannot create pipe go");
Packit 577717
Packit 577717
Packit 577717
		/*
Packit 577717
		 * Create the child task
Packit 577717
		 */
Packit 577717
		if ((pid=fork()) == -1)
Packit 577717
			err(1, "Cannot fork process");
Packit 577717
Packit 577717
		/*
Packit 577717
		 * and launch the child code
Packit 577717
		 *
Packit 577717
		 * The pipe is used to avoid a race condition
Packit 577717
		 * between for() and exec(). We need the pid
Packit 577717
		 * of the new tak but we want to start measuring
Packit 577717
		 * at the first user level instruction. Thus we
Packit 577717
		 * need to prevent exec until we have attached
Packit 577717
		 * the events.
Packit 577717
		 */
Packit 577717
		if (pid == 0) {
Packit 577717
			close(ready[0]);
Packit 577717
			close(go[1]);
Packit 577717
Packit 577717
			/*
Packit 577717
			 * let the parent know we exist
Packit 577717
			 */
Packit 577717
			close(ready[1]);
Packit 577717
			if (read(go[0], &buf, 1) == -1)
Packit 577717
				err(1, "unable to read go_pipe");
Packit 577717
Packit 577717
Packit 577717
			exit(child(arg));
Packit 577717
		}
Packit 577717
Packit 577717
		close(ready[1]);
Packit 577717
		close(go[0]);
Packit 577717
Packit 577717
		if (read(ready[0], &buf, 1) == -1)
Packit 577717
			err(1, "unable to read child_ready_pipe");
Packit 577717
Packit 577717
		close(ready[0]);
Packit 577717
	}
Packit 577717
Packit 577717
	for(i=0; i < num_fds; i++) {
Packit 577717
		int is_group_leader; /* boolean */
Packit 577717
Packit 577717
		is_group_leader = perf_is_group_leader(fds, i);
Packit 577717
		if (is_group_leader) {
Packit 577717
			/* this is the group leader */
Packit 577717
			group_fd = -1;
Packit 577717
		} else {
Packit 577717
			group_fd = fds[fds[i].group_leader].fd;
Packit 577717
		}
Packit 577717
Packit 577717
		/*
Packit 577717
		 * create leader disabled with enable_on-exec
Packit 577717
		 */
Packit 577717
		if (!options.pid) {
Packit 577717
			fds[i].hw.disabled = is_group_leader;
Packit 577717
			fds[i].hw.enable_on_exec = is_group_leader;
Packit 577717
		}
Packit 577717
Packit 577717
		fds[i].hw.read_format = PERF_FORMAT_SCALE;
Packit 577717
		/* request timing information necessary for scaling counts */
Packit 577717
		if (is_group_leader && options.format_group)
Packit 577717
			fds[i].hw.read_format |= PERF_FORMAT_GROUP;
Packit 577717
Packit 577717
		if (options.inherit)
Packit 577717
			fds[i].hw.inherit = 1;
Packit 577717
Packit 577717
		if (options.pin && is_group_leader)
Packit 577717
			fds[i].hw.pinned = 1;
Packit 577717
		fds[i].fd = perf_event_open(&fds[i].hw, pid, -1, group_fd, 0);
Packit 577717
		if (fds[i].fd == -1) {
Packit 577717
			warn("cannot attach event%d %s", i, fds[i].name);
Packit 577717
			goto error;
Packit 577717
		}
Packit 577717
	}
Packit 577717
Packit 577717
	if (!options.pid && go[1] > -1)
Packit 577717
		close(go[1]);
Packit 577717
Packit 577717
	if (options.print) {
Packit 577717
		if (!options.pid) {
Packit 577717
			while(waitpid(pid, &status, WNOHANG) == 0) {
Packit 577717
				sleep(1);
Packit 577717
				print_counts(fds, num_fds);
Packit 577717
			}
Packit 577717
		} else {
Packit 577717
			while(quit == 0) {
Packit 577717
				sleep(1);
Packit 577717
				print_counts(fds, num_fds);
Packit 577717
			}
Packit 577717
		}
Packit 577717
	} else {
Packit 577717
		if (!options.pid)
Packit 577717
			waitpid(pid, &status, 0);
Packit 577717
		else
Packit 577717
			pause();
Packit 577717
		print_counts(fds, num_fds);
Packit 577717
	}
Packit 577717
Packit 577717
	for(i=0; i < num_fds; i++)
Packit 577717
		close(fds[i].fd);
Packit 577717
Packit 577717
	perf_free_fds(fds, num_fds);
Packit 577717
Packit 577717
	/* free libpfm resources cleanly */
Packit 577717
	pfm_terminate();
Packit 577717
Packit 577717
	return 0;
Packit 577717
error:
Packit 577717
	free(fds);
Packit 577717
	if (!options.pid)
Packit 577717
		kill(SIGKILL, pid);
Packit 577717
Packit 577717
	/* free libpfm resources cleanly */
Packit 577717
	pfm_terminate();
Packit 577717
Packit 577717
	return -1;
Packit 577717
}
Packit 577717
Packit 577717
static void
Packit 577717
usage(void)
Packit 577717
{
Packit 577717
	printf("usage: task [-h] [-i] [-g] [-p] [-P] [-t pid] [-e event1,event2,...] cmd\n"
Packit 577717
		"-h\t\tget help\n"
Packit 577717
		"-i\t\tinherit across fork\n"
Packit 577717
		"-f\t\tuse PERF_FORMAT_GROUP for reading up counts (experimental, not working)\n"
Packit 577717
		"-p\t\tprint counts every second\n"
Packit 577717
		"-P\t\tpin events\n"
Packit 577717
		"-t pid\tmeasure existing pid\n"
Packit 577717
		"-e ev,ev\tgroup of events to measure (multiple -e switches are allowed)\n"
Packit 577717
		);
Packit 577717
}
Packit 577717
Packit 577717
int
Packit 577717
main(int argc, char **argv)
Packit 577717
{
Packit 577717
	int c;
Packit 577717
Packit 577717
	setlocale(LC_ALL, "");
Packit 577717
Packit 577717
	while ((c=getopt(argc, argv,"+he:ifpPt:")) != -1) {
Packit 577717
		switch(c) {
Packit 577717
			case 'e':
Packit 577717
				if (options.num_groups < MAX_GROUPS) {
Packit 577717
					options.events[options.num_groups++] = optarg;
Packit 577717
				} else {
Packit 577717
					errx(1, "you cannot specify more than %d groups.\n",
Packit 577717
						MAX_GROUPS);
Packit 577717
				}
Packit 577717
				break;
Packit 577717
			case 'f':
Packit 577717
				options.format_group = 1;
Packit 577717
				break;
Packit 577717
			case 'p':
Packit 577717
				options.print = 1;
Packit 577717
				break;
Packit 577717
			case 'P':
Packit 577717
				options.pin = 1;
Packit 577717
				break;
Packit 577717
			case 'i':
Packit 577717
				options.inherit = 1;
Packit 577717
				break;
Packit 577717
			case 't':
Packit 577717
				options.pid = atoi(optarg);
Packit 577717
				break;
Packit 577717
			case 'h':
Packit 577717
				usage();
Packit 577717
				exit(0);
Packit 577717
			default:
Packit 577717
				errx(1, "unknown error");
Packit 577717
		}
Packit 577717
	}
Packit 577717
	if (options.num_groups == 0) {
Packit 577717
		options.events[0] = "cycles,instructions";
Packit 577717
		options.num_groups = 1;
Packit 577717
	}
Packit 577717
	if (!argv[optind] && !options.pid)
Packit 577717
		errx(1, "you must specify a command to execute or a thread to attach to\n");
Packit 577717
Packit 577717
	signal(SIGINT, sig_handler);
Packit 577717
Packit 577717
	return parent(argv+optind);
Packit 577717
}