Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit aef29bf2 authored by Ingo Molnar's avatar Ingo Molnar
Browse files

Merge branch 'perf/core' of ssh://k/pub/scm/linux/kernel/git/acme/linux into perf/core

parents 27eb4a1e 7cec0922
Loading
Loading
Loading
Loading
+6 −6
Original line number Diff line number Diff line
@@ -115,10 +115,10 @@ OPTIONS
-f::
--fields::
        Comma separated list of fields to print. Options are:
        comm, tid, pid, time, cpu, event, trace, sym. Field
        list can be prepended with the type, trace, sw or hw,
        comm, tid, pid, time, cpu, event, trace, ip, sym, dso, addr.
        Field list can be prepended with the type, trace, sw or hw,
        to indicate to which event type the field list applies.
        e.g., -f sw:comm,tid,time,sym  and -f trace:time,cpu,trace
        e.g., -f sw:comm,tid,time,ip,sym  and -f trace:time,cpu,trace

		perf script -f <fields>

@@ -132,17 +132,17 @@ OPTIONS
	The arguments are processed in the order received. A later usage can
	reset a prior request. e.g.:
    
		-f trace: -f comm,tid,time,sym
		-f trace: -f comm,tid,time,ip,sym
    
	The first -f suppresses trace events (field list is ""), but then the
	second invocation sets the fields to comm,tid,time,sym. In this case a
	second invocation sets the fields to comm,tid,time,ip,sym. In this case a
	warning is given to the user:
    
		"Overriding previous field request for all events."
    
	Alternativey, consider the order:
    
		-f comm,tid,time,sym -f trace:
		-f comm,tid,time,ip,sym -f trace:
    
	The first -f sets the fields for all events and the second -f
	suppresses trace events. The user is given a warning message about
+98 −10
Original line number Diff line number Diff line
@@ -30,7 +30,10 @@ enum perf_output_field {
	PERF_OUTPUT_CPU             = 1U << 4,
	PERF_OUTPUT_EVNAME          = 1U << 5,
	PERF_OUTPUT_TRACE           = 1U << 6,
	PERF_OUTPUT_SYM             = 1U << 7,
	PERF_OUTPUT_IP              = 1U << 7,
	PERF_OUTPUT_SYM             = 1U << 8,
	PERF_OUTPUT_DSO             = 1U << 9,
	PERF_OUTPUT_ADDR            = 1U << 10,
};

struct output_option {
@@ -44,7 +47,10 @@ struct output_option {
	{.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},
};

/* default set to maintain compatibility with current format */
@@ -60,7 +66,8 @@ static struct {

		.fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
			      PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
			      PERF_OUTPUT_EVNAME | PERF_OUTPUT_SYM,
			      PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP |
				  PERF_OUTPUT_SYM | PERF_OUTPUT_DSO,

		.invalid_fields = PERF_OUTPUT_TRACE,
	},
@@ -70,7 +77,8 @@ static struct {

		.fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
			      PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
			      PERF_OUTPUT_EVNAME | PERF_OUTPUT_SYM,
			      PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP |
				  PERF_OUTPUT_SYM | PERF_OUTPUT_DSO,

		.invalid_fields = PERF_OUTPUT_TRACE,
	},
@@ -88,7 +96,8 @@ static struct {

		.fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
			      PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
			      PERF_OUTPUT_EVNAME | PERF_OUTPUT_SYM,
			      PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP |
				  PERF_OUTPUT_SYM | PERF_OUTPUT_DSO,

		.invalid_fields = PERF_OUTPUT_TRACE,
	},
@@ -157,9 +166,9 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,
		!perf_session__has_traces(session, "record -R"))
		return -EINVAL;

	if (PRINT_FIELD(SYM)) {
	if (PRINT_FIELD(IP)) {
		if (perf_event_attr__check_stype(attr, PERF_SAMPLE_IP, "IP",
					   PERF_OUTPUT_SYM))
					   PERF_OUTPUT_IP))
			return -EINVAL;

		if (!no_callchain &&
@@ -167,6 +176,24 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,
			symbol_conf.use_callchain = false;
	}

	if (PRINT_FIELD(ADDR) &&
		perf_event_attr__check_stype(attr, PERF_SAMPLE_ADDR, "ADDR",
				       PERF_OUTPUT_ADDR))
		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(DSO) && !PRINT_FIELD(IP) && !PRINT_FIELD(ADDR)) {
		pr_err("Display of DSO requested but neither sample IP nor "
			   "sample address\nis selected. Hence, no addresses to convert "
		       "to DSO.\n");
		return -EINVAL;
	}

	if ((PRINT_FIELD(PID) || PRINT_FIELD(TID)) &&
		perf_event_attr__check_stype(attr, PERF_SAMPLE_TID, "TID",
				       PERF_OUTPUT_TID|PERF_OUTPUT_PID))
@@ -230,7 +257,7 @@ static void print_sample_start(struct perf_sample *sample,
	if (PRINT_FIELD(COMM)) {
		if (latency_format)
			printf("%8.8s ", thread->comm);
		else if (PRINT_FIELD(SYM) && symbol_conf.use_callchain)
		else if (PRINT_FIELD(IP) && symbol_conf.use_callchain)
			printf("%s ", thread->comm);
		else
			printf("%16s ", thread->comm);
@@ -271,6 +298,63 @@ static void print_sample_start(struct perf_sample *sample,
	}
}

static bool sample_addr_correlates_sym(struct perf_event_attr *attr)
{
	if ((attr->type == PERF_TYPE_SOFTWARE) &&
	    ((attr->config == PERF_COUNT_SW_PAGE_FAULTS) ||
	     (attr->config == PERF_COUNT_SW_PAGE_FAULTS_MIN) ||
	     (attr->config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)))
		return true;

	return false;
}

static void print_sample_addr(union perf_event *event,
			  struct perf_sample *sample,
			  struct perf_session *session,
			  struct thread *thread,
			  struct perf_event_attr *attr)
{
	struct addr_location al;
	u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
	const char *symname, *dsoname;

	printf("%16" PRIx64, sample->addr);

	if (!sample_addr_correlates_sym(attr))
		return;

	thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION,
			      event->ip.pid, sample->addr, &al);
	if (!al.map)
		thread__find_addr_map(thread, session, cpumode, MAP__VARIABLE,
				      event->ip.pid, sample->addr, &al);

	al.cpu = sample->cpu;
	al.sym = NULL;

	if (al.map)
		al.sym = map__find_symbol(al.map, al.addr, NULL);

	if (PRINT_FIELD(SYM)) {
		if (al.sym && al.sym->name)
			symname = al.sym->name;
		else
			symname = "";

		printf(" %16s", symname);
	}

	if (PRINT_FIELD(DSO)) {
		if (al.map && al.map->dso && al.map->dso->name)
			dsoname = al.map->dso->name;
		else
			dsoname = "";

		printf(" (%s)", dsoname);
	}
}

static void process_event(union perf_event *event __unused,
			  struct perf_sample *sample,
			  struct perf_evsel *evsel,
@@ -288,12 +372,16 @@ static void process_event(union perf_event *event __unused,
		print_trace_event(sample->cpu, sample->raw_data,
				  sample->raw_size);

	if (PRINT_FIELD(SYM)) {
	if (PRINT_FIELD(ADDR))
		print_sample_addr(event, sample, session, thread, attr);

	if (PRINT_FIELD(IP)) {
		if (!symbol_conf.use_callchain)
			printf(" ");
		else
			printf("\n");
		perf_session__print_symbols(event, sample, session);
		perf_session__print_ip(event, sample, session,
					      PRINT_FIELD(SYM), PRINT_FIELD(DSO));
	}

	printf("\n");
@@ -985,7 +1073,7 @@ static const struct option options[] = {
	OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
		    "Look for files with symbols relative to this directory"),
	OPT_CALLBACK('f', "fields", NULL, "str",
		     "comma separated output fields prepend with 'type:'. Valid types: hw,sw,trace,raw. Fields: comm,tid,pid,time,cpu,event,trace,sym",
		     "comma separated output fields prepend with 'type:'. Valid types: hw,sw,trace,raw. Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso,addr",
		     parse_output_fields),

	OPT_END()
+7 −2
Original line number Diff line number Diff line
@@ -61,6 +61,8 @@
#include <locale.h>

#define DEFAULT_SEPARATOR	" "
#define CNTR_NOT_SUPPORTED	"<not supported>"
#define CNTR_NOT_COUNTED	"<not counted>"

static struct perf_event_attr default_attrs[] = {

@@ -448,6 +450,7 @@ static int run_perf_stat(int argc __used, const char **argv)
				if (verbose)
					ui__warning("%s event is not supported by the kernel.\n",
						    event_name(counter));
				counter->supported = false;
				continue;
			}

@@ -466,6 +469,7 @@ static int run_perf_stat(int argc __used, const char **argv)
			die("Not all events could be opened.\n");
			return -1;
		}
		counter->supported = true;
	}

	if (perf_evlist__set_filters(evsel_list)) {
@@ -861,7 +865,7 @@ static void print_counter_aggr(struct perf_evsel *counter)
	if (scaled == -1) {
		fprintf(stderr, "%*s%s%*s",
			csv_output ? 0 : 18,
			"<not counted>",
			counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
			csv_sep,
			csv_output ? 0 : -24,
			event_name(counter));
@@ -914,7 +918,8 @@ static void print_counter(struct perf_evsel *counter)
				csv_output ? 0 : -4,
				evsel_list->cpus->map[cpu], csv_sep,
				csv_output ? 0 : 18,
				"<not counted>", csv_sep,
				counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED,
				csv_sep,
				csv_output ? 0 : -24,
				event_name(counter));

+1 −1
Original line number Diff line number Diff line
@@ -474,7 +474,7 @@ static int test__basic_mmap(void)
	unsigned int nr_events[nsyscalls],
		     expected_nr_events[nsyscalls], i, j;
	struct perf_evsel *evsels[nsyscalls], *evsel;
	int sample_size = perf_sample_size(attr.sample_type);
	int sample_size = __perf_evsel__sample_size(attr.sample_type);

	for (i = 0; i < nsyscalls; ++i) {
		char name[64];
+0 −16
Original line number Diff line number Diff line
@@ -35,22 +35,6 @@ const char *perf_event__name(unsigned int id)
	return perf_event__names[id];
}

int perf_sample_size(u64 sample_type)
{
	u64 mask = sample_type & PERF_SAMPLE_MASK;
	int size = 0;
	int i;

	for (i = 0; i < 64; i++) {
		if (mask & (1ULL << i))
			size++;
	}

	size *= sizeof(u64);

	return size;
}

static struct perf_sample synth_sample = {
	.pid	   = -1,
	.tid	   = -1,
Loading