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 Original line Diff line number Diff line
@@ -115,10 +115,10 @@ OPTIONS
-f::
-f::
--fields::
--fields::
        Comma separated list of fields to print. Options are:
        Comma separated list of fields to print. Options are:
        comm, tid, pid, time, cpu, event, trace, sym. Field
        comm, tid, pid, time, cpu, event, trace, ip, sym, dso, addr.
        list can be prepended with the type, trace, sw or hw,
        Field list can be prepended with the type, trace, sw or hw,
        to indicate to which event type the field list applies.
        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>
		perf script -f <fields>


@@ -132,17 +132,17 @@ OPTIONS
	The arguments are processed in the order received. A later usage can
	The arguments are processed in the order received. A later usage can
	reset a prior request. e.g.:
	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
	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:
	warning is given to the user:
    
    
		"Overriding previous field request for all events."
		"Overriding previous field request for all events."
    
    
	Alternativey, consider the order:
	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
	The first -f sets the fields for all events and the second -f
	suppresses trace events. The user is given a warning message about
	suppresses trace events. The user is given a warning message about
+98 −10
Original line number Original line Diff line number Diff line
@@ -30,7 +30,10 @@ enum perf_output_field {
	PERF_OUTPUT_CPU             = 1U << 4,
	PERF_OUTPUT_CPU             = 1U << 4,
	PERF_OUTPUT_EVNAME          = 1U << 5,
	PERF_OUTPUT_EVNAME          = 1U << 5,
	PERF_OUTPUT_TRACE           = 1U << 6,
	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 {
struct output_option {
@@ -44,7 +47,10 @@ struct output_option {
	{.str = "cpu",   .field = PERF_OUTPUT_CPU},
	{.str = "cpu",   .field = PERF_OUTPUT_CPU},
	{.str = "event", .field = PERF_OUTPUT_EVNAME},
	{.str = "event", .field = PERF_OUTPUT_EVNAME},
	{.str = "trace", .field = PERF_OUTPUT_TRACE},
	{.str = "trace", .field = PERF_OUTPUT_TRACE},
	{.str = "ip",    .field = PERF_OUTPUT_IP},
	{.str = "sym",   .field = PERF_OUTPUT_SYM},
	{.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 */
/* default set to maintain compatibility with current format */
@@ -60,7 +66,8 @@ static struct {


		.fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
		.fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
			      PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
			      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,
		.invalid_fields = PERF_OUTPUT_TRACE,
	},
	},
@@ -70,7 +77,8 @@ static struct {


		.fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
		.fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
			      PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
			      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,
		.invalid_fields = PERF_OUTPUT_TRACE,
	},
	},
@@ -88,7 +96,8 @@ static struct {


		.fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
		.fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
			      PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
			      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,
		.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"))
		!perf_session__has_traces(session, "record -R"))
		return -EINVAL;
		return -EINVAL;


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


		if (!no_callchain &&
		if (!no_callchain &&
@@ -167,6 +176,24 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,
			symbol_conf.use_callchain = false;
			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)) &&
	if ((PRINT_FIELD(PID) || PRINT_FIELD(TID)) &&
		perf_event_attr__check_stype(attr, PERF_SAMPLE_TID, "TID",
		perf_event_attr__check_stype(attr, PERF_SAMPLE_TID, "TID",
				       PERF_OUTPUT_TID|PERF_OUTPUT_PID))
				       PERF_OUTPUT_TID|PERF_OUTPUT_PID))
@@ -230,7 +257,7 @@ static void print_sample_start(struct perf_sample *sample,
	if (PRINT_FIELD(COMM)) {
	if (PRINT_FIELD(COMM)) {
		if (latency_format)
		if (latency_format)
			printf("%8.8s ", thread->comm);
			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);
			printf("%s ", thread->comm);
		else
		else
			printf("%16s ", thread->comm);
			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,
static void process_event(union perf_event *event __unused,
			  struct perf_sample *sample,
			  struct perf_sample *sample,
			  struct perf_evsel *evsel,
			  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,
		print_trace_event(sample->cpu, sample->raw_data,
				  sample->raw_size);
				  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)
		if (!symbol_conf.use_callchain)
			printf(" ");
			printf(" ");
		else
		else
			printf("\n");
			printf("\n");
		perf_session__print_symbols(event, sample, session);
		perf_session__print_ip(event, sample, session,
					      PRINT_FIELD(SYM), PRINT_FIELD(DSO));
	}
	}


	printf("\n");
	printf("\n");
@@ -985,7 +1073,7 @@ static const struct option options[] = {
	OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
	OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
		    "Look for files with symbols relative to this directory"),
		    "Look for files with symbols relative to this directory"),
	OPT_CALLBACK('f', "fields", NULL, "str",
	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),
		     parse_output_fields),


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


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


static struct perf_event_attr default_attrs[] = {
static struct perf_event_attr default_attrs[] = {


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


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


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


+1 −1
Original line number Original line Diff line number Diff line
@@ -474,7 +474,7 @@ static int test__basic_mmap(void)
	unsigned int nr_events[nsyscalls],
	unsigned int nr_events[nsyscalls],
		     expected_nr_events[nsyscalls], i, j;
		     expected_nr_events[nsyscalls], i, j;
	struct perf_evsel *evsels[nsyscalls], *evsel;
	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) {
	for (i = 0; i < nsyscalls; ++i) {
		char name[64];
		char name[64];
+0 −16
Original line number Original line Diff line number Diff line
@@ -35,22 +35,6 @@ const char *perf_event__name(unsigned int id)
	return perf_event__names[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 = {
static struct perf_sample synth_sample = {
	.pid	   = -1,
	.pid	   = -1,
	.tid	   = -1,
	.tid	   = -1,
Loading