Skip to content
Snippets Groups Projects
builtin-report.c 24.1 KiB
Newer Older
  • Learn to ignore specific revisions
  • 
    	if (thread == NULL || map == NULL) {
    		dprintf("problem processing PERF_EVENT_MMAP, skipping event.\n");
    
    	}
    
    	thread__insert_map(thread, map);
    	total_mmap++;
    
    	return 0;
    }
    
    static int
    process_comm_event(event_t *event, unsigned long offset, unsigned long head)
    {
    	struct thread *thread = threads__findnew(event->comm.pid);
    
    	dprintf("%p [%p]: PERF_EVENT_COMM: %s:%d\n",
    		(void *)(offset + head),
    		(void *)(long)(event->header.size),
    		event->comm.comm, event->comm.pid);
    
    	if (thread == NULL ||
    	    thread__set_comm(thread, event->comm.comm)) {
    		dprintf("problem processing PERF_EVENT_COMM, skipping event.\n");
    		return -1;
    
    static int
    process_fork_event(event_t *event, unsigned long offset, unsigned long head)
    {
    	struct thread *thread = threads__findnew(event->fork.pid);
    	struct thread *parent = threads__findnew(event->fork.ppid);
    
    	dprintf("%p [%p]: PERF_EVENT_FORK: %d:%d\n",
    		(void *)(offset + head),
    		(void *)(long)(event->header.size),
    		event->fork.pid, event->fork.ppid);
    
    	if (!thread || !parent || thread__fork(thread, parent)) {
    		dprintf("problem processing PERF_EVENT_FORK, skipping event.\n");
    		return -1;
    	}
    	total_fork++;
    
    	return 0;
    }
    
    
    static int
    process_event(event_t *event, unsigned long offset, unsigned long head)
    {
    	if (event->header.misc & PERF_EVENT_MISC_OVERFLOW)
    		return process_overflow_event(event, offset, head);
    
    	switch (event->header.type) {
    	case PERF_EVENT_MMAP:
    		return process_mmap_event(event, offset, head);
    
    	case PERF_EVENT_COMM:
    		return process_comm_event(event, offset, head);
    
    
    	case PERF_EVENT_FORK:
    		return process_fork_event(event, offset, head);
    
    
    	/*
    	 * We dont process them right now but they are fine:
    	 */
    
    	case PERF_EVENT_PERIOD:
    	case PERF_EVENT_THROTTLE:
    	case PERF_EVENT_UNTHROTTLE:
    		return 0;
    
    
    	default:
    		return -1;
    	}
    
    	return 0;
    }
    
    static int __cmd_report(void)
    {
    
    	int ret, rc = EXIT_FAILURE;
    
    	unsigned long offset = 0;
    	unsigned long head = 0;
    	struct stat stat;
    	event_t *event;
    	uint32_t size;
    
    
    	register_idle_thread();
    
    	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 load kernel symbols");
    		return EXIT_FAILURE;
    	}
    
    	if (!full_paths) {
    		if (getcwd(__cwd, sizeof(__cwd)) == NULL) {
    			perror("failed to get the current directory");
    			return EXIT_FAILURE;
    		}
    		cwdlen = strlen(cwd);
    	} else {
    		cwd = NULL;
    		cwdlen = 0;
    	}
    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 || process_event(event, offset, head) < 0) {
    
    
    		dprintf("%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);
    
    	dprintf("      IP events: %10ld\n", total);
    	dprintf("    mmap events: %10ld\n", total_mmap);
    	dprintf("    comm events: %10ld\n", total_comm);
    
    	dprintf("    fork events: %10ld\n", total_fork);
    
    	dprintf(" unknown events: %10ld\n", total_unknown);
    
    	if (dump_trace)
    
    	collapse__resort();
    
    	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, "key[,key2...]",
    		   "sort by key(s): pid, comm, dso, symbol. Default: pid,symbol"),
    
    	OPT_BOOLEAN('P', "full-paths", &full_paths,
    		    "Don't shorten the pathnames taking into account the cwd"),
    
    static void setup_sorting(void)
    {
    	char *tmp, *tok, *str = strdup(sort_order);
    
    	for (tok = strtok_r(str, ", ", &tmp);
    			tok; tok = strtok_r(NULL, ", ", &tmp)) {
    		if (sort_dimension__add(tok) < 0) {
    			error("Unknown --sort key: `%s'", tok);
    			usage_with_options(report_usage, options);
    		}
    	}
    
    	free(str);
    }
    
    
    int cmd_report(int argc, const char **argv, const char *prefix)
    {
    
    
    	page_size = getpagesize();
    
    
    	argc = parse_options(argc, argv, options, report_usage, 0);
    
    	/*
    	 * Any (unrecognized) arguments left?
    	 */
    	if (argc)
    		usage_with_options(report_usage, options);
    
    
    	return __cmd_report();
    }