3083 lines · 77.7 KB · C
RawDownload
#include "builtin.h" #include "perf.h"#include "util/cache.h"#include "util/debug.h"#include <subcmd/exec-cmd.h>#include "util/header.h"#include <subcmd/parse-options.h>#include "util/perf_regs.h"#include "util/session.h"#include "util/tool.h"#include "util/symbol.h"#include "util/thread.h"#include "util/trace-event.h"#include "util/util.h"#include "util/evlist.h"#include "util/evsel.h"#include "util/sort.h"#include "util/data.h"#include "util/auxtrace.h"#include "util/cpumap.h"#include "util/thread_map.h"#include "util/stat.h"#include "util/string2.h"#include "util/thread-stack.h"#include "util/time-utils.h"#include "print_binary.h"#include <linux/bitmap.h>#include <linux/kernel.h>#include <linux/stringify.h>#include <linux/time64.h>#include "asm/bug.h"#include "util/mem-events.h"#include "util/dump-insn.h"#include <dirent.h>#include <errno.h>#include <inttypes.h>#include <signal.h>#include <sys/param.h>#include <sys/types.h>#include <sys/stat.h>#include <unistd.h> #include "sane_ctype.h" static char const		*script_name;static char const		*generate_script_lang;static bool			debug_mode;static u64			last_timestamp;static u64			nr_unordered;static bool			no_callchain;static bool			latency_format;static bool			system_wide;static bool			print_flags;static bool			nanosecs;static const char		*cpu_list;static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);static struct perf_stat_config	stat_config;static int			max_blocks; unsigned int scripting_max_stack = PERF_MAX_STACK_DEPTH; enum perf_output_field {	PERF_OUTPUT_COMM            = 1U << 0,	PERF_OUTPUT_TID             = 1U << 1,	PERF_OUTPUT_PID             = 1U << 2,	PERF_OUTPUT_TIME            = 1U << 3,	PERF_OUTPUT_CPU             = 1U << 4,	PERF_OUTPUT_EVNAME          = 1U << 5,	PERF_OUTPUT_TRACE           = 1U << 6,	PERF_OUTPUT_IP              = 1U << 7,	PERF_OUTPUT_SYM             = 1U << 8,	PERF_OUTPUT_DSO             = 1U << 9,	PERF_OUTPUT_ADDR            = 1U << 10,	PERF_OUTPUT_SYMOFFSET       = 1U << 11,	PERF_OUTPUT_SRCLINE         = 1U << 12,	PERF_OUTPUT_PERIOD          = 1U << 13,	PERF_OUTPUT_IREGS	    = 1U << 14,	PERF_OUTPUT_BRSTACK	    = 1U << 15,	PERF_OUTPUT_BRSTACKSYM	    = 1U << 16,	PERF_OUTPUT_DATA_SRC	    = 1U << 17,	PERF_OUTPUT_WEIGHT	    = 1U << 18,	PERF_OUTPUT_BPF_OUTPUT	    = 1U << 19,	PERF_OUTPUT_CALLINDENT	    = 1U << 20,	PERF_OUTPUT_INSN	    = 1U << 21,	PERF_OUTPUT_INSNLEN	    = 1U << 22,	PERF_OUTPUT_BRSTACKINSN	    = 1U << 23,	PERF_OUTPUT_BRSTACKOFF	    = 1U << 24,	PERF_OUTPUT_SYNTH           = 1U << 25,}; struct output_option {	const char *str;	enum perf_output_field field;} all_output_options[] = {	{.str = "comm",  .field = PERF_OUTPUT_COMM},	{.str = "tid",   .field = PERF_OUTPUT_TID},	{.str = "pid",   .field = PERF_OUTPUT_PID},	{.str = "time",  .field = PERF_OUTPUT_TIME},	{.str = "cpu",   .field = PERF_OUTPUT_CPU},	{.str = "event", .field = PERF_OUTPUT_EVNAME},	{.str = "trace", .field = PERF_OUTPUT_TRACE},	{.str = "ip",    .field = PERF_OUTPUT_IP},	{.str = "sym",   .field = PERF_OUTPUT_SYM},	{.str = "dso",   .field = PERF_OUTPUT_DSO},	{.str = "addr",  .field = PERF_OUTPUT_ADDR},	{.str = "symoff", .field = PERF_OUTPUT_SYMOFFSET},	{.str = "srcline", .field = PERF_OUTPUT_SRCLINE},	{.str = "period", .field = PERF_OUTPUT_PERIOD},	{.str = "iregs", .field = PERF_OUTPUT_IREGS},	{.str = "brstack", .field = PERF_OUTPUT_BRSTACK},	{.str = "brstacksym", .field = PERF_OUTPUT_BRSTACKSYM},	{.str = "data_src", .field = PERF_OUTPUT_DATA_SRC},	{.str = "weight",   .field = PERF_OUTPUT_WEIGHT},	{.str = "bpf-output",   .field = PERF_OUTPUT_BPF_OUTPUT},	{.str = "callindent", .field = PERF_OUTPUT_CALLINDENT},	{.str = "insn", .field = PERF_OUTPUT_INSN},	{.str = "insnlen", .field = PERF_OUTPUT_INSNLEN},	{.str = "brstackinsn", .field = PERF_OUTPUT_BRSTACKINSN},	{.str = "brstackoff", .field = PERF_OUTPUT_BRSTACKOFF},	{.str = "synth", .field = PERF_OUTPUT_SYNTH},}; enum {	OUTPUT_TYPE_SYNTH = PERF_TYPE_MAX,	OUTPUT_TYPE_MAX}; /* default set to maintain compatibility with current format */static struct {	bool user_set;	bool wildcard_set;	unsigned int print_ip_opts;	u64 fields;	u64 invalid_fields;} output[OUTPUT_TYPE_MAX] = { 	[PERF_TYPE_HARDWARE] = {		.user_set = false, 		.fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |			      PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |			      PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP |			      PERF_OUTPUT_SYM | PERF_OUTPUT_DSO |			      PERF_OUTPUT_PERIOD, 		.invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT,	}, 	[PERF_TYPE_SOFTWARE] = {		.user_set = false, 		.fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |			      PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |			      PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP |			      PERF_OUTPUT_SYM | PERF_OUTPUT_DSO |			      PERF_OUTPUT_PERIOD | PERF_OUTPUT_BPF_OUTPUT, 		.invalid_fields = PERF_OUTPUT_TRACE,	}, 	[PERF_TYPE_TRACEPOINT] = {		.user_set = false, 		.fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |				  PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |				  PERF_OUTPUT_EVNAME | PERF_OUTPUT_TRACE	}, 	[PERF_TYPE_RAW] = {		.user_set = false, 		.fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |			      PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |			      PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP |			      PERF_OUTPUT_SYM | PERF_OUTPUT_DSO |			      PERF_OUTPUT_PERIOD |  PERF_OUTPUT_ADDR |			      PERF_OUTPUT_DATA_SRC | PERF_OUTPUT_WEIGHT, 		.invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT,	}, 	[PERF_TYPE_BREAKPOINT] = {		.user_set = false, 		.fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |			      PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |			      PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP |			      PERF_OUTPUT_SYM | PERF_OUTPUT_DSO |			      PERF_OUTPUT_PERIOD, 		.invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT,	}, 	[OUTPUT_TYPE_SYNTH] = {		.user_set = false, 		.fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |			      PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |			      PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP |			      PERF_OUTPUT_SYM | PERF_OUTPUT_DSO |			      PERF_OUTPUT_SYNTH, 		.invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT,	},}; static inline int output_type(unsigned int type){	switch (type) {	case PERF_TYPE_SYNTH:		return OUTPUT_TYPE_SYNTH;	default:		return type;	}} static inline unsigned int attr_type(unsigned int type){	switch (type) {	case OUTPUT_TYPE_SYNTH:		return PERF_TYPE_SYNTH;	default:		return type;	}} static bool output_set_by_user(void){	int j;	for (j = 0; j < OUTPUT_TYPE_MAX; ++j) {		if (output[j].user_set)			return true;	}	return false;} static const char *output_field2str(enum perf_output_field field){	int i, imax = ARRAY_SIZE(all_output_options);	const char *str = ""; 	for (i = 0; i < imax; ++i) {		if (all_output_options[i].field == field) {			str = all_output_options[i].str;			break;		}	}	return str;} #define PRINT_FIELD(x)  (output[output_type(attr->type)].fields & PERF_OUTPUT_##x) static int perf_evsel__do_check_stype(struct perf_evsel *evsel,				      u64 sample_type, const char *sample_msg,				      enum perf_output_field field,				      bool allow_user_set){	struct perf_event_attr *attr = &evsel->attr;	int type = output_type(attr->type);	const char *evname; 	if (attr->sample_type & sample_type)		return 0; 	if (output[type].user_set) {		if (allow_user_set)			return 0;		evname = perf_evsel__name(evsel);		pr_err("Samples for '%s' event do not have %s attribute set. "		       "Cannot print '%s' field.\n",		       evname, sample_msg, output_field2str(field));		return -1;	} 	/* user did not ask for it explicitly so remove from the default list */	output[type].fields &= ~field;	evname = perf_evsel__name(evsel);	pr_debug("Samples for '%s' event do not have %s attribute set. "		 "Skipping '%s' field.\n",		 evname, sample_msg, output_field2str(field)); 	return 0;} static int perf_evsel__check_stype(struct perf_evsel *evsel,				   u64 sample_type, const char *sample_msg,				   enum perf_output_field field){	return perf_evsel__do_check_stype(evsel, sample_type, sample_msg, field,					  false);} static int perf_evsel__check_attr(struct perf_evsel *evsel,				  struct perf_session *session){	struct perf_event_attr *attr = &evsel->attr;	bool allow_user_set; 	if (perf_header__has_feat(&session->header, HEADER_STAT))		return 0; 	allow_user_set = perf_header__has_feat(&session->header,					       HEADER_AUXTRACE); 	if (PRINT_FIELD(TRACE) &&		!perf_session__has_traces(session, "record -R"))		return -EINVAL; 	if (PRINT_FIELD(IP)) {		if (perf_evsel__check_stype(evsel, PERF_SAMPLE_IP, "IP",					    PERF_OUTPUT_IP))			return -EINVAL;	} 	if (PRINT_FIELD(ADDR) &&		perf_evsel__do_check_stype(evsel, PERF_SAMPLE_ADDR, "ADDR",					   PERF_OUTPUT_ADDR, allow_user_set))		return -EINVAL; 	if (PRINT_FIELD(DATA_SRC) &&		perf_evsel__check_stype(evsel, PERF_SAMPLE_DATA_SRC, "DATA_SRC",					PERF_OUTPUT_DATA_SRC))		return -EINVAL; 	if (PRINT_FIELD(WEIGHT) &&		perf_evsel__check_stype(evsel, PERF_SAMPLE_WEIGHT, "WEIGHT",					PERF_OUTPUT_WEIGHT))		return -EINVAL; 	if (PRINT_FIELD(SYM) && !PRINT_FIELD(IP) && !PRINT_FIELD(ADDR)) {		pr_err("Display of symbols requested but neither sample IP nor "			   "sample address\nis selected. Hence, no addresses to convert "		       "to symbols.\n");		return -EINVAL;	}	if (PRINT_FIELD(SYMOFFSET) && !PRINT_FIELD(SYM)) {		pr_err("Display of offsets requested but symbol is not"		       "selected.\n");		return -EINVAL;	}	if (PRINT_FIELD(DSO) && !PRINT_FIELD(IP) && !PRINT_FIELD(ADDR) &&	    !PRINT_FIELD(BRSTACK) && !PRINT_FIELD(BRSTACKSYM) && !PRINT_FIELD(BRSTACKOFF)) {		pr_err("Display of DSO requested but no address to convert.  Select\n"		       "sample IP, sample address, brstack, brstacksym, or brstackoff.\n");		return -EINVAL;	}	if (PRINT_FIELD(SRCLINE) && !PRINT_FIELD(IP)) {		pr_err("Display of source line number requested but sample IP is not\n"		       "selected. Hence, no address to lookup the source line number.\n");		return -EINVAL;	}	if (PRINT_FIELD(BRSTACKINSN) &&	    !(perf_evlist__combined_branch_type(session->evlist) &	      PERF_SAMPLE_BRANCH_ANY)) {		pr_err("Display of branch stack assembler requested, but non all-branch filter set\n"		       "Hint: run 'perf record -b ...'\n");		return -EINVAL;	}	if ((PRINT_FIELD(PID) || PRINT_FIELD(TID)) &&		perf_evsel__check_stype(evsel, PERF_SAMPLE_TID, "TID",					PERF_OUTPUT_TID|PERF_OUTPUT_PID))		return -EINVAL; 	if (PRINT_FIELD(TIME) &&		perf_evsel__check_stype(evsel, PERF_SAMPLE_TIME, "TIME",					PERF_OUTPUT_TIME))		return -EINVAL; 	if (PRINT_FIELD(CPU) &&		perf_evsel__do_check_stype(evsel, PERF_SAMPLE_CPU, "CPU",					   PERF_OUTPUT_CPU, allow_user_set))		return -EINVAL; 	if (PRINT_FIELD(PERIOD) &&		perf_evsel__check_stype(evsel, PERF_SAMPLE_PERIOD, "PERIOD",					PERF_OUTPUT_PERIOD))		return -EINVAL; 	if (PRINT_FIELD(IREGS) &&		perf_evsel__check_stype(evsel, PERF_SAMPLE_REGS_INTR, "IREGS",					PERF_OUTPUT_IREGS))		return -EINVAL; 	return 0;} static void set_print_ip_opts(struct perf_event_attr *attr){	unsigned int type = output_type(attr->type); 	output[type].print_ip_opts = 0;	if (PRINT_FIELD(IP))		output[type].print_ip_opts |= EVSEL__PRINT_IP; 	if (PRINT_FIELD(SYM))		output[type].print_ip_opts |= EVSEL__PRINT_SYM; 	if (PRINT_FIELD(DSO))		output[type].print_ip_opts |= EVSEL__PRINT_DSO; 	if (PRINT_FIELD(SYMOFFSET))		output[type].print_ip_opts |= EVSEL__PRINT_SYMOFFSET; 	if (PRINT_FIELD(SRCLINE))		output[type].print_ip_opts |= EVSEL__PRINT_SRCLINE;} /* * verify all user requested events exist and the samples * have the expected data */static int perf_session__check_output_opt(struct perf_session *session){	unsigned int j;	struct perf_evsel *evsel; 	for (j = 0; j < OUTPUT_TYPE_MAX; ++j) {		evsel = perf_session__find_first_evtype(session, attr_type(j)); 		/*		 * even if fields is set to 0 (ie., show nothing) event must		 * exist if user explicitly includes it on the command line		 */		if (!evsel && output[j].user_set && !output[j].wildcard_set &&		    j != OUTPUT_TYPE_SYNTH) {			pr_err("%s events do not exist. "			       "Remove corresponding -F option to proceed.\n",			       event_type(j));			return -1;		} 		if (evsel && output[j].fields &&			perf_evsel__check_attr(evsel, session))			return -1; 		if (evsel == NULL)			continue; 		set_print_ip_opts(&evsel->attr);	} 	if (!no_callchain) {		bool use_callchain = false;		bool not_pipe = false; 		evlist__for_each_entry(session->evlist, evsel) {			not_pipe = true;			if (evsel->attr.sample_type & PERF_SAMPLE_CALLCHAIN) {				use_callchain = true;				break;			}		}		if (not_pipe && !use_callchain)			symbol_conf.use_callchain = false;	} 	/*	 * set default for tracepoints to print symbols only	 * if callchains are present	 */	if (symbol_conf.use_callchain &&	    !output[PERF_TYPE_TRACEPOINT].user_set) {		struct perf_event_attr *attr; 		j = PERF_TYPE_TRACEPOINT; 		evlist__for_each_entry(session->evlist, evsel) {			if (evsel->attr.type != j)				continue; 			attr = &evsel->attr; 			if (attr->sample_type & PERF_SAMPLE_CALLCHAIN) {				output[j].fields |= PERF_OUTPUT_IP;				output[j].fields |= PERF_OUTPUT_SYM;				output[j].fields |= PERF_OUTPUT_DSO;				set_print_ip_opts(attr);				goto out;			}		}	} out:	return 0;} static void print_sample_iregs(struct perf_sample *sample,			  struct perf_event_attr *attr){	struct regs_dump *regs = &sample->intr_regs;	uint64_t mask = attr->sample_regs_intr;	unsigned i = 0, r; 	if (!regs)		return; 	for_each_set_bit(r, (unsigned long *) &mask, sizeof(mask) * 8) {		u64 val = regs->regs[i++];		printf("%5s:0x%"PRIx64" ", perf_reg_name(r), val);

Lines 1–500 of 3083.