You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge branch 'perf-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip
* 'perf-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip: (30 commits) trace, filters: Initialize the match variable in process_ops() properly trace, documentation: Fix branch profiling location in debugfs oprofile, s390: Cleanups oprofile, s390: Remove hwsampler_files.c and merge it into init.c perf: Fix tear-down of inherited group events perf: Reorder & optimize perf_event_context to remove alignment padding on 64 bit builds perf: Handle stopped state with tracepoints perf: Fix the software events state check perf, powerpc: Handle events that raise an exception without overflowing perf, x86: Use INTEL_*_CONSTRAINT() for all PEBS event constraints perf, x86: Clean up SandyBridge PEBS events perf lock: Fix sorting by wait_min perf tools: Version incorrect with some versions of grep perf evlist: New command to list the names of events present in a perf.data file perf script: Add support for H/W and S/W events perf script: Add support for dumping symbols perf script: Support custom field selection for output perf script: Move printing of 'common' data from print_event and rename perf tracing: Remove print_graph_cpu and print_graph_proc from trace-event-parse perf script: Change process_event prototype ...
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
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]
|
||||
@@ -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],
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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();
|
||||
}
|
||||
@@ -202,9 +202,20 @@ static struct thread_stat *thread_stat_findnew_first(u32 tid)
|
||||
SINGLE_KEY(nr_acquired)
|
||||
SINGLE_KEY(nr_contended)
|
||||
SINGLE_KEY(wait_time_total)
|
||||
SINGLE_KEY(wait_time_min)
|
||||
SINGLE_KEY(wait_time_max)
|
||||
|
||||
static int lock_stat_key_wait_time_min(struct lock_stat *one,
|
||||
struct lock_stat *two)
|
||||
{
|
||||
u64 s1 = one->wait_time_min;
|
||||
u64 s2 = two->wait_time_min;
|
||||
if (s1 == ULLONG_MAX)
|
||||
s1 = 0;
|
||||
if (s2 == ULLONG_MAX)
|
||||
s2 = 0;
|
||||
return s1 > s2;
|
||||
}
|
||||
|
||||
struct lock_key {
|
||||
/*
|
||||
* name: the value for specify by user
|
||||
|
||||
+277
-23
@@ -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,26 +254,17 @@ 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
|
||||
" this: %" PRIu64 "\n", last_timestamp,
|
||||
sample->time);
|
||||
nr_unordered++;
|
||||
}
|
||||
last_timestamp = sample->time;
|
||||
return 0;
|
||||
if (debug_mode) {
|
||||
if (sample->time < last_timestamp) {
|
||||
pr_err("Samples misordered, previous: %" PRIu64
|
||||
" this: %" PRIu64 "\n", last_timestamp,
|
||||
sample->time);
|
||||
nr_unordered++;
|
||||
}
|
||||
/*
|
||||
* 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);
|
||||
last_timestamp = sample->time;
|
||||
return 0;
|
||||
}
|
||||
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;
|
||||
|
||||
int input = open(input_name, O_RDONLY);
|
||||
if (output_set_by_user) {
|
||||
fprintf(stderr,
|
||||
"custom fields not supported for generated scripts");
|
||||
return -1;
|
||||
}
|
||||
|
||||
input = open(input_name, O_RDONLY);
|
||||
if (input < 0) {
|
||||
perror("failed to open file");
|
||||
exit(-1);
|
||||
|
||||
@@ -333,6 +333,12 @@ static int run_perf_stat(int argc __used, const char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
if (perf_evlist__set_filters(evsel_list)) {
|
||||
error("failed to set filter with %d (%s)\n", errno,
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable counters and exec the command:
|
||||
*/
|
||||
@@ -634,6 +640,8 @@ static const struct option options[] = {
|
||||
OPT_CALLBACK('e', "event", &evsel_list, "event",
|
||||
"event selector. use 'perf list' to list available events",
|
||||
parse_events),
|
||||
OPT_CALLBACK(0, "filter", &evsel_list, "filter",
|
||||
"event filter", parse_filter),
|
||||
OPT_BOOLEAN('i', "no-inherit", &no_inherit,
|
||||
"child tasks do not inherit counters"),
|
||||
OPT_INTEGER('p', "pid", &target_pid,
|
||||
|
||||
+10
-10
@@ -152,7 +152,7 @@ static int parse_source(struct sym_entry *syme)
|
||||
/*
|
||||
* We can't annotate with just /proc/kallsyms
|
||||
*/
|
||||
if (map->dso->origin == DSO__ORIG_KERNEL) {
|
||||
if (map->dso->symtab_type == SYMTAB__KALLSYMS) {
|
||||
pr_err("Can't annotate %s: No vmlinux file was found in the "
|
||||
"path\n", sym->name);
|
||||
sleep(1);
|
||||
@@ -515,24 +515,25 @@ static void handle_keypress(struct perf_session *session, int c)
|
||||
break;
|
||||
case 'E':
|
||||
if (top.evlist->nr_entries > 1) {
|
||||
int counter;
|
||||
fprintf(stderr, "\nAvailable events:");
|
||||
|
||||
list_for_each_entry(top.sym_evsel, &top.evlist->entries, node)
|
||||
fprintf(stderr, "\n\t%d %s", top.sym_evsel->idx, event_name(top.sym_evsel));
|
||||
|
||||
prompt_integer(&top.sym_counter, "Enter details event counter");
|
||||
prompt_integer(&counter, "Enter details event counter");
|
||||
|
||||
if (top.sym_counter >= top.evlist->nr_entries) {
|
||||
if (counter >= top.evlist->nr_entries) {
|
||||
top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node);
|
||||
top.sym_counter = 0;
|
||||
fprintf(stderr, "Sorry, no such event, using %s.\n", event_name(top.sym_evsel));
|
||||
sleep(1);
|
||||
break;
|
||||
}
|
||||
list_for_each_entry(top.sym_evsel, &top.evlist->entries, node)
|
||||
if (top.sym_evsel->idx == top.sym_counter)
|
||||
if (top.sym_evsel->idx == counter)
|
||||
break;
|
||||
} else top.sym_counter = 0;
|
||||
} else
|
||||
top.sym_evsel = list_entry(top.evlist->entries.next, struct perf_evsel, node);
|
||||
break;
|
||||
case 'f':
|
||||
prompt_integer(&top.count_filter, "Enter display event count filter");
|
||||
@@ -675,7 +676,7 @@ static int symbol_filter(struct map *map, struct symbol *sym)
|
||||
|
||||
for (i = 0; skip_symbols[i]; i++) {
|
||||
if (!strcmp(skip_symbols[i], name)) {
|
||||
syme->skip = 1;
|
||||
sym->ignore = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -768,7 +769,7 @@ static void perf_event__process_sample(const union perf_event *event,
|
||||
struct symbol *sym = sym_entry__symbol(top.sym_filter_entry);
|
||||
|
||||
pr_err("Can't annotate %s", sym->name);
|
||||
if (top.sym_filter_entry->map->dso->origin == DSO__ORIG_KERNEL) {
|
||||
if (top.sym_filter_entry->map->dso->symtab_type == SYMTAB__KALLSYMS) {
|
||||
pr_err(": No vmlinux file was found in the path:\n");
|
||||
machine__fprintf_vmlinux_path(machine, stderr);
|
||||
} else
|
||||
@@ -778,10 +779,9 @@ static void perf_event__process_sample(const union perf_event *event,
|
||||
}
|
||||
|
||||
syme = symbol__priv(al.sym);
|
||||
if (!syme->skip) {
|
||||
if (!al.sym->ignore) {
|
||||
struct perf_evsel *evsel;
|
||||
|
||||
syme->origin = origin;
|
||||
evsel = perf_evlist__id2evsel(top.evlist, sample->id);
|
||||
assert(evsel != NULL);
|
||||
syme->count[evsel->idx]++;
|
||||
|
||||
@@ -19,6 +19,7 @@ extern int cmd_bench(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_buildid_cache(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_buildid_list(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_diff(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_evlist(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_help(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_sched(int argc, const char **argv, const char *prefix);
|
||||
extern int cmd_list(int argc, const char **argv, const char *prefix);
|
||||
|
||||
@@ -8,6 +8,7 @@ perf-bench mainporcelain common
|
||||
perf-buildid-cache mainporcelain common
|
||||
perf-buildid-list mainporcelain common
|
||||
perf-diff mainporcelain common
|
||||
perf-evlist mainporcelain common
|
||||
perf-inject mainporcelain common
|
||||
perf-list mainporcelain common
|
||||
perf-sched mainporcelain common
|
||||
|
||||
@@ -313,6 +313,7 @@ static void handle_internal_command(int argc, const char **argv)
|
||||
{ "buildid-cache", cmd_buildid_cache, 0 },
|
||||
{ "buildid-list", cmd_buildid_list, 0 },
|
||||
{ "diff", cmd_diff, 0 },
|
||||
{ "evlist", cmd_evlist, 0 },
|
||||
{ "help", cmd_help, 0 },
|
||||
{ "list", cmd_list, 0 },
|
||||
{ "record", cmd_record, 0 },
|
||||
|
||||
@@ -23,10 +23,10 @@ if test -d ../../.git -o -f ../../.git &&
|
||||
then
|
||||
VN=$(echo "$VN" | sed -e 's/-/./g');
|
||||
else
|
||||
eval `grep '^VERSION\s*=' ../../Makefile|tr -d ' '`
|
||||
eval `grep '^PATCHLEVEL\s*=' ../../Makefile|tr -d ' '`
|
||||
eval `grep '^SUBLEVEL\s*=' ../../Makefile|tr -d ' '`
|
||||
eval `grep '^EXTRAVERSION\s*=' ../../Makefile|tr -d ' '`
|
||||
eval $(grep '^VERSION[[:space:]]*=' ../../Makefile|tr -d ' ')
|
||||
eval $(grep '^PATCHLEVEL[[:space:]]*=' ../../Makefile|tr -d ' ')
|
||||
eval $(grep '^SUBLEVEL[[:space:]]*=' ../../Makefile|tr -d ' ')
|
||||
eval $(grep '^EXTRAVERSION[[:space:]]*=' ../../Makefile|tr -d ' ')
|
||||
|
||||
VN="${VERSION}.${PATCHLEVEL}.${SUBLEVEL}${EXTRAVERSION}"
|
||||
fi
|
||||
|
||||
@@ -294,7 +294,7 @@ fallback:
|
||||
free_filename = false;
|
||||
}
|
||||
|
||||
if (dso->origin == DSO__ORIG_KERNEL) {
|
||||
if (dso->symtab_type == SYMTAB__KALLSYMS) {
|
||||
char bf[BUILD_ID_SIZE * 2 + 16] = " with build id ";
|
||||
char *build_id_msg = NULL;
|
||||
|
||||
|
||||
@@ -263,6 +263,28 @@ static char *event_cache_name(u8 cache_type, u8 cache_op, u8 cache_result)
|
||||
return name;
|
||||
}
|
||||
|
||||
const char *event_type(int type)
|
||||
{
|
||||
switch (type) {
|
||||
case PERF_TYPE_HARDWARE:
|
||||
return "hardware";
|
||||
|
||||
case PERF_TYPE_SOFTWARE:
|
||||
return "software";
|
||||
|
||||
case PERF_TYPE_TRACEPOINT:
|
||||
return "tracepoint";
|
||||
|
||||
case PERF_TYPE_HW_CACHE:
|
||||
return "hardware-cache";
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
const char *event_name(struct perf_evsel *evsel)
|
||||
{
|
||||
u64 config = evsel->attr.config;
|
||||
|
||||
@@ -20,6 +20,7 @@ struct tracepoint_path {
|
||||
extern struct tracepoint_path *tracepoint_id_to_path(u64 config);
|
||||
extern bool have_tracepoints(struct list_head *evlist);
|
||||
|
||||
const char *event_type(int type);
|
||||
const char *event_name(struct perf_evsel *event);
|
||||
extern const char *__event_name(int type, u64 config);
|
||||
|
||||
|
||||
@@ -245,9 +245,10 @@ static inline struct event *find_cache_event(int type)
|
||||
return event;
|
||||
}
|
||||
|
||||
static void perl_process_event(int cpu, void *data,
|
||||
int size __unused,
|
||||
unsigned long long nsecs, char *comm)
|
||||
static void perl_process_event(union perf_event *pevent __unused,
|
||||
struct perf_sample *sample,
|
||||
struct perf_session *session __unused,
|
||||
struct thread *thread)
|
||||
{
|
||||
struct format_field *field;
|
||||
static char handler[256];
|
||||
@@ -256,6 +257,10 @@ static void perl_process_event(int cpu, void *data,
|
||||
struct event *event;
|
||||
int type;
|
||||
int pid;
|
||||
int cpu = sample->cpu;
|
||||
void *data = sample->raw_data;
|
||||
unsigned long long nsecs = sample->time;
|
||||
char *comm = thread->comm;
|
||||
|
||||
dSP;
|
||||
|
||||
|
||||
@@ -204,9 +204,10 @@ static inline struct event *find_cache_event(int type)
|
||||
return event;
|
||||
}
|
||||
|
||||
static void python_process_event(int cpu, void *data,
|
||||
int size __unused,
|
||||
unsigned long long nsecs, char *comm)
|
||||
static void python_process_event(union perf_event *pevent __unused,
|
||||
struct perf_sample *sample,
|
||||
struct perf_session *session __unused,
|
||||
struct thread *thread)
|
||||
{
|
||||
PyObject *handler, *retval, *context, *t, *obj, *dict = NULL;
|
||||
static char handler_name[256];
|
||||
@@ -217,6 +218,10 @@ static void python_process_event(int cpu, void *data,
|
||||
unsigned n = 0;
|
||||
int type;
|
||||
int pid;
|
||||
int cpu = sample->cpu;
|
||||
void *data = sample->raw_data;
|
||||
unsigned long long nsecs = sample->time;
|
||||
char *comm = thread->comm;
|
||||
|
||||
t = PyTuple_New(MAX_FIELDS);
|
||||
if (!t)
|
||||
|
||||
@@ -1134,3 +1134,64 @@ size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp)
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void perf_session__print_symbols(union perf_event *event,
|
||||
struct perf_sample *sample,
|
||||
struct perf_session *session)
|
||||
{
|
||||
struct addr_location al;
|
||||
const char *symname, *dsoname;
|
||||
struct callchain_cursor *cursor = &session->callchain_cursor;
|
||||
struct callchain_cursor_node *node;
|
||||
|
||||
if (perf_event__preprocess_sample(event, session, &al, sample,
|
||||
NULL) < 0) {
|
||||
error("problem processing %d event, skipping it.\n",
|
||||
event->header.type);
|
||||
return;
|
||||
}
|
||||
|
||||
if (symbol_conf.use_callchain && sample->callchain) {
|
||||
|
||||
if (perf_session__resolve_callchain(session, al.thread,
|
||||
sample->callchain, NULL) != 0) {
|
||||
if (verbose)
|
||||
error("Failed to resolve callchain. Skipping\n");
|
||||
return;
|
||||
}
|
||||
callchain_cursor_commit(cursor);
|
||||
|
||||
while (1) {
|
||||
node = callchain_cursor_current(cursor);
|
||||
if (!node)
|
||||
break;
|
||||
|
||||
if (node->sym && node->sym->name)
|
||||
symname = node->sym->name;
|
||||
else
|
||||
symname = "";
|
||||
|
||||
if (node->map && node->map->dso && node->map->dso->name)
|
||||
dsoname = node->map->dso->name;
|
||||
else
|
||||
dsoname = "";
|
||||
|
||||
printf("\t%16" PRIx64 " %s (%s)\n", node->ip, symname, dsoname);
|
||||
|
||||
callchain_cursor_advance(cursor);
|
||||
}
|
||||
|
||||
} else {
|
||||
if (al.sym && al.sym->name)
|
||||
symname = al.sym->name;
|
||||
else
|
||||
symname = "";
|
||||
|
||||
if (al.map && al.map->dso && al.map->dso->name)
|
||||
dsoname = al.map->dso->name;
|
||||
else
|
||||
dsoname = "";
|
||||
|
||||
printf("%16" PRIx64 " %s (%s)", al.addr, symname, dsoname);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,4 +159,8 @@ static inline int perf_session__parse_sample(struct perf_session *session,
|
||||
session->sample_id_all, sample);
|
||||
}
|
||||
|
||||
void perf_session__print_symbols(union perf_event *event,
|
||||
struct perf_sample *sample,
|
||||
struct perf_session *session);
|
||||
|
||||
#endif /* __PERF_SESSION_H */
|
||||
|
||||
+32
-32
@@ -207,7 +207,7 @@ struct dso *dso__new(const char *name)
|
||||
dso__set_short_name(self, self->name);
|
||||
for (i = 0; i < MAP__NR_TYPES; ++i)
|
||||
self->symbols[i] = self->symbol_names[i] = RB_ROOT;
|
||||
self->origin = DSO__ORIG_NOT_FOUND;
|
||||
self->symtab_type = SYMTAB__NOT_FOUND;
|
||||
self->loaded = 0;
|
||||
self->sorted_by_name = 0;
|
||||
self->has_build_id = 0;
|
||||
@@ -680,9 +680,9 @@ int dso__load_kallsyms(struct dso *self, const char *filename,
|
||||
return -1;
|
||||
|
||||
if (self->kernel == DSO_TYPE_GUEST_KERNEL)
|
||||
self->origin = DSO__ORIG_GUEST_KERNEL;
|
||||
self->symtab_type = SYMTAB__GUEST_KALLSYMS;
|
||||
else
|
||||
self->origin = DSO__ORIG_KERNEL;
|
||||
self->symtab_type = SYMTAB__KALLSYMS;
|
||||
|
||||
return dso__split_kallsyms(self, map, filter);
|
||||
}
|
||||
@@ -1204,7 +1204,7 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name,
|
||||
}
|
||||
curr_map->map_ip = identity__map_ip;
|
||||
curr_map->unmap_ip = identity__map_ip;
|
||||
curr_dso->origin = self->origin;
|
||||
curr_dso->symtab_type = self->symtab_type;
|
||||
map_groups__insert(kmap->kmaps, curr_map);
|
||||
dsos__add(&self->node, curr_dso);
|
||||
dso__set_loaded(curr_dso, map->type);
|
||||
@@ -1430,21 +1430,21 @@ out:
|
||||
char dso__symtab_origin(const struct dso *self)
|
||||
{
|
||||
static const char origin[] = {
|
||||
[DSO__ORIG_KERNEL] = 'k',
|
||||
[DSO__ORIG_JAVA_JIT] = 'j',
|
||||
[DSO__ORIG_BUILD_ID_CACHE] = 'B',
|
||||
[DSO__ORIG_FEDORA] = 'f',
|
||||
[DSO__ORIG_UBUNTU] = 'u',
|
||||
[DSO__ORIG_BUILDID] = 'b',
|
||||
[DSO__ORIG_DSO] = 'd',
|
||||
[DSO__ORIG_KMODULE] = 'K',
|
||||
[DSO__ORIG_GUEST_KERNEL] = 'g',
|
||||
[DSO__ORIG_GUEST_KMODULE] = 'G',
|
||||
[SYMTAB__KALLSYMS] = 'k',
|
||||
[SYMTAB__JAVA_JIT] = 'j',
|
||||
[SYMTAB__BUILD_ID_CACHE] = 'B',
|
||||
[SYMTAB__FEDORA_DEBUGINFO] = 'f',
|
||||
[SYMTAB__UBUNTU_DEBUGINFO] = 'u',
|
||||
[SYMTAB__BUILDID_DEBUGINFO] = 'b',
|
||||
[SYMTAB__SYSTEM_PATH_DSO] = 'd',
|
||||
[SYMTAB__SYSTEM_PATH_KMODULE] = 'K',
|
||||
[SYMTAB__GUEST_KALLSYMS] = 'g',
|
||||
[SYMTAB__GUEST_KMODULE] = 'G',
|
||||
};
|
||||
|
||||
if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND)
|
||||
if (self == NULL || self->symtab_type == SYMTAB__NOT_FOUND)
|
||||
return '!';
|
||||
return origin[self->origin];
|
||||
return origin[self->symtab_type];
|
||||
}
|
||||
|
||||
int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
|
||||
@@ -1477,8 +1477,8 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
|
||||
|
||||
if (strncmp(self->name, "/tmp/perf-", 10) == 0) {
|
||||
ret = dso__load_perf_map(self, map, filter);
|
||||
self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT :
|
||||
DSO__ORIG_NOT_FOUND;
|
||||
self->symtab_type = ret > 0 ? SYMTAB__JAVA_JIT :
|
||||
SYMTAB__NOT_FOUND;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1486,26 +1486,26 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
|
||||
* On the first pass, only load images if they have a full symtab.
|
||||
* Failing that, do a second pass where we accept .dynsym also
|
||||
*/
|
||||
for (self->origin = DSO__ORIG_BUILD_ID_CACHE, want_symtab = 1;
|
||||
self->origin != DSO__ORIG_NOT_FOUND;
|
||||
self->origin++) {
|
||||
switch (self->origin) {
|
||||
case DSO__ORIG_BUILD_ID_CACHE:
|
||||
for (self->symtab_type = SYMTAB__BUILD_ID_CACHE, want_symtab = 1;
|
||||
self->symtab_type != SYMTAB__NOT_FOUND;
|
||||
self->symtab_type++) {
|
||||
switch (self->symtab_type) {
|
||||
case SYMTAB__BUILD_ID_CACHE:
|
||||
/* skip the locally configured cache if a symfs is given */
|
||||
if (symbol_conf.symfs[0] ||
|
||||
(dso__build_id_filename(self, name, size) == NULL)) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case DSO__ORIG_FEDORA:
|
||||
case SYMTAB__FEDORA_DEBUGINFO:
|
||||
snprintf(name, size, "%s/usr/lib/debug%s.debug",
|
||||
symbol_conf.symfs, self->long_name);
|
||||
break;
|
||||
case DSO__ORIG_UBUNTU:
|
||||
case SYMTAB__UBUNTU_DEBUGINFO:
|
||||
snprintf(name, size, "%s/usr/lib/debug%s",
|
||||
symbol_conf.symfs, self->long_name);
|
||||
break;
|
||||
case DSO__ORIG_BUILDID: {
|
||||
case SYMTAB__BUILDID_DEBUGINFO: {
|
||||
char build_id_hex[BUILD_ID_SIZE * 2 + 1];
|
||||
|
||||
if (!self->has_build_id)
|
||||
@@ -1519,11 +1519,11 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
|
||||
symbol_conf.symfs, build_id_hex, build_id_hex + 2);
|
||||
}
|
||||
break;
|
||||
case DSO__ORIG_DSO:
|
||||
case SYMTAB__SYSTEM_PATH_DSO:
|
||||
snprintf(name, size, "%s%s",
|
||||
symbol_conf.symfs, self->long_name);
|
||||
break;
|
||||
case DSO__ORIG_GUEST_KMODULE:
|
||||
case SYMTAB__GUEST_KMODULE:
|
||||
if (map->groups && machine)
|
||||
root_dir = machine->root_dir;
|
||||
else
|
||||
@@ -1532,7 +1532,7 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
|
||||
root_dir, self->long_name);
|
||||
break;
|
||||
|
||||
case DSO__ORIG_KMODULE:
|
||||
case SYMTAB__SYSTEM_PATH_KMODULE:
|
||||
snprintf(name, size, "%s%s", symbol_conf.symfs,
|
||||
self->long_name);
|
||||
break;
|
||||
@@ -1544,7 +1544,7 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
|
||||
*/
|
||||
if (want_symtab) {
|
||||
want_symtab = 0;
|
||||
self->origin = DSO__ORIG_BUILD_ID_CACHE;
|
||||
self->symtab_type = SYMTAB__BUILD_ID_CACHE;
|
||||
} else
|
||||
continue;
|
||||
}
|
||||
@@ -1757,9 +1757,9 @@ struct map *machine__new_module(struct machine *self, u64 start,
|
||||
return NULL;
|
||||
|
||||
if (machine__is_host(self))
|
||||
dso->origin = DSO__ORIG_KMODULE;
|
||||
dso->symtab_type = SYMTAB__SYSTEM_PATH_KMODULE;
|
||||
else
|
||||
dso->origin = DSO__ORIG_GUEST_KMODULE;
|
||||
dso->symtab_type = SYMTAB__GUEST_KMODULE;
|
||||
map_groups__insert(&self->kmaps, map);
|
||||
return map;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user