4629 lines · 125.0 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0#include <errno.h>#include <inttypes.h>#include <signal.h>#include <stdio.h> #include <dirent.h>#include <fcntl.h>#include <linux/bitmap.h>#include <linux/compiler.h>#include <linux/ctype.h>#include <linux/err.h>#include <linux/kernel.h>#include <linux/stringify.h>#include <linux/time64.h>#include <linux/unaligned.h>#include <linux/zalloc.h>#include <sys/param.h>#include <sys/stat.h>#include <sys/types.h>#include <sys/utsname.h>#include <unistd.h> #include <perf/evlist.h>#include <subcmd/exec-cmd.h>#include <subcmd/pager.h>#include <subcmd/parse-options.h> #include "asm/bug.h"#include "builtin.h"#include "perf.h"#include "print_binary.h"#include "print_insn.h"#include "ui/ui.h"#include "util/annotate.h"#include "util/auxtrace.h"#include "util/cgroup.h"#include "util/color.h"#include "util/counts.h"#include "util/cpumap.h"#include "util/data.h"#include "util/debug.h"#include "util/dlfilter.h"#include "util/dso.h"#include "util/dump-insn.h"#include "util/env.h"#include "util/event.h"#include "util/evlist.h"#include "util/evsel.h"#include "util/evsel_fprintf.h"#include "util/evswitch.h"#include "util/header.h"#include "util/map.h"#include "util/mem-events.h"#include "util/mem-info.h"#include "util/metricgroup.h"#include "util/path.h"#include "util/perf_regs.h"#include "util/pmu.h"#include "util/record.h"#include "util/session.h"#include "util/sort.h"#include "util/srcline.h"#include "util/stat.h"#include "util/string2.h"#include "util/symbol.h"#include "util/thread-stack.h"#include "util/thread.h"#include "util/thread_map.h"#include "util/time-utils.h"#include "util/tool.h"#include "util/trace-event.h"#include "util/unwind.h"#include "util/util.h" #ifdef HAVE_LIBTRACEEVENT#include <event-parse.h>#endif static char const		*script_name;static char const		*generate_script_lang;static bool			reltime;static bool			deltatime;static u64			initial_time;static u64			previous_time;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 const char		*cpu_list;static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);static int			max_blocks;static struct dlfilter		*dlfilter;static int			dlargc;static char			**dlargv; enum perf_output_field {	PERF_OUTPUT_COMM            = 1ULL << 0,	PERF_OUTPUT_TID             = 1ULL << 1,	PERF_OUTPUT_PID             = 1ULL << 2,	PERF_OUTPUT_TIME            = 1ULL << 3,	PERF_OUTPUT_CPU             = 1ULL << 4,	PERF_OUTPUT_EVNAME          = 1ULL << 5,	PERF_OUTPUT_TRACE           = 1ULL << 6,	PERF_OUTPUT_IP              = 1ULL << 7,	PERF_OUTPUT_SYM             = 1ULL << 8,	PERF_OUTPUT_DSO             = 1ULL << 9,	PERF_OUTPUT_ADDR            = 1ULL << 10,	PERF_OUTPUT_SYMOFFSET       = 1ULL << 11,	PERF_OUTPUT_SRCLINE         = 1ULL << 12,	PERF_OUTPUT_PERIOD          = 1ULL << 13,	PERF_OUTPUT_IREGS	    = 1ULL << 14,	PERF_OUTPUT_BRSTACK	    = 1ULL << 15,	PERF_OUTPUT_BRSTACKSYM	    = 1ULL << 16,	PERF_OUTPUT_DATA_SRC	    = 1ULL << 17,	PERF_OUTPUT_WEIGHT	    = 1ULL << 18,	PERF_OUTPUT_BPF_OUTPUT	    = 1ULL << 19,	PERF_OUTPUT_CALLINDENT	    = 1ULL << 20,	PERF_OUTPUT_INSN	    = 1ULL << 21,	PERF_OUTPUT_INSNLEN	    = 1ULL << 22,	PERF_OUTPUT_BRSTACKINSN	    = 1ULL << 23,	PERF_OUTPUT_BRSTACKOFF	    = 1ULL << 24,	PERF_OUTPUT_SYNTH           = 1ULL << 25,	PERF_OUTPUT_PHYS_ADDR       = 1ULL << 26,	PERF_OUTPUT_UREGS	    = 1ULL << 27,	PERF_OUTPUT_METRIC	    = 1ULL << 28,	PERF_OUTPUT_MISC            = 1ULL << 29,	PERF_OUTPUT_SRCCODE	    = 1ULL << 30,	PERF_OUTPUT_IPC             = 1ULL << 31,	PERF_OUTPUT_TOD             = 1ULL << 32,	PERF_OUTPUT_DATA_PAGE_SIZE  = 1ULL << 33,	PERF_OUTPUT_CODE_PAGE_SIZE  = 1ULL << 34,	PERF_OUTPUT_INS_LAT         = 1ULL << 35,	PERF_OUTPUT_BRSTACKINSNLEN  = 1ULL << 36,	PERF_OUTPUT_MACHINE_PID     = 1ULL << 37,	PERF_OUTPUT_VCPU            = 1ULL << 38,	PERF_OUTPUT_CGROUP          = 1ULL << 39,	PERF_OUTPUT_RETIRE_LAT      = 1ULL << 40,	PERF_OUTPUT_DSOFF           = 1ULL << 41,	PERF_OUTPUT_DISASM          = 1ULL << 42,	PERF_OUTPUT_BRSTACKDISASM   = 1ULL << 43,	PERF_OUTPUT_BRCNTR          = 1ULL << 44,}; struct perf_script {	struct perf_tool	tool;	struct perf_session	*session;	bool			show_task_events;	bool			show_mmap_events;	bool			show_switch_events;	bool			show_namespace_events;	bool			show_lost_events;	bool			show_round_events;	bool			show_bpf_events;	bool			show_cgroup_events;	bool			show_text_poke_events;	bool			allocated;	bool			per_event_dump;	bool			stitch_lbr;	struct evswitch		evswitch;	struct perf_cpu_map	*cpus;	struct perf_thread_map *threads;	int			name_width;	const char              *time_str;	struct perf_time_interval *ptime_range;	int			range_size;	int			range_num;}; static 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 = "dsoff", .field = PERF_OUTPUT_DSOFF},	{.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 = "uregs", .field = PERF_OUTPUT_UREGS},	{.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 = "disasm", .field = PERF_OUTPUT_DISASM},	{.str = "insnlen", .field = PERF_OUTPUT_INSNLEN},	{.str = "brstackinsn", .field = PERF_OUTPUT_BRSTACKINSN},	{.str = "brstackoff", .field = PERF_OUTPUT_BRSTACKOFF},	{.str = "synth", .field = PERF_OUTPUT_SYNTH},	{.str = "phys_addr", .field = PERF_OUTPUT_PHYS_ADDR},	{.str = "metric", .field = PERF_OUTPUT_METRIC},	{.str = "misc", .field = PERF_OUTPUT_MISC},	{.str = "srccode", .field = PERF_OUTPUT_SRCCODE},	{.str = "ipc", .field = PERF_OUTPUT_IPC},	{.str = "tod", .field = PERF_OUTPUT_TOD},	{.str = "data_page_size", .field = PERF_OUTPUT_DATA_PAGE_SIZE},	{.str = "code_page_size", .field = PERF_OUTPUT_CODE_PAGE_SIZE},	{.str = "ins_lat", .field = PERF_OUTPUT_INS_LAT},	{.str = "brstackinsnlen", .field = PERF_OUTPUT_BRSTACKINSNLEN},	{.str = "machine_pid", .field = PERF_OUTPUT_MACHINE_PID},	{.str = "vcpu", .field = PERF_OUTPUT_VCPU},	{.str = "cgroup", .field = PERF_OUTPUT_CGROUP},	{.str = "retire_lat", .field = PERF_OUTPUT_RETIRE_LAT},	{.str = "brstackdisasm", .field = PERF_OUTPUT_BRSTACKDISASM},	{.str = "brcntr", .field = PERF_OUTPUT_BRCNTR},}; enum {	OUTPUT_TYPE_SYNTH = PERF_TYPE_MAX,	OUTPUT_TYPE_OTHER,	OUTPUT_TYPE_MAX}; // We need to refactor the evsel->priv use in 'perf script' to allow for// using that area, that is being used only in some cases.#define OUTPUT_TYPE_UNSET -1 /* 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;	u64 user_set_fields;	u64 user_unset_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_SYMOFFSET |			      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_SYMOFFSET |			      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_HW_CACHE] = {		.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_SYMOFFSET |			      PERF_OUTPUT_DSO | PERF_OUTPUT_PERIOD, 		.invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT,	}, 	[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_SYMOFFSET |			      PERF_OUTPUT_DSO | PERF_OUTPUT_PERIOD |			      PERF_OUTPUT_ADDR | PERF_OUTPUT_DATA_SRC |			      PERF_OUTPUT_WEIGHT | PERF_OUTPUT_PHYS_ADDR |			      PERF_OUTPUT_DATA_PAGE_SIZE | PERF_OUTPUT_CODE_PAGE_SIZE |			      PERF_OUTPUT_INS_LAT | PERF_OUTPUT_RETIRE_LAT, 		.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_SYMOFFSET |			      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_SYMOFFSET |			      PERF_OUTPUT_DSO | PERF_OUTPUT_SYNTH, 		.invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT,	}, 	[OUTPUT_TYPE_OTHER] = {		.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_SYMOFFSET |			      PERF_OUTPUT_DSO | PERF_OUTPUT_PERIOD, 		.invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT,	},}; struct evsel_script {       char *filename;       FILE *fp;       u64  samples;}; static struct evsel_script *evsel_script__new(struct evsel *evsel, struct perf_data *data){	struct evsel_script *es = zalloc(sizeof(*es)); 	if (es != NULL) {		if (asprintf(&es->filename, "%s.%s.dump", data->file.path, evsel__name(evsel)) < 0)			goto out_free;		es->fp = fopen(es->filename, "w");		if (es->fp == NULL)			goto out_free_filename;	} 	return es;out_free_filename:	zfree(&es->filename);out_free:	free(es);	return NULL;} static void evsel_script__delete(struct evsel_script *es){	zfree(&es->filename);	fclose(es->fp);	es->fp = NULL;	free(es);} static int evsel_script__fprintf(struct evsel_script *es, FILE *fp){	struct stat st; 	fstat(fileno(es->fp), &st);	return fprintf(fp, "[ perf script: Wrote %.3f MB %s (%" PRIu64 " samples) ]\n",		       st.st_size / 1024.0 / 1024.0, es->filename, es->samples);} static inline int output_type(unsigned int type){	switch (type) {	case PERF_TYPE_SYNTH:		return OUTPUT_TYPE_SYNTH;	default:		if (type < PERF_TYPE_MAX)			return type;	} 	return OUTPUT_TYPE_OTHER;} static inline int evsel__output_type(struct evsel *evsel){	int type = evsel->script_output_type; 	if (type == OUTPUT_TYPE_UNSET) {		type = output_type(evsel->core.attr.type);		if (type == OUTPUT_TYPE_OTHER) {			struct perf_pmu *pmu = evsel__find_pmu(evsel); 			if (pmu && pmu->is_core)				type = PERF_TYPE_RAW;		}		evsel->script_output_type = type;	} 	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[evsel__output_type(evsel)].fields & PERF_OUTPUT_##x) static int evsel__do_check_stype(struct evsel *evsel, u64 sample_type, const char *sample_msg,				 enum perf_output_field field, bool allow_user_set){	struct perf_event_attr *attr = &evsel->core.attr;	int type = evsel__output_type(evsel);	const char *evname; 	if (attr->sample_type & sample_type)		return 0; 	if (output[type].user_set_fields & field) {		if (allow_user_set)			return 0;		evname = 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 = 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 evsel__check_stype(struct evsel *evsel, u64 sample_type, const char *sample_msg,			      enum perf_output_field field){	return evsel__do_check_stype(evsel, sample_type, sample_msg, field, false);} static int evsel__check_attr(struct evsel *evsel, struct perf_session *session){	bool allow_user_set; 	if (evsel__is_dummy_event(evsel))		return 0; 	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 (evsel__check_stype(evsel, PERF_SAMPLE_IP, "IP", PERF_OUTPUT_IP))			return -EINVAL;	} 

Lines 1–500 of 4629.