 5b68164d6a
			
		
	
	
	5b68164d6a
	
	
	
		
			
			This patch adds a new branch sampling type support for indirect jumps:
  perf record -j ind_jmp .......
It enables analysis of indirect jumps targets. It requires kernel and
possibly hardware support to operate correctly.
Signed-off-by: Stephane Eranian <eranian@google.com>
[ Fixup against: f00898f4e2 (perf tools: Move branch option parsing to own file) ]
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Andi Kleen <ak@linux.intel.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: acme@redhat.com
Cc: dsahern@gmail.com
Cc: jolsa@redhat.com
Cc: kan.liang@intel.com
Cc: namhyung@kernel.org
Link: http://lkml.kernel.org/r/1431637800-31061-4-git-send-email-eranian@google.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
		
	
			
		
			
				
	
	
		
			94 lines
		
	
	
	
		
			1.9 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			94 lines
		
	
	
	
		
			1.9 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
| #include "perf.h"
 | |
| #include "util/util.h"
 | |
| #include "util/debug.h"
 | |
| #include "util/parse-options.h"
 | |
| #include "util/parse-branch-options.h"
 | |
| 
 | |
| #define BRANCH_OPT(n, m) \
 | |
| 	{ .name = n, .mode = (m) }
 | |
| 
 | |
| #define BRANCH_END { .name = NULL }
 | |
| 
 | |
| struct branch_mode {
 | |
| 	const char *name;
 | |
| 	int mode;
 | |
| };
 | |
| 
 | |
| static const struct branch_mode branch_modes[] = {
 | |
| 	BRANCH_OPT("u", PERF_SAMPLE_BRANCH_USER),
 | |
| 	BRANCH_OPT("k", PERF_SAMPLE_BRANCH_KERNEL),
 | |
| 	BRANCH_OPT("hv", PERF_SAMPLE_BRANCH_HV),
 | |
| 	BRANCH_OPT("any", PERF_SAMPLE_BRANCH_ANY),
 | |
| 	BRANCH_OPT("any_call", PERF_SAMPLE_BRANCH_ANY_CALL),
 | |
| 	BRANCH_OPT("any_ret", PERF_SAMPLE_BRANCH_ANY_RETURN),
 | |
| 	BRANCH_OPT("ind_call", PERF_SAMPLE_BRANCH_IND_CALL),
 | |
| 	BRANCH_OPT("abort_tx", PERF_SAMPLE_BRANCH_ABORT_TX),
 | |
| 	BRANCH_OPT("in_tx", PERF_SAMPLE_BRANCH_IN_TX),
 | |
| 	BRANCH_OPT("no_tx", PERF_SAMPLE_BRANCH_NO_TX),
 | |
| 	BRANCH_OPT("cond", PERF_SAMPLE_BRANCH_COND),
 | |
| 	BRANCH_OPT("ind_jmp", PERF_SAMPLE_BRANCH_IND_JUMP),
 | |
| 	BRANCH_END
 | |
| };
 | |
| 
 | |
| int
 | |
| parse_branch_stack(const struct option *opt, const char *str, int unset)
 | |
| {
 | |
| #define ONLY_PLM \
 | |
| 	(PERF_SAMPLE_BRANCH_USER	|\
 | |
| 	 PERF_SAMPLE_BRANCH_KERNEL	|\
 | |
| 	 PERF_SAMPLE_BRANCH_HV)
 | |
| 
 | |
| 	uint64_t *mode = (uint64_t *)opt->value;
 | |
| 	const struct branch_mode *br;
 | |
| 	char *s, *os = NULL, *p;
 | |
| 	int ret = -1;
 | |
| 
 | |
| 	if (unset)
 | |
| 		return 0;
 | |
| 
 | |
| 	/*
 | |
| 	 * cannot set it twice, -b + --branch-filter for instance
 | |
| 	 */
 | |
| 	if (*mode)
 | |
| 		return -1;
 | |
| 
 | |
| 	/* str may be NULL in case no arg is passed to -b */
 | |
| 	if (str) {
 | |
| 		/* because str is read-only */
 | |
| 		s = os = strdup(str);
 | |
| 		if (!s)
 | |
| 			return -1;
 | |
| 
 | |
| 		for (;;) {
 | |
| 			p = strchr(s, ',');
 | |
| 			if (p)
 | |
| 				*p = '\0';
 | |
| 
 | |
| 			for (br = branch_modes; br->name; br++) {
 | |
| 				if (!strcasecmp(s, br->name))
 | |
| 					break;
 | |
| 			}
 | |
| 			if (!br->name) {
 | |
| 				ui__warning("unknown branch filter %s,"
 | |
| 					    " check man page\n", s);
 | |
| 				goto error;
 | |
| 			}
 | |
| 
 | |
| 			*mode |= br->mode;
 | |
| 
 | |
| 			if (!p)
 | |
| 				break;
 | |
| 
 | |
| 			s = p + 1;
 | |
| 		}
 | |
| 	}
 | |
| 	ret = 0;
 | |
| 
 | |
| 	/* default to any branch */
 | |
| 	if ((*mode & ~ONLY_PLM) == 0) {
 | |
| 		*mode = PERF_SAMPLE_BRANCH_ANY;
 | |
| 	}
 | |
| error:
 | |
| 	free(os);
 | |
| 	return ret;
 | |
| }
 |