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

Commit 8b7cdd08 authored by Ingo Molnar's avatar Ingo Molnar
Browse files

Merge branch 'perf/core' of...

Merge branch 'perf/core' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux-2.6 into perf/urgent
parents d1090281 43adec95
Loading
Loading
Loading
Loading
+26 −0
Original line number Diff line number Diff line
perf-evlist(1)
==============

NAME
----
perf-evlist - List the event names in a perf.data file

SYNOPSIS
--------
[verse]
'perf evlist <options>'

DESCRIPTION
-----------
This command displays the names of events sampled in a perf.data file.

OPTIONS
-------
-i::
--input=::
        Input file name. (default: perf.data)

SEE ALSO
--------
linkperf:perf-record[1], linkperf:perf-list[1],
linkperf:perf-report[1]
+22 −0
Original line number Diff line number Diff line
@@ -112,6 +112,28 @@ OPTIONS
--debug-mode::
        Do various checks like samples ordering and lost events.

-f::
--fields
        Comma separated list of fields to print. Options are:
        comm, tid, pid, time, cpu, event, trace, sym. Field
        list must 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

-k::
--vmlinux=<file>::
        vmlinux pathname

--kallsyms=<file>::
        kallsyms pathname

--symfs=<directory>::
        Look for files with symbols relative to this directory.

-G::
--hide-call-graph::
        When printing symbols do not display call chain.

SEE ALSO
--------
linkperf:perf-record[1], linkperf:perf-script-perl[1],
+1 −0
Original line number Diff line number Diff line
@@ -338,6 +338,7 @@ endif
BUILTIN_OBJS += $(OUTPUT)bench/mem-memcpy.o

BUILTIN_OBJS += $(OUTPUT)builtin-diff.o
BUILTIN_OBJS += $(OUTPUT)builtin-evlist.o
BUILTIN_OBJS += $(OUTPUT)builtin-help.o
BUILTIN_OBJS += $(OUTPUT)builtin-sched.o
BUILTIN_OBJS += $(OUTPUT)builtin-buildid-list.o
+54 −0
Original line number Diff line number Diff line
/*
 * Builtin evlist command: Show the list of event selectors present
 * in a perf.data file.
 */
#include "builtin.h"

#include "util/util.h"

#include <linux/list.h>

#include "perf.h"
#include "util/evlist.h"
#include "util/evsel.h"
#include "util/parse-events.h"
#include "util/parse-options.h"
#include "util/session.h"

static char const *input_name = "perf.data";

static int __cmd_evlist(void)
{
	struct perf_session *session;
	struct perf_evsel *pos;

	session = perf_session__new(input_name, O_RDONLY, 0, false, NULL);
	if (session == NULL)
		return -ENOMEM;

	list_for_each_entry(pos, &session->evlist->entries, node)
		printf("%s\n", event_name(pos));

	perf_session__delete(session);
	return 0;
}

static const char * const evlist_usage[] = {
	"perf evlist [<options>]",
	NULL
};

static const struct option options[] = {
	OPT_STRING('i', "input", &input_name, "file",
		    "input file name"),
	OPT_END()
};

int cmd_evlist(int argc, const char **argv, const char *prefix __used)
{
	argc = parse_options(argc, argv, options, evlist_usage, 0);
	if (argc)
		usage_with_options(evlist_usage, options);

	return __cmd_evlist();
}
+277 −23
Original line number Diff line number Diff line
@@ -12,6 +12,8 @@
#include "util/trace-event.h"
#include "util/parse-options.h"
#include "util/util.h"
#include "util/evlist.h"
#include "util/evsel.h"

static char const		*script_name;
static char const		*generate_script_lang;
@@ -19,6 +21,183 @@ static bool debug_mode;
static u64			last_timestamp;
static u64			nr_unordered;
extern const struct option	record_options[];
static bool			no_callchain;

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_SYM             = 1U << 7,
};

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 = "sym",   .field = PERF_OUTPUT_SYM},
};

/* default set to maintain compatibility with current format */
static u64 output_fields[PERF_TYPE_MAX] = {
	[PERF_TYPE_HARDWARE] = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | \
			       PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | \
			       PERF_OUTPUT_EVNAME | PERF_OUTPUT_SYM,

	[PERF_TYPE_SOFTWARE] = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | \
			       PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | \
			       PERF_OUTPUT_EVNAME | PERF_OUTPUT_SYM,

	[PERF_TYPE_TRACEPOINT] = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | \
				 PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | \
				 PERF_OUTPUT_EVNAME | PERF_OUTPUT_TRACE,
};

static bool output_set_by_user;

#define PRINT_FIELD(x)  (output_fields[attr->type] & PERF_OUTPUT_##x)

static int perf_session__check_attr(struct perf_session *session,
				    struct perf_event_attr *attr)
{
	if (PRINT_FIELD(TRACE) &&
		!perf_session__has_traces(session, "record -R"))
		return -EINVAL;

	if (PRINT_FIELD(SYM)) {
		if (!(session->sample_type & PERF_SAMPLE_IP)) {
			pr_err("Samples do not contain IP data.\n");
			return -EINVAL;
		}
		if (!no_callchain &&
		    !(session->sample_type & PERF_SAMPLE_CALLCHAIN))
			symbol_conf.use_callchain = false;
	}

	if ((PRINT_FIELD(PID) || PRINT_FIELD(TID)) &&
		!(session->sample_type & PERF_SAMPLE_TID)) {
		pr_err("Samples do not contain TID/PID data.\n");
		return -EINVAL;
	}

	if (PRINT_FIELD(TIME) &&
		!(session->sample_type & PERF_SAMPLE_TIME)) {
		pr_err("Samples do not contain timestamps.\n");
		return -EINVAL;
	}

	if (PRINT_FIELD(CPU) &&
		!(session->sample_type & PERF_SAMPLE_CPU)) {
		pr_err("Samples do not contain cpu.\n");
		return -EINVAL;
	}

	return 0;
}

static void print_sample_start(struct perf_sample *sample,
			       struct thread *thread,
			       struct perf_event_attr *attr)
{
	int type;
	struct event *event;
	const char *evname = NULL;
	unsigned long secs;
	unsigned long usecs;
	unsigned long long nsecs;

	if (PRINT_FIELD(COMM)) {
		if (latency_format)
			printf("%8.8s ", thread->comm);
		else if (PRINT_FIELD(SYM) && symbol_conf.use_callchain)
			printf("%s ", thread->comm);
		else
			printf("%16s ", thread->comm);
	}

	if (PRINT_FIELD(PID) && PRINT_FIELD(TID))
		printf("%5d/%-5d ", sample->pid, sample->tid);
	else if (PRINT_FIELD(PID))
		printf("%5d ", sample->pid);
	else if (PRINT_FIELD(TID))
		printf("%5d ", sample->tid);

	if (PRINT_FIELD(CPU)) {
		if (latency_format)
			printf("%3d ", sample->cpu);
		else
			printf("[%03d] ", sample->cpu);
	}

	if (PRINT_FIELD(TIME)) {
		nsecs = sample->time;
		secs = nsecs / NSECS_PER_SEC;
		nsecs -= secs * NSECS_PER_SEC;
		usecs = nsecs / NSECS_PER_USEC;
		printf("%5lu.%06lu: ", secs, usecs);
	}

	if (PRINT_FIELD(EVNAME)) {
		if (attr->type == PERF_TYPE_TRACEPOINT) {
			type = trace_parse_common_type(sample->raw_data);
			event = trace_find_event(type);
			if (event)
				evname = event->name;
		} else
			evname = __event_name(attr->type, attr->config);

		printf("%s: ", evname ? evname : "(unknown)");
	}
}

static void process_event(union perf_event *event __unused,
			  struct perf_sample *sample,
			  struct perf_session *session,
			  struct thread *thread)
{
	struct perf_event_attr *attr;
	struct perf_evsel *evsel;

	evsel = perf_evlist__id2evsel(session->evlist, sample->id);
	if (evsel == NULL) {
		pr_err("Invalid data. Contains samples with id not in "
		       "its header!\n");
		return;
	}
	attr = &evsel->attr;

	if (output_fields[attr->type] == 0)
		return;

	if (perf_session__check_attr(session, attr) < 0)
		return;

	print_sample_start(sample, thread, attr);

	if (PRINT_FIELD(TRACE))
		print_trace_event(sample->cpu, sample->raw_data,
				  sample->raw_size);

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

	printf("\n");
}

static int default_start_script(const char *script __unused,
				int argc __unused,
@@ -40,7 +219,7 @@ static int default_generate_script(const char *outfile __unused)
static struct scripting_ops default_scripting_ops = {
	.start_script		= default_start_script,
	.stop_script		= default_stop_script,
	.process_event		= print_event,
	.process_event		= process_event,
	.generate_script	= default_generate_script,
};

@@ -75,7 +254,6 @@ static int process_sample_event(union perf_event *event,
		return -1;
	}

	if (session->sample_type & PERF_SAMPLE_RAW) {
	if (debug_mode) {
		if (sample->time < last_timestamp) {
			pr_err("Samples misordered, previous: %" PRIu64
@@ -86,15 +264,7 @@ static int process_sample_event(union perf_event *event,
		last_timestamp = sample->time;
		return 0;
	}
		/*
		 * FIXME: better resolve from pid from the struct trace_entry
		 * field, although it should be the same than this perf
		 * event pid
		 */
		scripting_ops->process_event(sample->cpu, sample->raw_data,
					     sample->raw_size,
					     sample->time, thread->comm);
	}
	scripting_ops->process_event(event, sample, session, thread);

	session->hists.stats.total_period += sample->period;
	return 0;
@@ -102,7 +272,10 @@ static int process_sample_event(union perf_event *event,

static struct perf_event_ops event_ops = {
	.sample		 = process_sample_event,
	.mmap		 = perf_event__process_mmap,
	.comm		 = perf_event__process_comm,
	.exit		 = perf_event__process_task,
	.fork		 = perf_event__process_task,
	.attr		 = perf_event__process_attr,
	.event_type	 = perf_event__process_event_type,
	.tracing_data	 = perf_event__process_tracing_data,
@@ -280,6 +453,68 @@ static int parse_scriptname(const struct option *opt __used,
	return 0;
}

static int parse_output_fields(const struct option *opt __used,
			    const char *arg, int unset __used)
{
	char *tok;
	int i, imax = sizeof(all_output_options) / sizeof(struct output_option);
	int rc = 0;
	char *str = strdup(arg);
	int type = -1;

	if (!str)
		return -ENOMEM;

	tok = strtok(str, ":");
	if (!tok) {
		fprintf(stderr,
			"Invalid field string - not prepended with type.");
		return -EINVAL;
	}

	/* first word should state which event type user
	 * is specifying the fields
	 */
	if (!strcmp(tok, "hw"))
		type = PERF_TYPE_HARDWARE;
	else if (!strcmp(tok, "sw"))
		type = PERF_TYPE_SOFTWARE;
	else if (!strcmp(tok, "trace"))
		type = PERF_TYPE_TRACEPOINT;
	else {
		fprintf(stderr, "Invalid event type in field string.");
		return -EINVAL;
	}

	output_fields[type] = 0;
	while (1) {
		tok = strtok(NULL, ",");
		if (!tok)
			break;
		for (i = 0; i < imax; ++i) {
			if (strcmp(tok, all_output_options[i].str) == 0) {
				output_fields[type] |= all_output_options[i].field;
				break;
			}
		}
		if (i == imax) {
			fprintf(stderr, "Invalid field requested.");
			rc = -EINVAL;
			break;
		}
	}

	if (output_fields[type] == 0) {
		pr_debug("No fields requested for %s type. "
			 "Events will not be displayed\n", event_type(type));
	}

	output_set_by_user = true;

	free(str);
	return rc;
}

/* Helper function for filesystems that return a dent->d_type DT_UNKNOWN */
static int is_directory(const char *base_path, const struct dirent *dent)
{
@@ -592,6 +827,17 @@ static const struct option options[] = {
		    "input file name"),
	OPT_BOOLEAN('d', "debug-mode", &debug_mode,
		   "do various checks like samples ordering and lost events"),
	OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
		   "file", "vmlinux pathname"),
	OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name,
		   "file", "kallsyms pathname"),
	OPT_BOOLEAN('G', "hide-call-graph", &no_callchain,
		    "When printing symbols do not display call chain"),
	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. Fields: comm,tid,pid,time,cpu,event,trace,sym",
		     parse_output_fields),

	OPT_END()
};
@@ -772,14 +1018,22 @@ int cmd_script(int argc, const char **argv, const char *prefix __used)
	if (session == NULL)
		return -ENOMEM;

	if (strcmp(input_name, "-") &&
	    !perf_session__has_traces(session, "record -R"))
		return -EINVAL;
	if (!no_callchain)
		symbol_conf.use_callchain = true;
	else
		symbol_conf.use_callchain = false;

	if (generate_script_lang) {
		struct stat perf_stat;
		int input;

		if (output_set_by_user) {
			fprintf(stderr,
				"custom fields not supported for generated scripts");
			return -1;
		}

		int input = open(input_name, O_RDONLY);
		input = open(input_name, O_RDONLY);
		if (input < 0) {
			perror("failed to open file");
			exit(-1);
Loading