Пример #1
0
void perf_end(const char* kname) {
  if (!enabled) return;
  int i, n;
  prctl(PR_TASK_PERF_EVENTS_DISABLE);

  static int first_time = 1;
  if (first_time) {
    first_time = 0;
    char name[128];
    for (n = 0; n < g_nthreads; n++) {
      sprintf (name, mxpa_profile_log, n);
      FILE* fp = fopen(name, "w");
      fclose(fp);
    }
  }

  char name[128];
  for (n = 0; n < g_nthreads; n++) {
    sprintf (name, mxpa_profile_log, n);
    FILE* fp = open_log_file(name);
    perf_event_desc_t *fds = g_fds[n];
    print_counts(fds, num_fds, kname, fp);
    for (i = 0; i < num_fds; i++) close(fds[i].fd);
    perf_free_fds(fds, num_fds);
    g_fds[n] = fds = NULL;
    fclose(fp);
  }
}
Пример #2
0
int
measure(pid_t pid)
{
	perf_event_desc_t *fds = NULL;
	int i, ret, num_fds = 0;
	char fn[32];

	if (pfm_initialize() != PFM_SUCCESS)
		errx(1, "libpfm initialization failed\n");

	ret = perf_setup_list_events(options.events, &fds, &num_fds);
	if (ret || (num_fds == 0))
		exit(1);

	fds[0].fd = -1;
	for(i=0; i < num_fds; i++) {
		fds[i].hw.disabled = 0; /* start immediately */

		/* request timing information necessary for scaling counts */
		fds[i].hw.read_format = PERF_FORMAT_SCALE;
		fds[i].hw.pinned = !i && options.pinned;
		fds[i].fd = perf_event_open(&fds[i].hw, pid, -1, (options.group? fds[0].fd : -1), 0);
		if (fds[i].fd == -1)
			errx(1, "cannot attach event %s", fds[i].name);
	}
	/*
	 * no notification is generated by perf_counters
	 * when the monitored thread exits. Thus we need
	 * to poll /proc/ to detect it has disappeared,
	 * otherwise we have to wait until the end of the
	 * timeout
	 */
	sprintf(fn, "/proc/%d/status", pid);

	while(access(fn, F_OK) == 0 && options.delay) {
		sleep(1);
		options.delay--;
		if (options.print)
			print_counts(fds, num_fds, 1);
	}
	if (options.delay)
		warn("thread %d terminated before timeout", pid);

	if (!options.print)
		print_counts(fds, num_fds, 0);

	for(i=0; i < num_fds; i++)
		close(fds[i].fd);

	perf_free_fds(fds, num_fds);

	/* free libpfm resources cleanly */
	pfm_terminate();

	return 0;
}
Пример #3
0
void close_cpu(int c)
{
	perf_event_desc_t *fds = NULL;
	int i, j;
	int total = 0;

	fds = all_fds[c];

	if (fds[0].fd == -1)
		return;

	for(i=0; i < options.num_groups; i++) {
		for(j=0; j < options.nevents[i]; j++)
			close(fds[j].fd);
		total += options.nevents[i];
	}
	perf_free_fds(fds, total);
}
Пример #4
0
int
mainloop(char **arg)
{
	static uint64_t ovfl_count; /* static to avoid setjmp issue */
	struct pollfd pollfds[1];
	sigset_t bmask;
	int go[2], ready[2];
	size_t pgsz;
	size_t map_size = 0;
	pid_t pid;
	int status, ret;
	int i;
	char buf;

	if (pfm_initialize() != PFM_SUCCESS)
		errx(1, "libpfm initialization failed\n");

	pgsz = sysconf(_SC_PAGESIZE);
	map_size = (options.mmap_pages+1)*pgsz;

	/*
	 * does allocate fds
	 */
	ret  = perf_setup_list_events(options.events, &fds, &num_fds);
	if (ret || !num_fds)
		errx(1, "cannot setup event list");

	memset(pollfds, 0, sizeof(pollfds));

	ret = pipe(ready);
	if (ret)
		err(1, "cannot create pipe ready");

	ret = pipe(go);
	if (ret)
		err(1, "cannot create pipe go");

	/*
	 * Create the child task
	 */
//	if ((pid=fork()) == -1)
//		err(1, "cannot fork process\n");

/*	if (pid == 0) {
		close(ready[0]);
		close(go[1]);
*/
		/*
		 * let the parent know we exist
		 */
/*		close(ready[1]);
		if (read(go[0], &buf, 1) == -1)
			err(1, "unable to read go_pipe");

		exit(child(arg));
	}
*/
	int tid;
	pid = getpid();
	tid = gettid();
	printf("From C - pid : %d, tid : %d\n",pid, tid);	
	
	close(ready[1]);
	close(go[0]);

	if (read(ready[0], &buf, 1) == -1)
		err(1, "unable to read child_ready_pipe");

	close(ready[0]);

	fds[0].fd = -1;

	fds[0].hw.sample_period=10000;
	if (!fds[0].hw.sample_period)
		errx(1, "need to set sampling period or freq on first event, use :period= or :freq=");

	for(i=0; i < num_fds; i++) {

		if (i == 0) {
			fds[i].hw.disabled = 1;
			fds[i].hw.enable_on_exec = 1; /* start immediately */
		} else
			fds[i].hw.disabled = 0;


		if (options.opt_inherit)
			fds[i].hw.inherit = 1;

		if (fds[i].hw.sample_period) {
			/*
			 * set notification threshold to be halfway through the buffer
			 */
			fds[i].hw.wakeup_watermark = (options.mmap_pages*pgsz) / 2;
			fds[i].hw.watermark = 1;

			fds[i].hw.sample_type = PERF_SAMPLE_IP|PERF_SAMPLE_TID|PERF_SAMPLE_READ|PERF_SAMPLE_TIME|PERF_SAMPLE_PERIOD;
			/*
			 * if we have more than one event, then record event identifier to help with parsing
			 */
			if (num_fds > 1)
				fds[i].hw.sample_type |= PERF_SAMPLE_IDENTIFIER;

			fprintf(options.output_file,"%s period=%"PRIu64" freq=%d\n", fds[i].name, fds[i].hw.sample_period, fds[i].hw.freq);

			fds[i].hw.read_format = PERF_FORMAT_SCALE;

			if (fds[i].hw.freq)
				fds[i].hw.sample_type |= PERF_SAMPLE_PERIOD;
			
			fds[i].hw.sample_period=10000;
			if (options.mem_mode)
				fds[i].hw.sample_type |= PERF_SAMPLE_WEIGHT | PERF_SAMPLE_DATA_SRC | PERF_SAMPLE_ADDR;
			if (options.branch_mode) {
				fds[i].hw.sample_type |= PERF_SAMPLE_BRANCH_STACK;
				fds[i].hw.branch_sample_type = PERF_SAMPLE_BRANCH_ANY;
			}
		}
		/*
		 * we are grouping the events, so there may be a limit
		 */
		fds[i].fd = perf_event_open(&fds[i].hw, tid+1, options.cpu, fds[0].fd, 0);
		if (fds[i].fd == -1) {
			if (fds[i].hw.precise_ip)
				err(1, "cannot attach event %s: precise mode may not be supported", fds[i].name);
			err(1, "cannot attach event %s", fds[i].name);
		}
	}

	/*
	 * kernel adds the header page to the size of the mmapped region
	 */
	fds[0].buf = mmap(NULL, map_size, PROT_READ|PROT_WRITE, MAP_SHARED, fds[0].fd, 0);
	if (fds[0].buf == MAP_FAILED)
		err(1, "cannot mmap buffer");

	/* does not include header page */
	fds[0].pgmsk = (options.mmap_pages*pgsz)-1;

	/*
	 * send samples for all events to first event's buffer
	 */
	for (i = 1; i < num_fds; i++) {
		if (!fds[i].hw.sample_period)
			continue;
		ret = ioctl(fds[i].fd, PERF_EVENT_IOC_SET_OUTPUT, fds[0].fd);
		if (ret)
			err(1, "cannot redirect sampling output");
	}

	if (num_fds > 1 && fds[0].fd > -1) {
		for(i = 0; i < num_fds; i++) {
			/*
			 * read the event identifier using ioctl
			 * new method replaced the trick with PERF_FORMAT_GROUP + PERF_FORMAT_ID + read()
			 */
			ret = ioctl(fds[i].fd, PERF_EVENT_IOC_ID, &fds[i].id);
			if (ret == -1)
				err(1, "cannot read ID");
			fprintf(options.output_file,"ID %"PRIu64"  %s\n", fds[i].id, fds[i].name);
		}
	}

	pollfds[0].fd = fds[0].fd;
	pollfds[0].events = POLLIN;
	
	for(i=0; i < num_fds; i++) {
		ret = ioctl(fds[i].fd, PERF_EVENT_IOC_ENABLE, 0);
		if (ret)
			err(1, "cannot enable event %s\n", fds[i].name);
	}
	signal(SIGCHLD, cld_handler);

	close(go[1]);

	if (setjmp(jbuf) == 1)
		goto terminate_session;

	sigemptyset(&bmask);
	sigaddset(&bmask, SIGCHLD);

	/*
	 * core loop
	 */
	for(;;) {
		ret = poll(pollfds, 1, -1);
		if (ret < 0 && errno == EINTR)
			break;
		ovfl_count++;
		ret = sigprocmask(SIG_SETMASK, &bmask, NULL);
		if (ret)
			err(1, "setmask");
		process_smpl_buf(&fds[0]);
		ret = sigprocmask(SIG_UNBLOCK, &bmask, NULL);
		if (ret)
			err(1, "unblock");
	}
	printf("How was you day??\n");
terminate_session:
	/*
	 * cleanup child
	 */
	wait4(pid, &status, 0, NULL);

	for(i=0; i < num_fds; i++)
		close(fds[i].fd);

	/* check for partial event buffer */
	process_smpl_buf(&fds[0]);
	munmap(fds[0].buf, map_size);

	perf_free_fds(fds, num_fds);

	fprintf(options.output_file,
		"%"PRIu64" samples collected in %"PRIu64" poll events, %"PRIu64" lost samples\n",
		collected_samples,
		ovfl_count, lost_samples);

	/* free libpfm resources cleanly */
	pfm_terminate();

	fclose(options.output_file);

	return 0;
}
Пример #5
0
static void
measure(void)
{
	perf_event_desc_t *fds = NULL;
	int num_fds = 0;
	uint64_t values[3];
	ssize_t n;
	int i, ret;
	int pr[2], pw[2];
	pid_t pid;
	char cc = '0';

	ret = pfm_initialize();
	if (ret != PFM_SUCCESS)
		err(1, "cannot initialize libpfm");

	if (options.cpu == -1) {
		srandom(getpid());
		options.cpu = random() % sysconf(_SC_NPROCESSORS_ONLN);
	}

	ret = pipe(pr);
	if (ret)
		err(1, "cannot create read pipe");

	ret = pipe(pw);
	if (ret)
		err(1, "cannot create write pipe");

	ret = perf_setup_list_events(options.events, &fds, &num_fds);
	if (ret || !num_fds)
		exit(1);

	for(i=0; i < num_fds; i++) {
		fds[i].hw.disabled = 1;
		fds[i].hw.read_format = PERF_FORMAT_SCALE;

		fds[i].fd = perf_event_open(&fds[i].hw, 0, -1, -1, 0);
		if (fds[i].fd == -1)
			err(1, "cannot open event %d", i);
	}

	/*
 	 * Pin to CPU0, inherited by child process. That will enforce
 	 * the ping-pionging and thus stress the PMU context switch 
 	 * which is what we want
 	 */
	ret = pin_cpu(getpid(), options.cpu);
	if (ret)
		err(1, "cannot pin to CPU%d", options.cpu);

	printf("Both processes pinned to CPU%d, running for %d seconds\n", options.cpu, options.delay);

	/*
 	 * create second process which is not monitoring at the moment
 	 */
	switch(pid=fork()) {
		case -1:
			err(1, "cannot create child\n");
		case 0:
			/* do not inherit session fd */
			for(i=0; i < num_fds; i++)
				close(fds[i].fd);
			/* pr[]: write master, read child */
			/* pw[]: read master, write child */
			close(pr[1]); close(pw[0]);
			do_child(pr[0], pw[1]);
			exit(1);
	}

	close(pr[0]);
	close(pw[1]);

	/*
	 * Let's roll now
	 */
	prctl(PR_TASK_PERF_EVENTS_ENABLE);
	signal(SIGALRM, sig_handler);
	alarm(options.delay);

	/*
	 * ping pong loop
	 */
	while(!quit) {
		n = write(pr[1], "c", 1);
		if (n < 1)
			err(1, "write failed");
		n = read(pw[0], &cc, 1);
		if (n < 1)
			err(1, "read failed");
	}

	prctl(PR_TASK_PERF_EVENTS_DISABLE);

	for(i=0; i < num_fds; i++) {
		uint64_t val;
		double ratio;

		ret = read(fds[i].fd, values, sizeof(values));
		if (ret == -1)
			err(1,"pfm_read error");
		if (ret != sizeof(values))
			errx(1, "did not read correct amount %d", ret);

		val = perf_scale(values);
		ratio = perf_scale_ratio(values);

		if (ratio == 1.0)
			printf("%20"PRIu64" %s\n", val, fds[i].name);
		else
			if (ratio == 0.0)
				printf("%20"PRIu64" %s (did not run: competing session)\n", val, fds[i].name);
			else
				printf("%20"PRIu64" %s (scaled from %.2f%% of time)\n", val, fds[i].name, ratio*100.0);
	}
	/*
	 * kill child process
	 */
	kill(SIGKILL, pid);

	/*
 	 * close pipes
 	 */
	close(pr[1]);
	close(pw[0]);
	/*
	 * and destroy our session
	 */
	for(i=0; i < num_fds; i++)
		close(fds[i].fd);

	perf_free_fds(fds, num_fds);

	/* free libpfm resources cleanly */
	pfm_terminate();
}
/* the **fd parameter must point to a null pointer on the first call
 * max_fds and num_fds must both point to a zero value on the first call
 * The return value is success (0) vs. failure (non-zero)
 */
int
perf_setup_argv_events(const char **argv, perf_event_desc_t **fds, int *num_fds)
{
	perf_event_desc_t *fd;
	pfm_perf_encode_arg_t arg;
	int new_max, ret, num, max_fds;
	int group_leader;

	if (!(argv && fds && num_fds))
		return -1;

	fd = *fds;
	if (fd) {
		max_fds = fd[0].max_fds;
		if (max_fds < 2)
			return -1;
		num = *num_fds;
	} else {
		max_fds = num = 0; /* bootstrap */
	}
	group_leader = num;

	while(*argv) {
		if (num == max_fds) {
			if (max_fds == 0)
				new_max = 2;
			else
				new_max = max_fds << 1;

			if (new_max < max_fds) {
				warn("too many entries");
				goto error;
			}
			fd = realloc(fd, new_max * sizeof(*fd));
			if (!fd) {
				warn("cannot allocate memory");
				goto error;
			}
			/* reset newly allocated chunk */
			memset(fd + max_fds, 0, (new_max - max_fds) * sizeof(*fd));
			max_fds = new_max;

			/* update max size */
			fd[0].max_fds = max_fds;
		}
		/* ABI compatibility, set before calling libpfm */
		fd[num].hw.size = sizeof(fd[num].hw);

		memset(&arg, 0, sizeof(arg));
		arg.attr = &fd[num].hw;
		arg.fstr = &fd[num].fstr; /* fd[].fstr is NULL */

		ret = pfm_get_os_event_encoding(*argv, PFM_PLM0|PFM_PLM3, PFM_OS_PERF_EVENT_EXT, &arg);
		if (ret != PFM_SUCCESS) {
			warnx("event %s: %s", *argv, pfm_strerror(ret));
			goto error;
		}

		fd[num].name = strdup(*argv);
		fd[num].group_leader = group_leader;
		fd[num].idx = arg.idx;
		fd[num].cpu = arg.cpu;

		num++;
		argv++;
	}
	*num_fds = num;
	*fds = fd;
	return 0;
error:
	perf_free_fds(fd, num);
	return -1;
}
Пример #7
0
int
mainloop(char **arg)
{
	static uint64_t ovfl_count; /* static to avoid setjmp issue */
	struct pollfd pollfds[1];
	sigset_t bmask;
	int go[2], ready[2];
	uint64_t *val;
	size_t sz, pgsz;
	size_t map_size = 0;
	pid_t pid;
	int status, ret;
	int i;
	char buf;

	if (pfm_initialize() != PFM_SUCCESS)
		errx(1, "libpfm initialization failed\n");

	pgsz = sysconf(_SC_PAGESIZE);
	map_size = (options.mmap_pages+1)*pgsz;

	/*
	 * does allocate fds
	 */
	ret  = perf_setup_list_events(options.events, &fds, &num_fds);
	if (ret || !num_fds)
		errx(1, "cannot setup event list");

	memset(pollfds, 0, sizeof(pollfds));

	ret = pipe(ready);
	if (ret)
		err(1, "cannot create pipe ready");

	ret = pipe(go);
	if (ret)
		err(1, "cannot create pipe go");

	/*
	 * Create the child task
	 */
	if ((pid=fork()) == -1)
		err(1, "cannot fork process\n");

	if (pid == 0) {
		close(ready[0]);
		close(go[1]);

		/*
		 * let the parent know we exist
		 */
		close(ready[1]);
		if (read(go[0], &buf, 1) == -1)
			err(1, "unable to read go_pipe");

		exit(child(arg));
	}
	close(ready[1]);
	close(go[0]);

	if (read(ready[0], &buf, 1) == -1)
		err(1, "unable to read child_ready_pipe");

	close(ready[0]);

	fds[0].fd = -1;

	if (!fds[0].hw.sample_period)
		errx(1, "need to set sampling period or freq on first event, use :period= or :freq=");

	for(i=0; i < num_fds; i++) {

		if (i == 0) {
			fds[i].hw.disabled = 1;
			fds[i].hw.enable_on_exec = 1; /* start immediately */
		} else
			fds[i].hw.disabled = 0;


		if (options.opt_inherit)
			fds[i].hw.inherit = 1;

		if (fds[i].hw.sample_period) {
			/*
			 * set notification threshold to be halfway through the buffer
			 */
			fds[i].hw.wakeup_watermark = (options.mmap_pages*pgsz) / 2;
			fds[i].hw.watermark = 1;

			fds[i].hw.sample_type = PERF_SAMPLE_IP|PERF_SAMPLE_TID|PERF_SAMPLE_READ|PERF_SAMPLE_TIME|PERF_SAMPLE_PERIOD|PERF_SAMPLE_STREAM_ID;
			fprintf(options.output_file,"%s period=%"PRIu64" freq=%d\n", fds[i].name, fds[i].hw.sample_period, fds[i].hw.freq);

			fds[i].hw.read_format = PERF_FORMAT_SCALE;
			if (num_fds > 1)
				fds[i].hw.read_format |= PERF_FORMAT_GROUP|PERF_FORMAT_ID;

			if (fds[i].hw.freq)
				fds[i].hw.sample_type |= PERF_SAMPLE_PERIOD;
		}

		fds[i].fd = perf_event_open(&fds[i].hw, pid, options.cpu, fds[0].fd, 0);
		if (fds[i].fd == -1) {
			if (fds[i].hw.precise_ip)
				err(1, "cannot attach event %s: precise mode may not be supported", fds[i].name);
			err(1, "cannot attach event %s", fds[i].name);
		}
	}

	/*
	 * kernel adds the header page to the size of the mmapped region
	 */
	fds[0].buf = mmap(NULL, map_size, PROT_READ|PROT_WRITE, MAP_SHARED, fds[0].fd, 0);
	if (fds[0].buf == MAP_FAILED)
		err(1, "cannot mmap buffer");

	/* does not include header page */
	fds[0].pgmsk = (options.mmap_pages*pgsz)-1;

	/*
	 * send samples for all events to first event's buffer
	 */
	for (i = 1; i < num_fds; i++) {
		if (!fds[i].hw.sample_period)
			continue;
		ret = ioctl(fds[i].fd, PERF_EVENT_IOC_SET_OUTPUT, fds[0].fd);
		if (ret)
			err(1, "cannot redirect sampling output");
	}

	/*
	 * we are using PERF_FORMAT_GROUP, therefore the structure
	 * of val is as follows:
	 *
	 *      { u64           nr;
	 *        { u64         time_enabled; } && PERF_FORMAT_ENABLED
	 *        { u64         time_running; } && PERF_FORMAT_RUNNING
	 *        { u64         value;
	 *          { u64       id;           } && PERF_FORMAT_ID
	 *        }             cntr[nr];
	 * We are skipping the first 3 values (nr, time_enabled, time_running)
	 * and then for each event we get a pair of values.
	 */
	if (num_fds > 1) {
		sz = (3+2*num_fds)*sizeof(uint64_t);
		val = malloc(sz);
		if (!val)
			err(1, "cannot allocate memory");

		ret = read(fds[0].fd, val, sz);
		if (ret == -1)
			err(1, "cannot read id %zu", sizeof(val));


		for(i=0; i < num_fds; i++) {
			fds[i].id = val[2*i+1+3];
			fprintf(options.output_file,"%"PRIu64"  %s\n", fds[i].id, fds[i].name);
		}
		free(val);
	}

	pollfds[0].fd = fds[0].fd;
	pollfds[0].events = POLLIN;
	
	for(i=0; i < num_fds; i++) {
		ret = ioctl(fds[i].fd, PERF_EVENT_IOC_ENABLE, 0);
		if (ret)
			err(1, "cannot enable event %s\n", fds[i].name);
	}
	signal(SIGCHLD, cld_handler);

	close(go[1]);

	if (setjmp(jbuf) == 1)
		goto terminate_session;

	sigemptyset(&bmask);
	sigaddset(&bmask, SIGCHLD);

	/*
	 * core loop
	 */
	for(;;) {
		ret = poll(pollfds, 1, -1);
		if (ret < 0 && errno == EINTR)
			break;
		ovfl_count++;
		ret = sigprocmask(SIG_SETMASK, &bmask, NULL);
		if (ret)
			err(1, "setmask");
		process_smpl_buf(&fds[0]);
		ret = sigprocmask(SIG_UNBLOCK, &bmask, NULL);
		if (ret)
			err(1, "unblock");
	}
terminate_session:
	/*
	 * cleanup child
	 */
	wait4(pid, &status, 0, NULL);

	for(i=0; i < num_fds; i++)
		close(fds[i].fd);

	/* check for partial event buffer */
	process_smpl_buf(&fds[0]);
	munmap(fds[0].buf, map_size);

	perf_free_fds(fds, num_fds);

	fprintf(options.output_file,
		"%"PRIu64" samples collected in %"PRIu64" poll events, %"PRIu64" lost samples\n",
		collected_samples,
		ovfl_count, lost_samples);

	/* free libpfm resources cleanly */
	pfm_terminate();

	fclose(options.output_file);

	return 0;
}
int
mainloop(char **arg)
{
	static uint64_t ovfl_count = 0; /* static to avoid setjmp issue */
	struct pollfd pollfds[1];
	int ret;
	int fd = -1;
	int i;

	if (pfm_initialize() != PFM_SUCCESS)
		errx(1, "libpfm initialization failed\n");

	pgsz = sysconf(_SC_PAGESIZE);
	map_size = (options.mmap_pages+1)*pgsz;

	if (options.cgroup) {
		fd = open_cgroup(options.cgroup);
		if (fd == -1)
			err(1, "cannot open cgroup file %s\n", options.cgroup);
	}

	setup_cpu(options.cpu, fd);

	/* done with cgroup */
	if (fd != -1)
		close(fd);

	signal(SIGALRM, handler);
	signal(SIGINT, handler);

	pollfds[0].fd = fds[0].fd;
	pollfds[0].events = POLLIN;

	printf("monitoring on CPU%d, session ending in %ds\n", options.cpu, options.delay);

	if (setjmp(jbuf) == 1)
		goto terminate_session;

	start_cpu();

	alarm(options.delay);
	/*
	 * core loop
	 */
	for(;;) {
		ret = poll(pollfds, 1, -1);
		if (ret < 0 && errno == EINTR)
			break;
		ovfl_count++;
		process_smpl_buf(&fds[0]);
	}
terminate_session:
	for(i=0; i < num_fds; i++)
		close(fds[i].fd);

	/* check for partial event buffer */
	process_smpl_buf(&fds[0]);
	munmap(fds[0].buf, map_size);

	perf_free_fds(fds, num_fds);

	printf("%"PRIu64" samples collected in %"PRIu64" poll events, %"PRIu64" lost samples\n",
		collected_samples,
		ovfl_count, lost_samples);
	return 0;
}
Пример #9
0
int
main(int argc, char **argv)
{
	struct sigaction act;
	uint64_t *val;
	size_t sz, pgsz;
	int ret, i;

	setlocale(LC_ALL, "");

	ret = pfm_initialize();
	if (ret != PFM_SUCCESS)
		errx(1, "Cannot initialize library: %s", pfm_strerror(ret));

	pgsz = sysconf(_SC_PAGESIZE);

	/*
	 * Install the signal handler (SIGIO)
	 * need SA_SIGINFO because we need the fd
	 * in the signal handler
	 */
	memset(&act, 0, sizeof(act));
	act.sa_sigaction = sigio_handler;
	act.sa_flags = SA_SIGINFO;
	sigaction (SIGIO, &act, 0);

	/*
 	 * allocates fd for us
 	 */
	ret = perf_setup_list_events("cycles,"
				       "instructions",
					&fds, &num_fds);
	if (ret || (num_fds == 0))
		exit(1);

	fds[0].fd = -1;
	for(i=0; i < num_fds; i++) {

		/* want a notification for every each added to the buffer */
		fds[i].hw.disabled = !i;
		if (!i) {
			fds[i].hw.wakeup_events = 1;
			fds[i].hw.sample_type = PERF_SAMPLE_IP|PERF_SAMPLE_READ|PERF_SAMPLE_PERIOD;
			fds[i].hw.sample_period = SMPL_PERIOD;

			/* read() returns event identification for signal handler */
			fds[i].hw.read_format = PERF_FORMAT_GROUP|PERF_FORMAT_ID|PERF_FORMAT_SCALE;
		}

		fds[i].fd = perf_event_open(&fds[i].hw, 0, -1, fds[0].fd, 0);
		if (fds[i].fd == -1)
			err(1, "cannot attach event %s", fds[i].name);
	}
	
	sz = (3+2*num_fds)*sizeof(uint64_t);
	val = malloc(sz);
	if (!val)
		err(1, "cannot allocated memory");
	/*
	 * On overflow, the non lead events are stored in the sample.
	 * However we need some key to figure the order in which they
	 * were laid out in the buffer. The file descriptor does not
	 * work for this. Instead, we extract a unique ID for each event.
	 * That id will be part of the sample for each event value.
	 * Therefore we will be able to match value to events
	 *
	 * PERF_FORMAT_ID: returns unique 64-bit identifier in addition
	 * to event value.
	 */
	ret = read(fds[0].fd, val, sz);
	if (ret == -1)
		err(1, "cannot read id %zu", sizeof(val));

	/*
	 * we are using PERF_FORMAT_GROUP, therefore the structure
	 * of val is as follows:
	 *
	 *      { u64           nr;
	 *        { u64         time_enabled; } && PERF_FORMAT_ENABLED
	 *        { u64         time_running; } && PERF_FORMAT_RUNNING
	 *        { u64         value;                  
	 *          { u64       id;           } && PERF_FORMAT_ID
	 *        }             cntr[nr];               
	 * We are skipping the first 3 values (nr, time_enabled, time_running)
	 * and then for each event we get a pair of values.
	 */ 
	for(i=0; i < num_fds; i++) {
		fds[i].id = val[2*i+1+3];
		printf("%"PRIu64"  %s\n", fds[i].id, fds[i].name);
	}
	 
	fds[0].buf = mmap(NULL, (buffer_pages+1)*pgsz, PROT_READ|PROT_WRITE, MAP_SHARED, fds[0].fd, 0);
	if (fds[0].buf == MAP_FAILED)
		err(1, "cannot mmap buffer");
	
	fds[0].pgmsk = (buffer_pages * pgsz) - 1;

	/*
	 * setup asynchronous notification on the file descriptor
	 */
	ret = fcntl(fds[0].fd, F_SETFL, fcntl(fds[0].fd, F_GETFL, 0) | O_ASYNC);
	if (ret == -1)
		err(1, "cannot set ASYNC");

	/*
 	 * necessary if we want to get the file descriptor for
 	 * which the SIGIO is sent in siginfo->si_fd.
 	 * SA_SIGINFO in itself is not enough
 	 */
	ret = fcntl(fds[0].fd, F_SETSIG, SIGIO);
	if (ret == -1)
		err(1, "cannot setsig");

	/*
	 * get ownership of the descriptor
	 */
	ret = fcntl(fds[0].fd, F_SETOWN, getpid());
	if (ret == -1)
		err(1, "cannot setown");

	/*
	 * enable the group for one period
	 */
	ret = ioctl(fds[0].fd, PERF_EVENT_IOC_REFRESH , 1);
	if (ret == -1)
		err(1, "cannot refresh");

	busyloop();

	ret = ioctl(fds[0].fd, PERF_EVENT_IOC_DISABLE, 1);
	if (ret == -1)
		err(1, "cannot disable");

	/*
	 * destroy our session
	 */
	for(i=0; i < num_fds; i++)
		close(fds[i].fd);

	perf_free_fds(fds, num_fds);
	free(val);

	/* free libpfm resources cleanly */
	pfm_terminate();

	return 0;
}
Пример #10
0
int
parent(char **arg)
{
	perf_event_desc_t *fds = NULL;
	int status, ret, i, num_fds = 0, grp, group_fd;
	int ready[2], go[2];
	char buf;
	pid_t pid;

	go[0] = go[1] = -1;

	if (pfm_initialize() != PFM_SUCCESS)
		errx(1, "libpfm initialization failed");

	for (grp = 0; grp < options.num_groups; grp++) {
		int ret;
		ret = perf_setup_list_events(options.events[grp], &fds, &num_fds);
		if (ret || !num_fds)
			exit(1);
	}

	pid = options.pid;
	if (!pid) {
		ret = pipe(ready);
		if (ret)
			err(1, "cannot create pipe ready");

		ret = pipe(go);
		if (ret)
			err(1, "cannot create pipe go");


		/*
		 * Create the child task
		 */
		if ((pid=fork()) == -1)
			err(1, "Cannot fork process");

		/*
		 * and launch the child code
		 *
		 * The pipe is used to avoid a race condition
		 * between for() and exec(). We need the pid
		 * of the new tak but we want to start measuring
		 * at the first user level instruction. Thus we
		 * need to prevent exec until we have attached
		 * the events.
		 */
		if (pid == 0) {
			close(ready[0]);
			close(go[1]);

			/*
			 * let the parent know we exist
			 */
			close(ready[1]);
			if (read(go[0], &buf, 1) == -1)
				err(1, "unable to read go_pipe");


			exit(child(arg));
		}

		close(ready[1]);
		close(go[0]);

		if (read(ready[0], &buf, 1) == -1)
			err(1, "unable to read child_ready_pipe");

		close(ready[0]);
	}

	for(i=0; i < num_fds; i++) {
		int is_group_leader; /* boolean */

		is_group_leader = perf_is_group_leader(fds, i);
		if (is_group_leader) {
			/* this is the group leader */
			group_fd = -1;
		} else {
			group_fd = fds[fds[i].group_leader].fd;
		}

		/*
		 * create leader disabled with enable_on-exec
		 */
		if (!options.pid) {
			fds[i].hw.disabled = is_group_leader;
			fds[i].hw.enable_on_exec = is_group_leader;
		}

		fds[i].hw.read_format = PERF_FORMAT_SCALE;
		/* request timing information necessary for scaling counts */
		if (is_group_leader && options.format_group)
			fds[i].hw.read_format |= PERF_FORMAT_GROUP;

		if (options.inherit)
			fds[i].hw.inherit = 1;

		if (options.pin && is_group_leader)
			fds[i].hw.pinned = 1;
		fds[i].fd = perf_event_open(&fds[i].hw, pid, -1, group_fd, 0);
		if (fds[i].fd == -1) {
			warn("cannot attach event%d %s", i, fds[i].name);
			goto error;
		}
	}

	if (!options.pid && go[1] > -1)
		close(go[1]);

	if (options.print) {
		if (!options.pid) {
			while(waitpid(pid, &status, WNOHANG) == 0) {
				sleep(1);
				print_counts(fds, num_fds);
			}
		} else {
			while(quit == 0) {
				sleep(1);
				print_counts(fds, num_fds);
			}
		}
	} else {
		if (!options.pid)
			waitpid(pid, &status, 0);
		else
			pause();
		print_counts(fds, num_fds);
	}

	for(i=0; i < num_fds; i++)
		close(fds[i].fd);

	perf_free_fds(fds, num_fds);

	/* free libpfm resources cleanly */
	pfm_terminate();

	return 0;
error:
	free(fds);
	if (!options.pid)
		kill(SIGKILL, pid);

	/* free libpfm resources cleanly */
	pfm_terminate();

	return -1;
}