Ejemplo n.º 1
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));
		}
	}
}
Ejemplo n.º 2
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");

}
Ejemplo n.º 3
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;
}