Blame src/libpfm-3.y/examples_v3.x/multiplex2.c

Packit 577717
/*
Packit 577717
 * multiplex2.c - example of kernel-level time-based or overflow-based event multiplexing
Packit 577717
 *
Packit 577717
 * Copyright (c) 2004-2006 Hewlett-Packard Development Company, L.P.
Packit 577717
 * Contributed by Stephane Eranian <eranian@hpl.hp.com>
Packit 577717
 *
Packit 577717
 * This program is free software; you can redistribute it and/or
Packit 577717
 * modify it under the terms of the GNU General Public License as
Packit 577717
 * published by the Free Software Foundation; either version 2 of the
Packit 577717
 * License, or (at your option) any later version.
Packit 577717
 *
Packit 577717
 * This program is distributed in the hope that it will be useful,
Packit 577717
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 577717
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 577717
 * General Public License for more details.
Packit 577717
 *
Packit 577717
 * You should have received a copy of the GNU General Public License
Packit 577717
 * along with this program; if not, write to the Free Software
Packit 577717
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
Packit 577717
 * 02111-1307 USA
Packit 577717
 */
Packit 577717
#ifndef _GNU_SOURCE
Packit 577717
  #define _GNU_SOURCE /* for getline */
Packit 577717
#endif
Packit 577717
#include <sys/types.h>
Packit 577717
#include <inttypes.h>
Packit 577717
#include <stdio.h>
Packit 577717
#include <stdlib.h>
Packit 577717
#include <stdarg.h>
Packit 577717
#include <errno.h>
Packit 577717
#include <unistd.h>
Packit 577717
#include <string.h>
Packit 577717
#include <syscall.h>
Packit 577717
#include <getopt.h>
Packit 577717
#include <signal.h>
Packit 577717
#include <math.h>
Packit 577717
#include <limits.h>
Packit 577717
#include <setjmp.h>
Packit 577717
#include <fcntl.h>
Packit 577717
#include <time.h>
Packit 577717
#include <sys/wait.h>
Packit 577717
#include <sys/ptrace.h>
Packit 577717
Packit 577717
#include <perfmon/pfmlib.h>
Packit 577717
#include <perfmon/perfmon.h>
Packit 577717
Packit 577717
#include "detect_pmcs.h"
Packit 577717
Packit 577717
#define MAX_EVT_NAME_LEN	128
Packit 577717
Packit 577717
#define MULTIPLEX_VERSION	"0.2"
Packit 577717
Packit 577717
#define SMPL_FREQ_IN_HZ	100
Packit 577717
Packit 577717
#define NUM_PMCS 256
Packit 577717
Packit 577717
typedef struct {
Packit 577717
	struct {
Packit 577717
		int opt_plm;	/* which privilege level to monitor (more than one possible) */
Packit 577717
		int opt_debug;	/* print debug information */
Packit 577717
		int opt_verbose;	/* verbose output */
Packit 577717
		int opt_us_format;	/* print large numbers with comma for thousands */
Packit 577717
		int opt_ovfl_switch;	/* overflow-based switching */
Packit 577717
		int opt_is_system;	/* use system-wide */
Packit 577717
		int opt_excl_idle;	/* exclude idle task */
Packit 577717
		int opt_excl_intr;	/* exclude interrupts */
Packit 577717
		int opt_intr_only;	/* interrupts only*/
Packit 577717
		int opt_no_cmd_out;	/* redirect cmd output to /dev/null */
Packit 577717
		int opt_no_header;	/* no header */
Packit 577717
	} program_opt_flags;
Packit 577717
Packit 577717
	unsigned long	max_counters;	/* maximum number of counter for the platform */
Packit 577717
	uint64_t	smpl_freq_hz;
Packit 577717
	uint64_t	smpl_freq_ns;
Packit 577717
	unsigned long	session_timeout;
Packit 577717
	uint64_t	smpl_period;
Packit 577717
	uint64_t	clock_res;
Packit 577717
Packit 577717
	unsigned long	cpu_mhz;
Packit 577717
Packit 577717
	pid_t		attach_pid;
Packit 577717
	int		pin_cmd_cpu;
Packit 577717
	int		pin_cpu;
Packit 577717
} program_options_t;
Packit 577717
Packit 577717
#define opt_plm			program_opt_flags.opt_plm
Packit 577717
#define opt_debug		program_opt_flags.opt_debug
Packit 577717
#define opt_verbose		program_opt_flags.opt_verbose
Packit 577717
#define opt_us_format		program_opt_flags.opt_us_format
Packit 577717
#define opt_ovfl_switch		program_opt_flags.opt_ovfl_switch
Packit 577717
#define opt_is_system		program_opt_flags.opt_is_system
Packit 577717
#define opt_excl_idle		program_opt_flags.opt_excl_idle
Packit 577717
#define opt_excl_intr		program_opt_flags.opt_excl_intr
Packit 577717
#define opt_intr_only		program_opt_flags.opt_intr_only
Packit 577717
#define opt_no_cmd_out		program_opt_flags.opt_no_cmd_out
Packit 577717
#define opt_no_header		program_opt_flags.opt_no_header
Packit 577717
Packit 577717
typedef struct _event_set_t {
Packit 577717
	struct _event_set_t	*next;
Packit 577717
	char			*event_str;
Packit 577717
	unsigned int		n_events;
Packit 577717
} event_set_t;
Packit 577717
Packit 577717
typedef int	pfm_ctxid_t;
Packit 577717
Packit 577717
static program_options_t options;
Packit 577717
Packit 577717
static pfarg_pmr_t	*all_pmcs;
Packit 577717
static pfarg_pmd_attr_t	*all_pmds;
Packit 577717
static pfarg_set_desc_t	*all_sets;
Packit 577717
static event_set_t	*all_events;
Packit 577717
Packit 577717
static unsigned int 	num_pmds, num_pmcs, num_sets, total_events;
Packit 577717
static volatile int	time_to_quit;
Packit 577717
static jmp_buf jbuf;
Packit 577717
Packit 577717
static void fatal_error(char *fmt,...) __attribute__((noreturn));
Packit 577717
Packit 577717
static void
Packit 577717
vbprintf(char *fmt, ...)
Packit 577717
{
Packit 577717
	va_list ap;
Packit 577717
Packit 577717
	if (options.opt_verbose == 0) return;
Packit 577717
Packit 577717
	va_start(ap, fmt);
Packit 577717
	vprintf(fmt, ap);
Packit 577717
	va_end(ap);
Packit 577717
}
Packit 577717
Packit 577717
static void
Packit 577717
fatal_error(char *fmt, ...)
Packit 577717
{
Packit 577717
	va_list ap;
Packit 577717
Packit 577717
	va_start(ap, fmt);
Packit 577717
	vfprintf(stderr, fmt, ap);
Packit 577717
	va_end(ap);
Packit 577717
Packit 577717
	exit(1);
Packit 577717
}
Packit 577717
Packit 577717
/*
Packit 577717
 * unreliable for CPU with variable clock speed
Packit 577717
 */
Packit 577717
static unsigned long
Packit 577717
get_cpu_speed(void)
Packit 577717
{
Packit 577717
	FILE *fp1;	
Packit 577717
	unsigned long f1 = 0, f2 = 0;
Packit 577717
	char buffer[128], *p, *value;
Packit 577717
Packit 577717
	memset(buffer, 0, sizeof(buffer));
Packit 577717
Packit 577717
	fp1 = fopen("/proc/cpuinfo", "r");
Packit 577717
	if (fp1 == NULL) return 0;
Packit 577717
Packit 577717
	for (;;) {
Packit 577717
		buffer[0] = '\0';
Packit 577717
Packit 577717
		p  = fgets(buffer, 127, fp1);
Packit 577717
		if (p == NULL)
Packit 577717
			break;
Packit 577717
Packit 577717
		/* skip  blank lines */
Packit 577717
		if (*p == '\n') continue;
Packit 577717
Packit 577717
		p = strchr(buffer, ':');
Packit 577717
		if (p == NULL)
Packit 577717
			break;
Packit 577717
Packit 577717
		/*
Packit 577717
		 * p+2: +1 = space, +2= firt character
Packit 577717
		 * strlen()-1 gets rid of \n
Packit 577717
		 */
Packit 577717
		*p = '\0';
Packit 577717
		value = p+2;
Packit 577717
Packit 577717
		value[strlen(value)-1] = '\0';
Packit 577717
Packit 577717
		if (!strncasecmp("cpu MHz", buffer, 7)) {
Packit 577717
			float fl;
Packit 577717
			sscanf(value, "%f", &fl);
Packit 577717
			f1 = lroundf(fl);
Packit 577717
			break;
Packit 577717
		}
Packit 577717
		if (!strncasecmp("BogoMIPS", buffer, 8)) {
Packit 577717
			float fl;
Packit 577717
			sscanf(value, "%f", &fl);
Packit 577717
			f2 = lroundf(fl);
Packit 577717
		}
Packit 577717
	}
Packit 577717
	fclose(fp1);
Packit 577717
	return f1 == 0 ? f2 : f1;
Packit 577717
}
Packit 577717
Packit 577717
/*
Packit 577717
 * pin task to CPU
Packit 577717
 */
Packit 577717
#ifndef __NR_sched_setaffinity
Packit 577717
#error "you need to define __NR_sched_setaffinity"
Packit 577717
#endif
Packit 577717
Packit 577717
#define MAX_CPUS	2048
Packit 577717
#define NR_CPU_BITS	(MAX_CPUS>>3)
Packit 577717
int
Packit 577717
pin_cpu(pid_t pid, unsigned int cpu)
Packit 577717
{
Packit 577717
	uint64_t my_mask[NR_CPU_BITS];
Packit 577717
Packit 577717
	if (cpu >= MAX_CPUS)
Packit 577717
		fatal_error("this program supports only up to %d CPUs\n", MAX_CPUS);
Packit 577717
Packit 577717
	my_mask[cpu>>6] = 1ULL << (cpu&63);
Packit 577717
Packit 577717
	return syscall(__NR_sched_setaffinity, pid, sizeof(my_mask), &my_mask);
Packit 577717
}
Packit 577717
Packit 577717
int
Packit 577717
child(char **arg)
Packit 577717
{
Packit 577717
	ptrace(PTRACE_TRACEME, 0, NULL, NULL);
Packit 577717
Packit 577717
	if (options.pin_cmd_cpu != -1) {
Packit 577717
		pin_cpu(getpid(), options.pin_cmd_cpu);
Packit 577717
		vbprintf("command running on CPU core %d\n", options.pin_cmd_cpu);
Packit 577717
	}
Packit 577717
Packit 577717
	if (options.opt_no_cmd_out) {
Packit 577717
		close(1);
Packit 577717
		close(2);
Packit 577717
	}
Packit 577717
	execvp(arg[0], arg);
Packit 577717
	/* not reached */
Packit 577717
Packit 577717
	exit(1);
Packit 577717
}
Packit 577717
Packit 577717
static void
Packit 577717
dec2sep(char *str2, char *str, char sep)
Packit 577717
{
Packit 577717
	int i, l, b, j, c=0;
Packit 577717
Packit 577717
	l = strlen(str2);
Packit 577717
	if (l <= 3) {
Packit 577717
		strcpy(str, str2);
Packit 577717
		return;
Packit 577717
	}
Packit 577717
	b = l +  l /3 - (l%3 == 0); /* l%3=correction to avoid extraneous comma at the end */
Packit 577717
	for(i=l, j=0; i >= 0; i--, j++) {
Packit 577717
		if (j) c++;
Packit 577717
		str[b-j] = str2[i];
Packit 577717
		if (c == 3 && i>0) {
Packit 577717
			str[b-++j] = sep;
Packit 577717
			c = 0;
Packit 577717
		}
Packit 577717
	}
Packit 577717
}
Packit 577717
Packit 577717
static void
Packit 577717
print_results(int ctxid, uint64_t *eff_timeout)
Packit 577717
{
Packit 577717
	unsigned int i, j, cnt, ovfl_event;
Packit 577717
	uint64_t value, tot_runs = 0;
Packit 577717
	uint64_t tot_dur = 0, c;
Packit 577717
	pfarg_set_info_t	*all_setinfos;
Packit 577717
	event_set_t *e;
Packit 577717
	char *p;
Packit 577717
	char tmp1[32], tmp2[32], *str;
Packit 577717
	char mtotal_str[32], *mtotal;
Packit 577717
	char stotal_str[32], *stotal;
Packit 577717
	int ret;
Packit 577717
Packit 577717
	all_setinfos = malloc(sizeof(pfarg_set_info_t)*num_sets);
Packit 577717
	if (all_setinfos == NULL)
Packit 577717
		fatal_error("cannot allocate all_setinfo\n");
Packit 577717
Packit 577717
	memset(all_setinfos, 0, sizeof(pfarg_set_info_t)*num_sets);
Packit 577717
Packit 577717
	for(i=0; i < num_sets; i++)
Packit 577717
		all_setinfos[i].set_id = i;
Packit 577717
Packit 577717
	/*
Packit 577717
	 * read all counters in one call
Packit 577717
	 *
Packit 577717
	 * There is a limitation on the size of the argument vector and
Packit 577717
	 * it may be necesarry to split into multiple calls. That limit
Packit 577717
	 * is usally at page size (16KB)
Packit 577717
	 */
Packit 577717
	ret = pfm_read(ctxid, 0, PFM_RW_PMD_ATTR, all_pmds, num_pmds * sizeof(*all_pmds));
Packit 577717
	if (ret == -1)
Packit 577717
		fatal_error("cannot read pmds: %s\n", strerror(errno));
Packit 577717
Packit 577717
	/*
Packit 577717
	 * extract all set information
Packit 577717
	 *
Packit 577717
	 * There is a limitation on the size of the argument vector and
Packit 577717
	 * it may be necesarry to split into multiple calls. That limit
Packit 577717
	 * is usually at page size (16KB)
Packit 577717
	 */
Packit 577717
	ret = pfm_getinfo_sets(ctxid, 0, all_setinfos, num_sets * sizeof(*all_setinfos));
Packit 577717
	if (ret == -1)
Packit 577717
		fatal_error("cannot get set info: %s\n", strerror(errno));
Packit 577717
Packit 577717
	/*
Packit 577717
	 * compute average number of runs
Packit 577717
	 *
Packit 577717
	 * the number of runs per set can be at most off by 1 between all sets
Packit 577717
	 */
Packit 577717
	for (i=0, cnt = 0; i < num_sets; i++) {
Packit 577717
		if (all_setinfos[i].set_runs == 0)
Packit 577717
			fatal_error("not enough runs to collect meaningful results: set%u did not run\n", i);
Packit 577717
		tot_runs += all_setinfos[i].set_runs;
Packit 577717
		tot_dur  += all_setinfos[i].set_duration;
Packit 577717
	}
Packit 577717
Packit 577717
	/*
Packit 577717
	 * print the results
Packit 577717
	 *
Packit 577717
	 * It is important to realize, that the first event we specified may not
Packit 577717
	 * be in PMD4. Not all events can be measured by any monitor. That's why
Packit 577717
	 * we need to use the pc[] array to figure out where event i was allocated.
Packit 577717
	 *
Packit 577717
	 */
Packit 577717
	if (options.opt_no_header == 0) {
Packit 577717
		printf("# %.2fHz period = %"PRIu64"nsecs\n# %"PRIu64" cycles @ %lu MHz\n", 
Packit 577717
			1000000000.0 / options.smpl_freq_ns, 
Packit 577717
			options.smpl_freq_ns, 
Packit 577717
			options.smpl_period,
Packit 577717
			options.cpu_mhz);
Packit 577717
Packit 577717
		if (options.opt_ovfl_switch == 0)
Packit 577717
			printf("# using time-based multiplexing\n"
Packit 577717
				"# %"PRIu64" nsecs effective switch timeout\n", 
Packit 577717
				*eff_timeout);
Packit 577717
		else
Packit 577717
			printf("# using overflow-based multiplexing\n");
Packit 577717
Packit 577717
		if (options.opt_is_system)
Packit 577717
			printf("# system-wide mode on CPU core %d\n",options.pin_cpu);
Packit 577717
		printf("# %d sets\n", num_sets);
Packit 577717
		printf("# %.2f average run per set\n", (double)tot_runs/num_sets);
Packit 577717
		printf("# %.2f average ns per set\n", (double)tot_dur/num_sets);
Packit 577717
		printf("# set       measured total     #runs         scaled total event name\n");
Packit 577717
		printf("# ------------------------------------------------------------------\n");
Packit 577717
	}
Packit 577717
	ovfl_event = options.opt_ovfl_switch ? 1 : 0;
Packit 577717
Packit 577717
	for (i=0, e = all_events, cnt = 0; i < num_sets; i++, e = e->next) {
Packit 577717
Packit 577717
		str = e->event_str;
Packit 577717
Packit 577717
		for(j=0; j < e->n_events-ovfl_event; j++, cnt++) {
Packit 577717
			value = all_pmds[cnt].reg_value;
Packit 577717
Packit 577717
			sprintf(tmp1, "%"PRIu64, value);
Packit 577717
Packit 577717
			if (options.opt_us_format) {
Packit 577717
				dec2sep(tmp1, mtotal_str, ',');
Packit 577717
			} else {
Packit 577717
				strcpy(mtotal_str, tmp1);
Packit 577717
			}
Packit 577717
			mtotal = mtotal_str;
Packit 577717
Packit 577717
			/* 
Packit 577717
			 * scaling
Packit 577717
			 * We use duration rather than number of runs to compute a more precise
Packit 577717
			 * scaled value. This avoids overcounting when the last set only partially
Packit 577717
			 * ran.
Packit 577717
			 *
Packit 577717
			 * We use double to avoid overflowing of the 64-bit count in case of very
Packit 577717
			 * large total duration
Packit 577717
			 */
Packit 577717
			c = llround(((double)value*tot_dur)/(double)all_setinfos[i].set_duration);
Packit 577717
			sprintf(tmp2, "%"PRIu64, c);
Packit 577717
Packit 577717
			if (options.opt_us_format) {
Packit 577717
				dec2sep(tmp2, stotal_str, ',');
Packit 577717
			} else {
Packit 577717
				strcpy(stotal_str, tmp2);
Packit 577717
			}
Packit 577717
			stotal  = stotal_str;
Packit 577717
Packit 577717
			printf("  %03d %20s  %8"PRIu64" %20s %s\n",
Packit 577717
					i,
Packit 577717
					mtotal,
Packit 577717
					all_setinfos[i].set_runs,
Packit 577717
					stotal,
Packit 577717
					str);
Packit 577717
			p = strchr(str, '\0');
Packit 577717
			if (p)
Packit 577717
				str = p+1;
Packit 577717
		}
Packit 577717
		/*
Packit 577717
		 * skip first event
Packit 577717
		 */
Packit 577717
		if (options.opt_ovfl_switch) cnt++;
Packit 577717
	}
Packit 577717
}
Packit 577717
Packit 577717
static void
Packit 577717
sigintr_handler(int sig)
Packit 577717
{
Packit 577717
	if (sig == SIGALRM) 
Packit 577717
		time_to_quit = 1;
Packit 577717
	else
Packit 577717
		time_to_quit = 2;
Packit 577717
	longjmp(jbuf, 1);
Packit 577717
}
Packit 577717
Packit 577717
static int
Packit 577717
measure_one_task(char **argv)
Packit 577717
{
Packit 577717
	int ctxid;
Packit 577717
	pfarg_sinfo_t sif;
Packit 577717
	pfarg_set_desc_t *my_sets;
Packit 577717
	pfarg_pmr_t *my_pmcs;
Packit 577717
	pfarg_pmd_attr_t *my_pmds;
Packit 577717
	uint64_t eff_timeout;
Packit 577717
	pfarg_msg_t msg;
Packit 577717
	pid_t pid;
Packit 577717
	int status, ret;
Packit 577717
Packit 577717
	memset(&sif, 0, sizeof(sif));
Packit 577717
Packit 577717
	my_pmcs = malloc(sizeof(pfarg_pmr_t)*num_pmcs);
Packit 577717
	my_pmds = malloc(sizeof(pfarg_pmd_attr_t)*num_pmds);
Packit 577717
	my_sets = malloc(sizeof(pfarg_set_desc_t)*num_sets);
Packit 577717
Packit 577717
	if (my_pmcs == NULL || my_pmds == NULL || my_sets == NULL)
Packit 577717
		fatal_error("cannot allocate event tables\n");
Packit 577717
	/*
Packit 577717
	 * make private copies
Packit 577717
	 */
Packit 577717
	memcpy(my_pmcs, all_pmcs, sizeof(pfarg_pmr_t)*num_pmcs);
Packit 577717
	memcpy(my_pmds, all_pmds, sizeof(pfarg_pmd_attr_t)*num_pmds);
Packit 577717
	memcpy(my_sets, all_sets, sizeof(pfarg_set_desc_t)*num_sets);
Packit 577717
Packit 577717
	/*
Packit 577717
	 * create the context
Packit 577717
	 */
Packit 577717
	ctxid = pfm_create(0, &sif;;
Packit 577717
	if (ctxid == -1 ) {
Packit 577717
		if (errno == ENOSYS) {
Packit 577717
			fatal_error("Your kernel does not have performance monitoring support!\n");
Packit 577717
		}
Packit 577717
		fatal_error("cannot create session %s\n", strerror(errno));
Packit 577717
	}
Packit 577717
	/*
Packit 577717
	 * set close-on-exec to ensure we will be getting the PFM_END_MSG, i.e.,
Packit 577717
	 * fd not visible to child.
Packit 577717
	 */
Packit 577717
	if (fcntl(ctxid, F_SETFD, FD_CLOEXEC))
Packit 577717
		fatal_error("cannot set CLOEXEC: %s\n", strerror(errno));
Packit 577717
Packit 577717
	/*
Packit 577717
	 * create the event sets
Packit 577717
	 *
Packit 577717
	 * event set 0 is always exist by default for backward compatibility
Packit 577717
	 * reason. However to avoid special casing set0 for creation, a PFM_CREATE_EVTSETS
Packit 577717
	 * for set0 does not complain and behaves as a PFM_CHANGE_EVTSETS
Packit 577717
	 */
Packit 577717
	vbprintf("requested timeout %"PRIu64" nsecs\n", my_sets[0].set_timeout);
Packit 577717
Packit 577717
	if (pfm_create_sets(ctxid, 0, my_sets, num_sets * sizeof(*my_sets)))
Packit 577717
		fatal_error("cannot create sets\n");
Packit 577717
Packit 577717
	eff_timeout = my_sets[0].set_timeout;
Packit 577717
Packit 577717
	vbprintf("effective timeout %"PRIu64" nsecs\n", my_sets[0].set_timeout);
Packit 577717
	/*
Packit 577717
	 * Now program the all the registers in one call
Packit 577717
	 *
Packit 577717
	 * Note that there is a limitation on the size of the argument vector
Packit 577717
	 * that can be passed. It is usually set to a page size (16KB).
Packit 577717
	 */
Packit 577717
	if (pfm_write(ctxid, 0, PFM_RW_PMC, my_pmcs, num_pmcs * sizeof(*my_pmcs)) == -1)
Packit 577717
		fatal_error("pfm_write error errno %d\n",errno);
Packit 577717
Packit 577717
	/*
Packit 577717
	 * initialize the PMD registers.
Packit 577717
	 *
Packit 577717
	 * Can use global pma because they are used read-only
Packit 577717
	 */
Packit 577717
	if (pfm_write(ctxid, 0, PFM_RW_PMD_ATTR, my_pmds, num_pmds * sizeof(*my_pmds)) == -1)
Packit 577717
		fatal_error("pfm_write(PMD) error errno %d\n",errno);
Packit 577717
Packit 577717
	/*
Packit 577717
	 * now launch the child code
Packit 577717
	 */
Packit 577717
	if (options.attach_pid == 0) {
Packit 577717
		if ((pid= fork()) == -1) fatal_error("Cannot fork process\n");
Packit 577717
		if (pid == 0) exit(child(argv));
Packit 577717
	} else {
Packit 577717
		pid = options.attach_pid;
Packit 577717
		ret = ptrace(PTRACE_ATTACH, pid, NULL, 0);
Packit 577717
		if (ret) {
Packit 577717
			fatal_error("cannot attach to task %d: %s\n",options.attach_pid, strerror(errno));
Packit 577717
		}
Packit 577717
	}
Packit 577717
Packit 577717
	ret = waitpid(pid, &status, WUNTRACED);
Packit 577717
	if (ret < 0 || WIFEXITED(status))
Packit 577717
		fatal_error("error command already terminated, exit code %d\n", WEXITSTATUS(status));
Packit 577717
Packit 577717
	vbprintf("child created and stopped\n");
Packit 577717
Packit 577717
	/*
Packit 577717
	 * now attach session
Packit 577717
	 */
Packit 577717
	if (pfm_attach(ctxid, 0, pid) == -1)
Packit 577717
		fatal_error("pfm_attach error errno %d\n",errno);
Packit 577717
Packit 577717
	/*
Packit 577717
	 * start monitoring
Packit 577717
	 */
Packit 577717
	if (pfm_set_state(ctxid, 0, PFM_ST_START) == -1)
Packit 577717
		fatal_error("pfm_set_state(start) error errno %d\n",errno);
Packit 577717
Packit 577717
	ptrace(PTRACE_DETACH, pid, NULL, 0);
Packit 577717
	vbprintf("child restarted\n");
Packit 577717
Packit 577717
	if (setjmp(jbuf) == 1) {
Packit 577717
		if (time_to_quit == 1) {
Packit 577717
			printf("timeout expired\n");
Packit 577717
		}
Packit 577717
		if (time_to_quit == 2)
Packit 577717
			printf("session interrupted\n");
Packit 577717
		goto finish_line;
Packit 577717
	}
Packit 577717
	signal(SIGALRM, sigintr_handler);
Packit 577717
	signal(SIGINT, sigintr_handler);
Packit 577717
Packit 577717
	if (options.session_timeout) {
Packit 577717
		printf("<monitoring for %lu seconds>\n", options.session_timeout);
Packit 577717
		alarm(options.session_timeout);
Packit 577717
	}
Packit 577717
	/*
Packit 577717
	 * mainloop
Packit 577717
	 */
Packit 577717
	ret = read(ctxid, &msg, sizeof(msg));
Packit 577717
	if (ret < sizeof(msg))
Packit 577717
		fatal_error("interrupted read\n");
Packit 577717
Packit 577717
	switch(msg.type) {
Packit 577717
		case PFM_MSG_OVFL:
Packit 577717
			fatal_error("unexpected ovfl message\n");
Packit 577717
			break;
Packit 577717
		case PFM_MSG_END:
Packit 577717
			break;
Packit 577717
		default: printf("unknown message type %d\n", msg.type);
Packit 577717
	}
Packit 577717
Packit 577717
finish_line:
Packit 577717
	/*
Packit 577717
	 * cleanup after an alarm timeout
Packit 577717
	 */
Packit 577717
	if (time_to_quit) {
Packit 577717
		/* stop monitored task */
Packit 577717
		ptrace(PTRACE_ATTACH, pid, NULL, 0);
Packit 577717
		waitpid(pid, NULL, WUNTRACED);
Packit 577717
Packit 577717
		/* detach context */
Packit 577717
		pfm_attach(ctxid, 0, PFM_NO_TARGET);
Packit 577717
	}
Packit 577717
Packit 577717
	if (options.attach_pid == 0) {
Packit 577717
		kill(pid, SIGKILL);
Packit 577717
		waitpid(pid, &status, 0);
Packit 577717
	} else {
Packit 577717
		ptrace(PTRACE_DETACH, pid, NULL, 0);
Packit 577717
	}
Packit 577717
Packit 577717
	if (time_to_quit < 2)
Packit 577717
		print_results(ctxid, &eff_timeout);
Packit 577717
Packit 577717
	close(ctxid);
Packit 577717
Packit 577717
	return 0;
Packit 577717
}
Packit 577717
Packit 577717
	
Packit 577717
static int
Packit 577717
measure_one_cpu(char **argv)
Packit 577717
{
Packit 577717
	int ctxid, status;
Packit 577717
	pfarg_pmr_t *my_pmcs;
Packit 577717
	pfarg_pmd_attr_t *my_pmds;
Packit 577717
	pfarg_set_desc_t *my_sets;
Packit 577717
	pfarg_sinfo_t sif;
Packit 577717
	pid_t pid = 0;
Packit 577717
	int ret;
Packit 577717
Packit 577717
	memset(&sif, 0, sizeof(sif));
Packit 577717
Packit 577717
	my_pmcs = malloc(sizeof(pfarg_pmr_t)*total_events);
Packit 577717
	my_pmds = malloc(sizeof(pfarg_pmd_attr_t)*total_events);
Packit 577717
	my_sets = malloc(sizeof(pfarg_set_desc_t)*num_sets);
Packit 577717
Packit 577717
	if (my_pmcs == NULL || my_pmds == NULL || my_sets == NULL)
Packit 577717
		fatal_error("cannot allocate event tables\n");
Packit 577717
	/*
Packit 577717
	 * make private copies
Packit 577717
	 */
Packit 577717
	memcpy(my_pmcs, all_pmcs, sizeof(pfarg_pmr_t)*num_pmcs);
Packit 577717
	memcpy(my_pmds, all_pmds, sizeof(pfarg_pmd_attr_t)*num_pmds);
Packit 577717
	memcpy(my_sets, all_sets, sizeof(pfarg_set_desc_t)*num_sets);
Packit 577717
Packit 577717
	if (options.pin_cpu == -1) {
Packit 577717
		options.pin_cpu = 0;
Packit 577717
		printf("forcing monitoring onto CPU core 0\n");
Packit 577717
		pin_cpu(getpid(), 0);
Packit 577717
	}
Packit 577717
Packit 577717
	/*
Packit 577717
	 * create session
Packit 577717
	 */
Packit 577717
	ctxid = pfm_create(PFM_FL_SYSTEM_WIDE, &sif;;
Packit 577717
	if (ctxid == -1) {
Packit 577717
		if (errno == ENOSYS) {
Packit 577717
			fatal_error("Your kernel does not have performance monitoring support!\n");
Packit 577717
		}
Packit 577717
		fatal_error("cannot create session %s\n", strerror(errno));
Packit 577717
	}
Packit 577717
	/*
Packit 577717
	 * set close-on-exec to ensure we will be getting the PFM_END_MSG, i.e.,
Packit 577717
	 * fd not visible to child.
Packit 577717
	 */
Packit 577717
	if (fcntl(ctxid, F_SETFD, FD_CLOEXEC))
Packit 577717
		fatal_error("cannot set CLOEXEC: %s\n", strerror(errno));
Packit 577717
Packit 577717
	/*
Packit 577717
	 * create the event sets
Packit 577717
	 *
Packit 577717
	 * event set 0 is always created by default for backward compatibility
Packit 577717
	 * reason. However to avoid special casing set0 for creation, a PFM_CREATE_EVTSETS
Packit 577717
	 * for set0 does not complain and behaves as a PFM_CHANGE_EVTSETS
Packit 577717
	 */
Packit 577717
	if (pfm_create_sets(ctxid, 0, my_sets, num_sets * sizeof(*my_sets)))
Packit 577717
		fatal_error("cannot create sets\n");
Packit 577717
Packit 577717
	/*
Packit 577717
	 * Now program the all the registers in one call
Packit 577717
	 *
Packit 577717
	 * Note that there is a limitation on the size of the argument vector
Packit 577717
	 * that can be passed. It is usually set to a page size (16KB).
Packit 577717
	 */
Packit 577717
	if (pfm_write(ctxid, 0, PFM_RW_PMC, my_pmcs, num_pmcs * sizeof(*my_pmcs)) == -1)
Packit 577717
		fatal_error("pfm_write error errno %d\n",errno);
Packit 577717
Packit 577717
	/*
Packit 577717
	 * initialize the PMD registers.
Packit 577717
	 *
Packit 577717
	 * We use all_Pmas because they are not modified, i.e., read-only
Packit 577717
	 */
Packit 577717
	if (pfm_write(ctxid, 0, PFM_RW_PMD_ATTR, my_pmds, num_pmds * sizeof(*my_pmds)) == -1)
Packit 577717
		fatal_error("pfm_write(PMD) error errno %d\n",errno);
Packit 577717
Packit 577717
	/*
Packit 577717
	 * now launch the child code
Packit 577717
	 */
Packit 577717
	if (*argv) {
Packit 577717
		if ((pid = fork()) == -1) fatal_error("Cannot fork process\n");
Packit 577717
		if (pid == 0) exit(child(argv));
Packit 577717
	} 
Packit 577717
Packit 577717
	/*
Packit 577717
	 * wait for the child to exec or be stopped
Packit 577717
	 * We do this even in system-wide mode to ensure
Packit 577717
	 * that the task does not start until we are ready
Packit 577717
	 * to monitor.
Packit 577717
	 */
Packit 577717
	if (pid) {
Packit 577717
		ret = waitpid(pid, &status, WUNTRACED);
Packit 577717
		if (ret < 0 || WIFEXITED(status))
Packit 577717
			fatal_error("error command already terminated, exit code %d\n", WEXITSTATUS(status));
Packit 577717
Packit 577717
		vbprintf("child created and stopped\n");
Packit 577717
	}
Packit 577717
Packit 577717
	/*
Packit 577717
	 * now attach the context
Packit 577717
	 */
Packit 577717
	if (pfm_attach(ctxid, 0, options.pin_cpu) == -1)
Packit 577717
		fatal_error("pfm_attach error errno %d\n",errno);
Packit 577717
Packit 577717
	/*
Packit 577717
	 * start monitoring
Packit 577717
	 */
Packit 577717
	if (pfm_set_state(ctxid, 0, PFM_ST_START) == -1)
Packit 577717
		fatal_error("pfm_set_state(start) error errno %d\n",errno);
Packit 577717
Packit 577717
	if (pid) ptrace(PTRACE_DETACH, pid, NULL, 0);
Packit 577717
Packit 577717
	if (pid == 0) {
Packit 577717
		if (options.session_timeout == 0) {
Packit 577717
			printf("<press enter to stop>\n");
Packit 577717
			getchar();
Packit 577717
		} else {
Packit 577717
			printf("<monitoring for %lu seconds>\n", options.session_timeout);
Packit 577717
			sleep(options.session_timeout);
Packit 577717
		}
Packit 577717
	} else {
Packit 577717
		ret = waitpid(pid, &status, 0);
Packit 577717
	} 
Packit 577717
	print_results(ctxid, &my_sets[0].set_timeout);
Packit 577717
Packit 577717
	if (ctxid) close(ctxid);
Packit 577717
Packit 577717
	return 0;
Packit 577717
}
Packit 577717
Packit 577717
int
Packit 577717
mainloop(char **argv)
Packit 577717
{
Packit 577717
	event_set_t *e;
Packit 577717
	pfarg_sinfo_t sif;
Packit 577717
	pfmlib_input_param_t inp;
Packit 577717
	pfmlib_output_param_t outp;
Packit 577717
	pfmlib_regmask_t impl_counters, used_pmcs;
Packit 577717
	pfmlib_event_t cycle_event;
Packit 577717
	unsigned int i, j;
Packit 577717
	char *p, *str;
Packit 577717
	int ret;
Packit 577717
	unsigned int max_counters, allowed_counters;
Packit 577717
Packit 577717
	pfm_get_num_counters(&max_counters);
Packit 577717
Packit 577717
	if (max_counters < 2 && options.opt_ovfl_switch) 
Packit 577717
		fatal_error("not enough counter to get overflow switching to work\n");
Packit 577717
Packit 577717
	allowed_counters = max_counters;
Packit 577717
Packit 577717
	/*
Packit 577717
	 * account for overflow counter (cpu cycles)
Packit 577717
	 */
Packit 577717
	if (options.opt_ovfl_switch) allowed_counters--;
Packit 577717
Packit 577717
	memset(&used_pmcs, 0, sizeof(used_pmcs));
Packit 577717
	memset(&impl_counters, 0, sizeof(impl_counters));
Packit 577717
Packit 577717
	pfm_get_impl_counters(&impl_counters);
Packit 577717
Packit 577717
	options.smpl_period = (options.cpu_mhz*1000000)/options.smpl_freq_hz;
Packit 577717
Packit 577717
	vbprintf("%"PRIu64"Hz period = %"PRIu64" cycles @ %luMhz\n", options.smpl_freq_hz, options.smpl_period, options.cpu_mhz);
Packit 577717
Packit 577717
	for (e = all_events; e; e = e->next) {
Packit 577717
		for (p = str = e->event_str; p ; ) {
Packit 577717
			p = strchr(str, ',');
Packit 577717
			if (p) str = p +1;
Packit 577717
			total_events++;
Packit 577717
		}
Packit 577717
	}
Packit 577717
Packit 577717
	/*
Packit 577717
	 * account for extra event per set (cycle event)
Packit 577717
	 */
Packit 577717
	if (options.opt_ovfl_switch) {
Packit 577717
		total_events += num_sets;
Packit 577717
		/*
Packit 577717
		 * look for our trigger event
Packit 577717
		 */
Packit 577717
		if (pfm_get_cycle_event(&cycle_event) != PFMLIB_SUCCESS)
Packit 577717
			fatal_error("Cannot find cycle event\n");
Packit 577717
	}
Packit 577717
Packit 577717
	vbprintf("total_events=%u\n", total_events);
Packit 577717
Packit 577717
	/*
Packit 577717
	 * assumes number of pmds = number  of events
Packit 577717
	 * cannot assume number of pmcs = num of events (e.g., P4 2 PMCS per event)
Packit 577717
	 */
Packit 577717
	all_pmcs = calloc(NUM_PMCS, sizeof(pfarg_pmr_t));
Packit 577717
	all_pmds = calloc(total_events, sizeof(pfarg_pmd_attr_t));
Packit 577717
	all_sets = calloc(num_sets, sizeof(pfarg_set_desc_t));
Packit 577717
Packit 577717
	if (all_pmcs == NULL || all_pmds == NULL || all_sets == NULL)
Packit 577717
		fatal_error("cannot allocate event tables\n");
Packit 577717
Packit 577717
	/*
Packit 577717
	 * use the library to figure out assignments for all events of all sets
Packit 577717
	 */
Packit 577717
	for (i=0, e = all_events; i < num_sets; i++, e = e->next) {
Packit 577717
Packit 577717
		memset(&inp,0, sizeof(inp));
Packit 577717
		memset(&outp,0, sizeof(outp));
Packit 577717
Packit 577717
		/*
Packit 577717
	 	 * build the pfp_unavail_pmcs bitmask by looking
Packit 577717
	 	 * at what perfmon has available. It is not always
Packit 577717
	 	 * the case that all PMU registers are actually available
Packit 577717
	 	 * to applications. For instance, on IA-32 platforms, some
Packit 577717
	 	 * registers may be reserved for the NMI watchdog timer.
Packit 577717
	 	 *
Packit 577717
	 	 * With this bitmap, the library knows which registers NOT to
Packit 577717
	 	 * use. Of source, it is possible that no valid assignement may
Packit 577717
	 	 * be possible if certina PMU registers  are not available.
Packit 577717
	 	 */
Packit 577717
		get_sif(options.opt_is_system? PFM_FL_SYSTEM_WIDE: 0, &sif;;
Packit 577717
		detect_unavail_pmu_regs(&sif, &inp.pfp_unavail_pmcs, NULL);
Packit 577717
Packit 577717
		str = e->event_str;
Packit 577717
		for(j=0, p = str; p && j < allowed_counters; j++) {
Packit 577717
Packit 577717
			p = strchr(str, ',');
Packit 577717
			if (p)
Packit 577717
				*p = '\0';
Packit 577717
			ret = pfm_find_full_event(str, &inp.pfp_events[j]);
Packit 577717
			if (ret != PFMLIB_SUCCESS)
Packit 577717
				fatal_error("event %s for set %d event %d: %s\n", str, i, j, pfm_strerror(ret));
Packit 577717
			if (p)
Packit 577717
				str = p + 1;
Packit 577717
		}
Packit 577717
		if (p) {
Packit 577717
			fatal_error("error in set %d: cannot have more than %d event(s) per set %s\n",
Packit 577717
				    i,
Packit 577717
				    allowed_counters,
Packit 577717
				    options.opt_ovfl_switch ? "(overflow switch mode)": "(hardware limit)");
Packit 577717
		}
Packit 577717
		/*
Packit 577717
		 * add the cycle event as the last event when we switch on overflow
Packit 577717
		 */
Packit 577717
		if (options.opt_ovfl_switch) {
Packit 577717
			inp.pfp_events[j]   = cycle_event;
Packit 577717
			inp.pfp_event_count = j+1;
Packit 577717
			inp.pfp_dfl_plm     = options.opt_plm;
Packit 577717
			e->n_events	    = j+1;
Packit 577717
		} else {
Packit 577717
			e->n_events         = j;
Packit 577717
			inp.pfp_event_count = j;
Packit 577717
		}
Packit 577717
Packit 577717
		inp.pfp_dfl_plm = options.opt_plm;
Packit 577717
Packit 577717
		if (options.opt_is_system) 
Packit 577717
			inp.pfp_flags = PFMLIB_PFP_SYSTEMWIDE;
Packit 577717
Packit 577717
		vbprintf("PMU programming for set %d\n", i);
Packit 577717
		/*
Packit 577717
		 * let the library do the hard work
Packit 577717
		 */
Packit 577717
		if ((ret=pfm_dispatch_events(&inp, NULL, &outp, NULL)) != PFMLIB_SUCCESS)
Packit 577717
			fatal_error("cannot configure events for set %d: %s\n", i, pfm_strerror(ret));
Packit 577717
Packit 577717
		/*
Packit 577717
		 * propagate from libpfm to kernel data structures
Packit 577717
		 */
Packit 577717
		for (j=0; j < outp.pfp_pmc_count; j++, num_pmcs++) {
Packit 577717
			all_pmcs[num_pmcs].reg_num   = outp.pfp_pmcs[j].reg_num;
Packit 577717
			all_pmcs[num_pmcs].reg_value = outp.pfp_pmcs[j].reg_value;
Packit 577717
			all_pmcs[num_pmcs].reg_set   = i;
Packit 577717
		}
Packit 577717
		for (j=0; j < outp.pfp_pmd_count; j++, num_pmds++) {
Packit 577717
			all_pmds[num_pmds].reg_num = outp.pfp_pmds[j].reg_num;
Packit 577717
			all_pmds[num_pmds].reg_set = i;
Packit 577717
		}
Packit 577717
Packit 577717
		/*
Packit 577717
		 * setup event set properties
Packit 577717
		 */
Packit 577717
		all_sets[i].set_id = i;
Packit 577717
Packit 577717
		if (options.opt_ovfl_switch) {
Packit 577717
Packit 577717
			all_sets[i].set_flags       = PFM_SETFL_OVFL_SWITCH;
Packit 577717
Packit 577717
			/* 
Packit 577717
			 * last counter contains our sampling counter
Packit 577717
			 *
Packit 577717
			 * the first overflow of our trigger counter does
Packit 577717
			 * trigger a switch.
Packit 577717
			 */
Packit 577717
			all_pmds[num_pmds-1].reg_ovfl_swcnt = 1;
Packit 577717
Packit 577717
			/*
Packit 577717
			 * We do this even in system-wide mode to ensure
Packit 577717
			 * that the task does not start until we are ready
Packit 577717
			 * to monitor.
Packit 577717
			 * setup the sampling period
Packit 577717
			 */
Packit 577717
			all_pmds[num_pmds-1].reg_value       = - options.smpl_period;
Packit 577717
			all_pmds[num_pmds-1].reg_short_reset = - options.smpl_period;
Packit 577717
			all_pmds[num_pmds-1].reg_long_reset  = - options.smpl_period;
Packit 577717
		} else {
Packit 577717
			/*
Packit 577717
			 * setup the switch timeout (in nanoseconds)
Packit 577717
			 * Note that the actual timeout may be bigger than requested
Packit 577717
			 * due to timer tick granularity. It is always advised to
Packit 577717
			 * check the set_timeout value upon return from set creation.
Packit 577717
			 * The structure will by then contain the actual timeout.
Packit 577717
			 */
Packit 577717
			all_sets[i].set_flags    = PFM_SETFL_TIME_SWITCH;
Packit 577717
			all_sets[i].set_timeout  = options.smpl_freq_ns;
Packit 577717
		}
Packit 577717
#ifdef __ia64__
Packit 577717
		if (options.opt_excl_intr && options.opt_is_system)
Packit 577717
			all_sets[i].set_flags  |= PFM_ITA_SETFL_EXCL_INTR;
Packit 577717
Packit 577717
		if (options.opt_intr_only && options.opt_is_system)
Packit 577717
			all_sets[i].set_flags  |= PFM_ITA_SETFL_INTR_ONLY;
Packit 577717
#endif
Packit 577717
	}
Packit 577717
Packit 577717
	if (options.opt_is_system)
Packit 577717
		return measure_one_cpu(argv);
Packit 577717
	return measure_one_task(argv);
Packit 577717
Packit 577717
}
Packit 577717
Packit 577717
static struct option multiplex_options[]={
Packit 577717
	{ "help", 0, 0, 1},
Packit 577717
	{ "freq", 1, 0, 2 },
Packit 577717
	{ "kernel-level", 0, 0, 3 },
Packit 577717
	{ "user-level", 0, 0, 4 },
Packit 577717
	{ "version", 0, 0, 5 },
Packit 577717
	{ "set", 1, 0, 6 },
Packit 577717
	{ "session-timeout", 1, 0, 7 },
Packit 577717
	{ "attach-task", 1, 0, 8 },
Packit 577717
	{ "pin-cmd", 1, 0, 9 },
Packit 577717
	{ "cpu", 1, 0, 10 },
Packit 577717
Packit 577717
	{ "verbose", 0, &options.opt_verbose, 1 },
Packit 577717
	{ "debug", 0, &options.opt_debug, 1 },
Packit 577717
	{ "us-counter-format", 0, &options.opt_us_format, 1},
Packit 577717
	{ "ovfl-switch", 0, &options.opt_ovfl_switch, 1},
Packit 577717
	{ "system-wide", 0, &options.opt_is_system, 1},
Packit 577717
#ifdef __ia64__
Packit 577717
	{ "excl-intr", 0, &options.opt_excl_intr, 1},
Packit 577717
	{ "intr-only", 0, &options.opt_intr_only, 1},
Packit 577717
#endif
Packit 577717
	{ "no-cmd-output", 0, &options.opt_no_cmd_out, 1},
Packit 577717
	{ "no-header", 0, &options.opt_no_header, 1},
Packit 577717
	{ 0, 0, 0, 0}
Packit 577717
};
Packit 577717
Packit 577717
static void
Packit 577717
generate_default_sets(void)
Packit 577717
{
Packit 577717
	event_set_t *es, *tail = NULL;
Packit 577717
	pfmlib_event_t events[2];
Packit 577717
	size_t len;
Packit 577717
	char *name;
Packit 577717
	unsigned int i;
Packit 577717
	int ret;
Packit 577717
	
Packit 577717
	ret = pfm_get_cycle_event(&events[0]);
Packit 577717
	if (ret != PFMLIB_SUCCESS)
Packit 577717
		fatal_error("cannot find cycle event\n");
Packit 577717
Packit 577717
	ret = pfm_get_inst_retired_event(&events[1]);
Packit 577717
	if (ret != PFMLIB_SUCCESS)
Packit 577717
		fatal_error("cannot find instruction retired event\n");
Packit 577717
Packit 577717
	pfm_get_max_event_name_len(&len;;
Packit 577717
Packit 577717
	for (i=0; i < 2; i++) {
Packit 577717
		name = malloc(len+1);
Packit 577717
		if (name == NULL)
Packit 577717
			fatal_error("cannot allocate space for event name\n");
Packit 577717
Packit 577717
		pfm_get_full_event_name(events+i, name, len+1);
Packit 577717
Packit 577717
		es = (event_set_t *)malloc(sizeof(event_set_t));
Packit 577717
		if (es == NULL)
Packit 577717
			fatal_error("cannot allocate new event set\n");
Packit 577717
Packit 577717
		memset(es, 0, sizeof(*es));
Packit 577717
Packit 577717
		es->event_str = name;
Packit 577717
		es->next      = NULL;
Packit 577717
		es->n_events  = 0;
Packit 577717
Packit 577717
		if (all_events == NULL)
Packit 577717
			all_events = es;
Packit 577717
		else
Packit 577717
			tail->next = es;
Packit 577717
		tail = es;
Packit 577717
	}
Packit 577717
	num_sets = i;
Packit 577717
}
Packit 577717
Packit 577717
static void
Packit 577717
print_usage(char **argv)
Packit 577717
{
Packit 577717
	printf("usage: %s [OPTIONS]... COMMAND\n", argv[0]);
Packit 577717
Packit 577717
	printf(	"-h, --help\t\t\t\tdisplay this help and exit\n"
Packit 577717
		"-V, --version\t\t\t\toutput version information and exit\n"
Packit 577717
		"-u, --user-level\t\t\tmonitor at the user level for all events\n"
Packit 577717
		"-k, --kernel-level\t\t\tmonitor at the kernel level for all events\n"
Packit 577717
		"-c, --us-counter-format\t\t\tprint large counts with comma for thousands\n"
Packit 577717
		"-p pid, --attach-task pid\t\tattach to a running task\n"
Packit 577717
		"--set=ev1[,ev2,ev3,ev4,...]\t\tdescribe one set\n"
Packit 577717
		"--freq=number\t\t\t\tset set switching frequency in Hz\n"
Packit 577717
		"-c cpu, --cpu=cpu\t\t\tCPU to use for system-wide [default current]\n"
Packit 577717
		"--ovfl-switch\t\t\t\tuse overflow based multiplexing (default: time-based)\n"
Packit 577717
		"--verbose\t\t\t\tprint more information during execution\n"
Packit 577717
		"--system-wide\t\t\t\tuse system-wide (only one CPU at a time)\n"
Packit 577717
		"--excl-idle\t\t\t\texclude idle task(system-wide only)\n"
Packit 577717
		"--excl-intr\t\t\t\texclude interrupt triggered execution(system-wide only)\n"
Packit 577717
		"--intr-only\t\t\t\tinclude only interrupt triggered execution(system-wide only)\n"
Packit 577717
		"--session-timeout=sec\t\t\tsession timeout in seconds (system-wide only)\n"
Packit 577717
		"--no-cmd-output\t\t\t\toutput of executed command redirected to /dev/null\n"
Packit 577717
		"--pin-cmd=cpu\t\t\t\tpin executed command onto a specific cpu\n"
Packit 577717
	);
Packit 577717
}
Packit 577717
Packit 577717
int
Packit 577717
main(int argc, char **argv)
Packit 577717
{
Packit 577717
	char *endptr = NULL;
Packit 577717
	pfmlib_options_t pfmlib_options;
Packit 577717
	event_set_t *tail = NULL, *es;
Packit 577717
	unsigned long long_val;
Packit 577717
	struct timespec ts;
Packit 577717
	uint64_t f_ns, d, f_final;
Packit 577717
	int c, ret;
Packit 577717
Packit 577717
	options.pin_cmd_cpu = options.pin_cpu = -1;
Packit 577717
Packit 577717
	while ((c=getopt_long(argc, argv,"+vhkuVct:p:", multiplex_options, 0)) != -1) {
Packit 577717
		switch(c) {
Packit 577717
			case   0: continue; /* fast path for options */
Packit 577717
Packit 577717
			case 'h':
Packit 577717
			case   1:
Packit 577717
				  print_usage(argv);
Packit 577717
				  exit(0);
Packit 577717
Packit 577717
			case 'v': options.opt_verbose = 1;
Packit 577717
				  break;
Packit 577717
			case  'c':
Packit 577717
				  options.opt_us_format = 1;
Packit 577717
				  break;
Packit 577717
			case   2:
Packit 577717
				if (options.smpl_freq_hz) fatal_error("sampling frequency set twice\n");
Packit 577717
				options.smpl_freq_hz = strtoull(optarg, &endptr, 10);
Packit 577717
				if (*endptr != '\0')
Packit 577717
					fatal_error("invalid frequency: %s\n", optarg);
Packit 577717
				break;
Packit 577717
			case   3:
Packit 577717
			case 'k':
Packit 577717
				options.opt_plm |= PFM_PLM0;
Packit 577717
				break;
Packit 577717
			case   4:
Packit 577717
			case 'u':
Packit 577717
				options.opt_plm |= PFM_PLM3;
Packit 577717
				break;
Packit 577717
			case 'V':
Packit 577717
			case   5:
Packit 577717
				printf("multiplex version " MULTIPLEX_VERSION " Date: " __DATE__ "\n"
Packit 577717
					"Copyright (C) 2004 Hewlett-Packard Company\n");
Packit 577717
				exit(0);
Packit 577717
			case   6:
Packit 577717
				es = (event_set_t *)malloc(sizeof(event_set_t));
Packit 577717
				if (es == NULL) fatal_error("cannot allocate new event set\n");
Packit 577717
Packit 577717
				es->event_str = optarg;
Packit 577717
				es->next      = NULL;
Packit 577717
				es->n_events  = 0;
Packit 577717
Packit 577717
				if (all_events == NULL)
Packit 577717
					all_events = es;
Packit 577717
				else
Packit 577717
					tail->next = es;
Packit 577717
				tail = es;
Packit 577717
				num_sets++;
Packit 577717
				break;
Packit 577717
			case 't':
Packit 577717
			case   7:
Packit 577717
				if (options.session_timeout) fatal_error("too many timeouts\n");
Packit 577717
				if (*optarg == '\0') fatal_error("--session-timeout needs an argument\n");
Packit 577717
			  	long_val = strtoul(optarg,&endptr, 10);
Packit 577717
				if (*endptr != '\0') 
Packit 577717
					fatal_error("invalid number of seconds for timeout: %s\n", optarg);
Packit 577717
Packit 577717
				if (long_val >= UINT_MAX) 
Packit 577717
					fatal_error("timeout is too big, must be < %u\n", UINT_MAX);
Packit 577717
Packit 577717
				options.session_timeout = (unsigned int)long_val;
Packit 577717
				break;
Packit 577717
			case 'p':
Packit 577717
			case   8:
Packit 577717
				if (options.attach_pid) fatal_error("process to attach specified twice\n");
Packit 577717
				options.attach_pid = (pid_t)atoi(optarg);
Packit 577717
				break;
Packit 577717
			case  9:
Packit 577717
				if (options.pin_cmd_cpu != -1) fatal_error("cannot pin command twice\n");
Packit 577717
				options.pin_cmd_cpu  = atoi(optarg);
Packit 577717
				break;
Packit 577717
Packit 577717
			case  10:
Packit 577717
				if (options.pin_cpu != -1) fatal_error("cannot pin to more than one cpu\n");
Packit 577717
				options.pin_cpu  = atoi(optarg);
Packit 577717
				break;
Packit 577717
			default:
Packit 577717
				fatal_error(""); /* just quit silently now */
Packit 577717
		}
Packit 577717
	}
Packit 577717
Packit 577717
	if (optind == argc && options.opt_is_system == 0 && options.attach_pid == 0) 
Packit 577717
		fatal_error("you need to specify a command to measure\n");
Packit 577717
Packit 577717
Packit 577717
	/*
Packit 577717
	 * pass options to library (optional)
Packit 577717
	 */
Packit 577717
	memset(&pfmlib_options, 0, sizeof(pfmlib_options));
Packit 577717
	pfmlib_options.pfm_debug = 0; /* set to 1 for debug */
Packit 577717
	pfmlib_options.pfm_verbose = options.opt_verbose; /* set to 1 for verbose */
Packit 577717
	pfm_set_options(&pfmlib_options);
Packit 577717
Packit 577717
	/*
Packit 577717
	 * Initialize pfm library (required before we can use it)
Packit 577717
	 */
Packit 577717
	ret = pfm_initialize();
Packit 577717
	if (ret != PFMLIB_SUCCESS)
Packit 577717
		fatal_error("Cannot initialize library: %s\n", pfm_strerror(ret));
Packit 577717
Packit 577717
	if ((options.cpu_mhz = get_cpu_speed()) == 0)
Packit 577717
		fatal_error("can't get CPU speed\n");
Packit 577717
Packit 577717
Packit 577717
	/*
Packit 577717
 	 * extract kernel clock resolution
Packit 577717
 	 */
Packit 577717
        clock_getres(CLOCK_MONOTONIC, &ts);
Packit 577717
       	options.clock_res  = ts.tv_sec * 1000000000 + ts.tv_nsec;
Packit 577717
Packit 577717
	/*
Packit 577717
 	 * adjust frequency to be a multiple of clock resolution
Packit 577717
 	 * otherwise kernel will fail pfm_create_evtsets()
Packit 577717
 	 */
Packit 577717
Packit 577717
	/*
Packit 577717
 	 * f_ns = run period in ns (1s/hz)
Packit 577717
 	 * default switch period is clock resolution
Packit 577717
 	 */
Packit 577717
	if (options.smpl_freq_hz == 0)
Packit 577717
		f_ns = options.clock_res;
Packit 577717
	else
Packit 577717
		f_ns = 1000000000 / options.smpl_freq_hz;
Packit 577717
Packit 577717
	/* round up period in nanoseconds */
Packit 577717
	d = (f_ns+options.clock_res-1) / options.clock_res;
Packit 577717
Packit 577717
	/* final period (multilple of clock_res */
Packit 577717
	f_final = d * options.clock_res;
Packit 577717
Packit 577717
	if (options.opt_ovfl_switch)
Packit 577717
		printf("clock_res=%"PRIu64"ns(%.2fHz) ask period=%"PRIu64"ns(%.2fHz) get period=%"PRIu64"ns(%.2fHz)\n",
Packit 577717
			options.clock_res,
Packit 577717
			1000000000.0 / options.clock_res,
Packit 577717
			f_ns,
Packit 577717
			1000000000.0 / f_ns,
Packit 577717
			f_final,
Packit 577717
			1000000000.0 / f_final);
Packit 577717
Packit 577717
	if (f_ns != f_final)
Packit 577717
		printf("Not getting the expected frequency due to kernel/hw limitation\n");
Packit 577717
Packit 577717
	/* adjust period */
Packit 577717
	options.smpl_freq_ns = f_final;
Packit 577717
Packit 577717
	/* not used */
Packit 577717
	options.smpl_freq_hz = 1000000000 / f_final;
Packit 577717
Packit 577717
	if (options.opt_plm == 0) options.opt_plm = PFM_PLM3;
Packit 577717
Packit 577717
	if (num_sets == 0)
Packit 577717
		generate_default_sets();
Packit 577717
Packit 577717
	return mainloop(argv+optind);
Packit 577717
}