static int
perf_display_stack_user(perf_event_desc_t *hw, FILE *fp)
{
	uint64_t nr;
	char buf[512];
	size_t sz;
	int ret;

	ret = perf_read_buffer(hw, &nr, sizeof(nr));
	if (ret)
		errx(1, "cannot user stack size");

	fprintf(fp, "USER_STACK: SZ:%"PRIu64"\n", nr);

	/* consume content */
	while (nr) {
		sz = nr;
		if (sz > sizeof(buf))
			sz = sizeof(buf);

		ret = perf_read_buffer(hw, buf, sz);
		if (ret)
			errx(1, "cannot user stack content");
		nr -= sz;
	}

	return 0;
}
static int
perf_display_branch_stack(perf_event_desc_t *desc, FILE *fp)
{
	struct perf_branch_entry b;
	uint64_t nr, n;
	int ret;

	ret = perf_read_buffer(desc, &n, sizeof(n));
	if (ret)
		errx(1, "cannot read branch stack nr");

	fprintf(fp, "\n\tBRANCH_STACK:%"PRIu64"\n", n);
	nr = n;
	/*
	 * from most recent to least recent take branch
	 */
	while (nr--) {
		ret = perf_read_buffer(desc, &b, sizeof(b));
		if (ret)
			errx(1, "cannot read branch stack entry");

		fprintf(fp, "\tFROM:0x%016"PRIx64" TO:0x%016"PRIx64" MISPRED:%c\n",
			b.from,
			b.to,
			!(b.mispred || b.predicted) ? '-':
			(b.mispred ? 'Y' :'N'));
	}
	return (int)(n * sizeof(b) + sizeof(n));
}
uint64_t
display_lost(perf_event_desc_t *hw, perf_event_desc_t *fds, int num_fds, FILE *fp)
{
	struct { uint64_t id, lost; } lost;
	const char *str;
	int e, ret;

	ret = perf_read_buffer(hw, &lost, sizeof(lost));
	if (ret) {
		warnx("cannot read lost info");
		return 0;
	}

	e = perf_id2event(fds, num_fds, lost.id);
	if (e == -1)
		str = "unknown lost event";
	else
		str = fds[e].name;

	fprintf(fp, "<<<LOST %"PRIu64" SAMPLES FOR EVENT %s>>>\n",
		lost.lost,
		str);

	return lost.lost;
}
Exemple #4
0
static void
display_exit(perf_event_desc_t *hw)
{
	struct { pid_t pid, ppid, tid, ptid; } grp;
	int ret;

	ret = perf_read_buffer(hw->buf, hw->pgmsk, &grp, sizeof(grp));
	if (ret)
		errx(1, "cannot read exit info");

	printf("[%d] exited\n", grp.pid);
}
Exemple #5
0
static void
display_freq(int mode, perf_event_desc_t *hw)
{
	struct { uint64_t time, id, stream_id; } thr;
	int ret;

	ret = perf_read_buffer(hw->buf, hw->pgmsk, &thr, sizeof(thr));
	if (ret)
		errx(1, "cannot read throttling info");

	printf("%s value=%"PRIu64" event ID=%"PRIu64"\n", mode ? "Throttled" : "Unthrottled", thr.id, thr.stream_id);
}
void
display_exit(perf_event_desc_t *hw, FILE *fp)
{
	struct { pid_t pid, ppid, tid, ptid; } grp;
	int ret;

	ret = perf_read_buffer(hw, &grp, sizeof(grp));
	if (ret) {
		warnx("cannot read exit info");
		return;
	}

	fprintf(fp,"[%d] exited\n", grp.pid);
}
Exemple #7
0
static void
sigio_handler(int n, siginfo_t *info, void *uc)
{
	struct perf_event_header ehdr;
	int ret, id;
	
	/*
	 * positive si_code indicate kernel generated signal
	 * which is normal for SIGIO
	 */
	if (info->si_code < 0)
		errx(1, "signal not generated by kernel");

	/*
	 * SIGPOLL = SIGIO
	 * expect POLL_HUP instead of POLL_IN because we are
	 * in one-shot mode (IOC_REFRESH)
	 */
	if (info->si_code != POLL_HUP)
		errx(1, "signal not generated by SIGIO");

	id = perf_fd2event(fds, num_fds, info->si_fd);
	if (id == -1)
		errx(1, "no event associated with fd=%d", info->si_fd);

	ret = perf_read_buffer(fds+id, &ehdr, sizeof(ehdr));
	if (ret)
		errx(1, "cannot read event header");

	if (ehdr.type != PERF_RECORD_SAMPLE) {
		warnx("unexpected sample type=%d, skipping\n", ehdr.type);
		perf_skip_buffer(fds+id, ehdr.size);
		goto skip;
	}
	printf("Notification:%lu ", notification_received);
	ret = perf_display_sample(fds, num_fds, 0, &ehdr, stdout);
	/*
	 * increment our notification counter
	 */
	notification_received++;
skip:
	/*
	 * rearm the counter for one more shot
	 */
	ret = ioctl(info->si_fd, PERF_EVENT_IOC_REFRESH, 1);
	if (ret == -1)
		err(1, "cannot refresh");

}
static size_t
__perf_handle_raw(perf_event_desc_t *hw)
{
	size_t sz = 0;
	uint32_t raw_sz, i;
	char *buf;
	int ret;

	ret = perf_read_buffer_32(hw, &raw_sz);
	if (ret) {
		warnx("cannot read raw size");
		return -1;
	}

	sz += sizeof(raw_sz);

	printf("\n\tRAWSZ:%u\n", raw_sz);

	buf = malloc(raw_sz);
	if (!buf) {
		warn("cannot allocate raw buffer");
		return -1;
	}


	ret = perf_read_buffer(hw, buf, raw_sz);
	if (ret) {
		warnx("cannot read raw data");
		free(buf);
		return -1;
	}

	if (raw_sz)
		putchar('\t');

	for(i=0; i < raw_sz; i++) {
		printf("0x%02x ", buf[i] & 0xff );
		if (((i+1) % 16)  == 0)
			printf("\n\t");
	}
	if (raw_sz)
		putchar('\n');

	free(buf);

	return sz + raw_sz;
}
void
display_freq(int mode, perf_event_desc_t *hw, FILE *fp)
{
	struct { uint64_t time, id, stream_id; } thr;
	int ret;

	ret = perf_read_buffer(hw, &thr, sizeof(thr));
	if (ret) {
		warnx("cannot read throttling info");
		return;
	}

	fprintf(fp, "%s value=%"PRIu64" event ID=%"PRIu64"\n",
		mode ? "Throttled" : "Unthrottled",
		thr.id,
		thr.stream_id);
}
Exemple #10
0
static void
display_lost(perf_event_desc_t *hw)
{
	struct { uint64_t id, lost; } lost;
	const char *str;
	int e, ret;

	ret = perf_read_buffer(hw->buf, hw->pgmsk, &lost, sizeof(lost));
	if (ret)
		errx(1, "cannot read lost info");

	e = perf_id2event(fds, num_fds, lost.id);
	if (e == -1)
		str = "unknown lost event";
	else
		str = fds[e].name;

	printf("<<<LOST %"PRIu64" SAMPLES FOR EVENT %s>>>\n", lost.lost, str);
	lost_samples += lost.lost;
}
Exemple #11
0
static void
process_smpl_buf(perf_event_desc_t *hw)
{
	struct perf_event_header ehdr;
	int ret;

	for(;;) {
		ret = perf_read_buffer(hw, &ehdr, sizeof(ehdr));
		if (ret)
			return; /* nothing to read */

		if (options.opt_no_show) {
			perf_skip_buffer(hw, ehdr.size - sizeof(ehdr));
			continue;
		}

		switch(ehdr.type) {
			case PERF_RECORD_SAMPLE:
				collected_samples++;
				ret = perf_display_sample(fds, num_fds, hw - fds, &ehdr, options.output_file);
				if (ret)
					errx(1, "cannot parse sample");
				break;
			case PERF_RECORD_EXIT:
				display_exit(hw, options.output_file);
				break;
			case PERF_RECORD_LOST:
				lost_samples += display_lost(hw, fds, num_fds, options.output_file);
				break;
			case PERF_RECORD_THROTTLE:
				display_freq(1, hw, options.output_file);
				break;
			case PERF_RECORD_UNTHROTTLE:
				display_freq(0, hw, options.output_file);
				break;
			default:
				printf("unknown sample type %d\n", ehdr.type);
				perf_skip_buffer(hw, ehdr.size - sizeof(ehdr));
		}
	}
}
Exemple #12
0
static void
process_smpl_buf(perf_event_desc_t *hw)
{
	struct perf_event_header ehdr;
	int ret;

	for(;;) {
		ret = perf_read_buffer(hw->buf, hw->pgmsk, &ehdr, sizeof(ehdr));
		if (ret)
			return; /* nothing to read */

		switch(ehdr.type) {
			case PERF_RECORD_SAMPLE:
				ret = perf_display_sample(fds, num_fds, hw - fds, &ehdr, stdout);
				if (ret)
					errx(1, "cannot parse sample");
				collected_samples++;
				break;
			case PERF_RECORD_EXIT:
				display_exit(hw);
				break;
			case PERF_RECORD_LOST:
				display_lost(hw);
				break;
			case PERF_RECORD_THROTTLE:
				display_freq(1, hw);
				break;
			case PERF_RECORD_UNTHROTTLE:
				display_freq(0, hw);
				break;
			default:
				printf("unknown sample type %d\n", ehdr.type);
				perf_skip_buffer(hw->buf, ehdr.size - sizeof(ehdr));
		}
	}
}
int
perf_display_sample(perf_event_desc_t *fds, int num_fds, int idx, struct perf_event_header *ehdr, FILE *fp)
{
	perf_event_desc_t *hw;
	struct { uint32_t pid, tid; } pid;
	struct { uint64_t value, id; } grp;
	uint64_t time_enabled, time_running;
	size_t sz;
	uint64_t type, fmt;
	uint64_t val64;
	const char *str;
	int ret, e;

	if (!fds || !fp || !ehdr  || num_fds < 0 || idx < 0 ||  idx >= num_fds)
		return -1;

	sz = ehdr->size - sizeof(*ehdr);

	hw = fds+idx;

	type = hw->hw.sample_type;
	fmt  = hw->hw.read_format;

	/*
	 * the sample_type information is laid down
	 * based on the PERF_RECORD_SAMPLE format specified
	 * in the perf_event.h header file.
	 * That order is different from the enum perf_event_sample_format
	 */
	if (type & PERF_SAMPLE_IP) {
		const char *xtra = " ";
		ret = perf_read_buffer_64(hw, &val64);
		if (ret) {
			warnx("cannot read IP");
			return -1;
		}

		/*
		 * MISC_EXACT_IP indicates that kernel is returning
		 * th  IIP of an instruction which caused the event, i.e.,
		 * no skid
		 */
		if (hw->hw.precise_ip && (ehdr->misc & PERF_RECORD_MISC_EXACT_IP))
			xtra = " (exact) ";

		fprintf(fp, "IIP:%#016"PRIx64"%s", val64, xtra);
		sz -= sizeof(val64);
	}

	if (type & PERF_SAMPLE_TID) {
		ret = perf_read_buffer(hw, &pid, sizeof(pid));
		if (ret) {
			warnx( "cannot read PID");
			return -1;
		}

		fprintf(fp, "PID:%d TID:%d ", pid.pid, pid.tid);
		sz -= sizeof(pid);
	}

	if (type & PERF_SAMPLE_TIME) {
		ret = perf_read_buffer_64(hw, &val64);
		if (ret) {
			warnx( "cannot read time");
			return -1;
		}

		fprintf(fp, "TIME:%'"PRIu64" ", val64);
		sz -= sizeof(val64);
	}

	if (type & PERF_SAMPLE_ADDR) {
		ret = perf_read_buffer_64(hw, &val64);
		if (ret) {
			warnx( "cannot read addr");
			return -1;
		}

		fprintf(fp, "ADDR:%#016"PRIx64" ", val64);
		sz -= sizeof(val64);
	}

	if (type & PERF_SAMPLE_ID) {
		ret = perf_read_buffer_64(hw, &val64);
		if (ret) {
			warnx( "cannot read id");
			return -1;
		}

		fprintf(fp, "ID:%"PRIu64" ", val64);
		sz -= sizeof(val64);
	}

	if (type & PERF_SAMPLE_STREAM_ID) {
		ret = perf_read_buffer_64(hw, &val64);
		if (ret) {
			warnx( "cannot read stream_id");
			return -1;
		}
		fprintf(fp, "STREAM_ID:%"PRIu64" ", val64);
		sz -= sizeof(val64);
	}

	if (type & PERF_SAMPLE_CPU) {
		struct { uint32_t cpu, reserved; } cpu;
		ret = perf_read_buffer(hw, &cpu, sizeof(cpu));
		if (ret) {
			warnx( "cannot read cpu");
			return -1;
		}
		fprintf(fp, "CPU:%u ", cpu.cpu);
		sz -= sizeof(cpu);
	}

	if (type & PERF_SAMPLE_PERIOD) {
		ret = perf_read_buffer_64(hw, &val64);
		if (ret) {
			warnx( "cannot read period");
			return -1;
		}
		fprintf(fp, "PERIOD:%'"PRIu64" ", val64);
		sz -= sizeof(val64);
	}

	/* struct read_format {
	 * 	{ u64		value;
	 * 	  { u64		time_enabled; } && PERF_FORMAT_ENABLED
	 * 	  { u64		time_running; } && PERF_FORMAT_RUNNING
	 * 	  { u64		id;           } && PERF_FORMAT_ID
	 * 	} && !PERF_FORMAT_GROUP
	 *
	 * 	{ u64		nr;
	 * 	  { u64		time_enabled; } && PERF_FORMAT_ENABLED
	 * 	  { u64		time_running; } && PERF_FORMAT_RUNNING
	 * 	  { u64		value;
	 * 	    { u64	id;           } && PERF_FORMAT_ID
	 * 	  }		cntr[nr];
	 * 	} && PERF_FORMAT_GROUP
	 * };
	 */
	if (type & PERF_SAMPLE_READ) {
		uint64_t values[3];
		uint64_t nr;

		if (fmt & PERF_FORMAT_GROUP) {
			ret = perf_read_buffer_64(hw, &nr);
			if (ret) {
				warnx( "cannot read nr");
				return -1;
			}

			sz -= sizeof(nr);

			time_enabled = time_running = 1;

			if (fmt & PERF_FORMAT_TOTAL_TIME_ENABLED) {
				ret = perf_read_buffer_64(hw, &time_enabled);
				if (ret) {
					warnx( "cannot read timing info");
					return -1;
				}
				sz -= sizeof(time_enabled);
			}

			if (fmt & PERF_FORMAT_TOTAL_TIME_RUNNING) {
				ret = perf_read_buffer_64(hw, &time_running);
				if (ret) {
					warnx( "cannot read timing info");
					return -1;
				}
				sz -= sizeof(time_running);
			}

			fprintf(fp, "ENA=%'"PRIu64" RUN=%'"PRIu64" NR=%"PRIu64"\n", time_enabled, time_running, nr);

			values[1] = time_enabled;
			values[2] = time_running;
			while(nr--) {
				grp.id = -1;
				ret = perf_read_buffer_64(hw, &grp.value);
				if (ret) {
					warnx( "cannot read group value");
					return -1;
				}
				sz -= sizeof(grp.value);

				if (fmt & PERF_FORMAT_ID) {
					ret = perf_read_buffer_64(hw, &grp.id);
					if (ret) {
						warnx( "cannot read leader id");
						return -1;
					}
					sz -= sizeof(grp.id);
				}

				e = perf_id2event(fds, num_fds, grp.id);
				if (e == -1)
					str = "unknown sample event";
				else
					str = fds[e].name;

				values[0] = grp.value;
				grp.value = perf_scale(values);

				fprintf(fp, "\t%'"PRIu64" %s (%"PRIu64"%s)\n",
					grp.value, str,
					grp.id,
					time_running != time_enabled ? ", scaled":"");

			}
		} else {
			time_enabled = time_running = 0;
			/*
			 * this program does not use FORMAT_GROUP when there is only one event
			 */
			ret = perf_read_buffer_64(hw, &val64);
			if (ret) {
				warnx( "cannot read value");
				return -1;
			}
			sz -= sizeof(val64);

			if (fmt & PERF_FORMAT_TOTAL_TIME_ENABLED) {
				ret = perf_read_buffer_64(hw, &time_enabled);
				if (ret) {
					warnx( "cannot read timing info");
					return -1;
				}
				sz -= sizeof(time_enabled);
			}

			if (fmt & PERF_FORMAT_TOTAL_TIME_RUNNING) {
				ret = perf_read_buffer_64(hw, &time_running);
				if (ret) {
					warnx( "cannot read timing info");
					return -1;
				}
				sz -= sizeof(time_running);
			}
			if (fmt & PERF_FORMAT_ID) {
				ret = perf_read_buffer_64(hw, &val64);
				if (ret) {
					warnx( "cannot read leader id");
					return -1;
				}
				sz -= sizeof(val64);
			}

			fprintf(fp, "ENA=%'"PRIu64" RUN=%'"PRIu64"\n", time_enabled, time_running);

			values[0] = val64;
			values[1] = time_enabled;
			values[2] = time_running;
			val64 = perf_scale(values);

			fprintf(fp, "\t%'"PRIu64" %s %s\n",
				val64, fds[0].name,
				time_running != time_enabled ? ", scaled":"");
		}
	}

	if (type & PERF_SAMPLE_CALLCHAIN) {
		uint64_t nr, ip;

		ret = perf_read_buffer_64(hw, &nr);
		if (ret) {
			warnx( "cannot read callchain nr");
			return -1;
		}
		sz -= sizeof(nr);

		while(nr--) {
			ret = perf_read_buffer_64(hw, &ip);
			if (ret) {
				warnx( "cannot read ip");
				return -1;
			}

			sz -= sizeof(ip);

			fprintf(fp, "\t0x%"PRIx64"\n", ip);
		}
	}

	if (type & PERF_SAMPLE_RAW) {
		ret = __perf_handle_raw(hw);
		if (ret == -1)
			return -1;
		sz -= ret;
	}

	if (type & PERF_SAMPLE_BRANCH_STACK) {
		ret = perf_display_branch_stack(hw, fp);
		sz -= ret;
	}

	if (type & PERF_SAMPLE_REGS_USER) {
		ret = perf_display_regs_user(hw, fp);
		sz -= ret;
	}

	if (type & PERF_SAMPLE_STACK_USER) {
		ret = perf_display_stack_user(hw, fp);
		sz -= ret;
	}

	if (type & PERF_SAMPLE_WEIGHT) {
		ret = perf_read_buffer_64(hw, &val64);
		if (ret) {
			warnx( "cannot read weight");
			return -1;
		}
		fprintf(fp, "WEIGHT:%'"PRIu64" ", val64);
		sz -= sizeof(val64);
	}

	if (type & PERF_SAMPLE_DATA_SRC) {
		ret = perf_read_buffer_64(hw, &val64);
		if (ret) {
			warnx( "cannot read data src");
			return -1;
		}
		fprintf(fp, "DATA_SRC:%'"PRIu64" ", val64);
		sz -= sizeof(val64);
	}

	/*
	 * if we have some data left, it is because there is more
	 * than what we know about. In fact, it is more complicated
	 * because we may have the right size but wrong layout. But
	 * that's the best we can do.
	 */
	if (sz) {
		warnx("did not correctly parse sample leftover=%zu", sz);
		perf_skip_buffer(hw, sz);
	}

	fputc('\n',fp);
	return 0;
}