Skip to content
Snippets Groups Projects
builtin-report.c 23.8 KiB
Newer Older
  • Learn to ignore specific revisions
  • 	fprintf(fp, "\n");
    
    	fprintf(fp, "# ........");
    
    	list_for_each_entry(se, &hist_entry__sort_list, list) {
    
    		int i;
    
    		fprintf(fp, " ");
    		for (i = 0; i < strlen(se->header); i++)
    			fprintf(fp, ".");
    
    	for (nd = rb_first(&output_hists); nd; nd = rb_next(nd)) {
    		pos = rb_entry(nd, struct hist_entry, rb_node);
    		ret += hist_entry__fprintf(fp, pos, total_samples);
    
    static int __cmd_report(void)
    
    {
    	unsigned long offset = 0;
    	unsigned long head = 0;
    	struct stat stat;
    	char *buf;
    	event_t *event;
    	int ret, rc = EXIT_FAILURE;
    
    	uint32_t size;
    
    	unsigned long total = 0, total_mmap = 0, total_comm = 0, total_unknown = 0;
    
    
    	input = open(input_name, O_RDONLY);
    	if (input < 0) {
    		perror("failed to open file");
    		exit(-1);
    	}
    
    	ret = fstat(input, &stat);
    	if (ret < 0) {
    		perror("failed to stat file");
    		exit(-1);
    	}
    
    	if (!stat.st_size) {
    		fprintf(stderr, "zero-sized file, nothing to do!\n");
    		exit(0);
    	}
    
    
    	if (load_kernel() < 0) {
    
    		perror("failed to open kallsyms");
    		return EXIT_FAILURE;
    	}
    
    remap:
    	buf = (char *)mmap(NULL, page_size * mmap_window, PROT_READ,
    			   MAP_SHARED, input, offset);
    	if (buf == MAP_FAILED) {
    		perror("failed to mmap file");
    		exit(-1);
    	}
    
    more:
    	event = (event_t *)(buf + head);
    
    
    	size = event->header.size;
    	if (!size)
    		size = 8;
    
    
    	if (head + event->header.size >= page_size * mmap_window) {
    		unsigned long shift = page_size * (head / page_size);
    		int ret;
    
    		ret = munmap(buf, page_size * mmap_window);
    		assert(ret == 0);
    
    		offset += shift;
    		head -= shift;
    		goto remap;
    	}
    
    
    	size = event->header.size;
    	if (!size)
    		goto broken_event;
    
    
    	if (event->header.misc & PERF_EVENT_MISC_OVERFLOW) {
    		char level;
    		int show = 0;
    		struct dso *dso = NULL;
    		struct thread *thread = threads__findnew(event->ip.pid);
    
    		uint64_t ip = event->ip.ip;
    
    		struct map *map = NULL;
    
    		if (dump_trace) {
    
    			fprintf(stderr, "%p [%p]: PERF_EVENT (IP, %d): %d: %p\n",
    				(void *)(offset + head),
    				(void *)(long)(event->header.size),
    
    				event->header.misc,
    				event->ip.pid,
    
    			fprintf(stderr, "problem processing %d event, skipping it.\n",
    
    
    		if (event->header.misc & PERF_EVENT_MISC_KERNEL) {
    			show = SHOW_KERNEL;
    			level = 'k';
    
    		} else if (event->header.misc & PERF_EVENT_MISC_USER) {
    
    
    			map = thread__find_map(thread, ip);
    
    			if (map != NULL) {
    
    				ip -= map->start + map->pgoff;
    			}
    
    			struct symbol *sym = dso__find_symbol(dso, ip);
    
    			if (hist_entry__add(thread, map, dso, sym, ip, level)) {
    				fprintf(stderr,
    
    		"problem incrementing symbol count, skipping event\n");
    				goto broken_event;
    
    		}
    		total++;
    	} else switch (event->header.type) {
    	case PERF_EVENT_MMAP: {
    		struct thread *thread = threads__findnew(event->mmap.pid);
    		struct map *map = map__new(&event->mmap);
    
    
    		if (dump_trace) {
    
    			fprintf(stderr, "%p [%p]: PERF_EVENT_MMAP: [%p(%p) @ %p]: %s\n",
    				(void *)(offset + head),
    				(void *)(long)(event->header.size),
    
    				(void *)(long)event->mmap.start,
    				(void *)(long)event->mmap.len,
    				(void *)(long)event->mmap.pgoff,
    
    				event->mmap.filename);
    		}
    
    		if (thread == NULL || map == NULL) {
    
    			fprintf(stderr, "problem processing PERF_EVENT_MMAP, skipping event.\n");
    			goto broken_event;
    
    		total_mmap++;
    
    		break;
    	}
    	case PERF_EVENT_COMM: {
    		struct thread *thread = threads__findnew(event->comm.pid);
    
    
    		if (dump_trace) {
    
    			fprintf(stderr, "%p [%p]: PERF_EVENT_COMM: %s:%d\n",
    				(void *)(offset + head),
    				(void *)(long)(event->header.size),
    
    				event->comm.comm, event->comm.pid);
    		}
    
    		    thread__set_comm(thread, event->comm.comm)) {
    
    			fprintf(stderr, "problem processing PERF_EVENT_COMM, skipping event.\n");
    			goto broken_event;
    
    		total_comm++;
    
    		if (dump_trace)
    			fprintf(stderr, "%p [%p]: skipping unknown header type: %d\n",
    					(void *)(offset + head),
    					(void *)(long)(event->header.size),
    					event->header.type);
    
    
    		total_unknown++;
    
    
    		/*
    		 * assume we lost track of the stream, check alignment, and
    		 * increment a single u64 in the hope to catch on again 'soon'.
    		 */
    
    		if (unlikely(head & 7))
    			head &= ~7ULL;
    
    		size = 8;
    
    	if (offset + head < stat.st_size)
    		goto more;
    
    	rc = EXIT_SUCCESS;
    	close(input);
    
    		fprintf(stderr, "      IP events: %10ld\n", total);
    		fprintf(stderr, "    mmap events: %10ld\n", total_mmap);
    		fprintf(stderr, "    comm events: %10ld\n", total_comm);
    		fprintf(stderr, " unknown events: %10ld\n", total_unknown);
    
    	output__resort();
    	output__fprintf(stdout, total);
    
    static const char * const report_usage[] = {
    	"perf report [<options>] <command>",
    	NULL
    };
    
    static const struct option options[] = {
    	OPT_STRING('i', "input", &input_name, "file",
    		    "input file name"),
    
    	OPT_BOOLEAN('v', "verbose", &verbose,
    		    "be more verbose (show symbol address, etc)"),
    
    	OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
    		    "dump raw trace in ASCII"),
    
    	OPT_STRING('k', "vmlinux", &vmlinux, "file", "vmlinux pathname"),
    
    	OPT_STRING('s', "sort", &sort_order, "foo", "bar"),
    
    	OPT_END()
    };
    
    int cmd_report(int argc, const char **argv, const char *prefix)
    {
    	elf_version(EV_CURRENT);
    
    	page_size = getpagesize();
    
    	parse_options(argc, argv, options, report_usage, 0);
    
    
    	return __cmd_report();
    }