perf/core improvements and fixes:

. Improve 'perf bench' docs, by Namhyung Kim
 
 . Fix build when O= is not used, from David Ahern
 
 . Fix cross compilation build, from Namhyung Kim
 
 . Fix pipe mode when callchains are used, from David Ahern
 
 . Follow .gnu_debuglink section to find separate symbols, from Pierre-Loup A. Griffais
 
 . Fix 'perf test' raw events entries, from Jiri Olsa
 
 . Use the events description in the perf.data file, not the sysfs ones.
 
 Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2.0.14 (GNU/Linux)
 
 iQIcBAABAgAGBQJP61nAAAoJENZQFvNTUqpA1iQQAKFv7R0GsGpC5bIVTUFmDGMX
 PL+XJ6b9vx4Ut0p+GO2v0gUSkuyRAL1LLxQDgWks2jgeOSagJE430LYiSrwv5omn
 on1rkoGCGk9+TOnlR2E/OQZOlRQUN3/rIXbY3WEKDb/kU2pevFfgYFFXpC2qPoYm
 4otgfCyYVnzgvgoDj3CbFhQ6gCYLSZmw3WdPmoCPDWBLYMLX9OD10Q+ylg/GOrcG
 05GwkEJyjt9pMGJKo4FVWkoPKyL1UwEVhRm/rW4VqnvHOUPm45MK3j3M35yGlsLI
 9tDUkSygr0kGayyJyq1+1FtdZoYbCc49EgxKDtS47wvEyZ88N8v4mhUx45Fqb/2A
 5AJecv4F9N1PoJALuFVs2OPdWJ78eEijzpFouQxd4OxHakvx8VE1EKVvrCL24uuf
 EpFn6TPnGFvZLCAsnviWdPkph8EpoP43IQtrYJu7N6zE83m7b51k8aytXS4zxZzZ
 pbK2okMCT+mD6SRLGwXC5Sj6nl53KPl8K0JNuTX8ytEU22wtLDqzB2w7Hafhmrrd
 KCyBYlwfiEpiqvTE5AoPBWZgxOHrTEBzinglvWwaBCHI5ua5nxW2chH8rc0fhG9Z
 8T2AsYqahmOF2WVHgJsBKoM3SjcIO1QFFOCymt3HP4YTwYXgzBQi1cNThWZNxmE8
 AKU2+40KOuegGgy3qVzD
 =Hpga
 -----END PGP SIGNATURE-----

Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core

perf/core improvements and fixes:

 * Improve 'perf bench' docs, by Namhyung Kim

 * Fix build when O= is not used, from David Ahern

 * Fix cross compilation build, from Namhyung Kim

 * Fix pipe mode when callchains are used, from David Ahern

 * Follow .gnu_debuglink section to find separate symbols, from Pierre-Loup A. Griffais

 * Fix 'perf test' raw events entries, from Jiri Olsa

 * Use the events description in the perf.data file, not the sysfs ones.

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
Ingo Molnar 2012-06-29 15:11:26 +02:00
commit add79461a2
25 changed files with 471 additions and 201 deletions

View File

@ -12,7 +12,7 @@ SYNOPSIS
DESCRIPTION DESCRIPTION
----------- -----------
This 'perf bench' command is general framework for benchmark suites. This 'perf bench' command is a general framework for benchmark suites.
COMMON OPTIONS COMMON OPTIONS
-------------- --------------
@ -45,14 +45,20 @@ SUBSYSTEM
'sched':: 'sched'::
Scheduler and IPC mechanisms. Scheduler and IPC mechanisms.
'mem'::
Memory access performance.
'all'::
All benchmark subsystems.
SUITES FOR 'sched' SUITES FOR 'sched'
~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~
*messaging*:: *messaging*::
Suite for evaluating performance of scheduler and IPC mechanisms. Suite for evaluating performance of scheduler and IPC mechanisms.
Based on hackbench by Rusty Russell. Based on hackbench by Rusty Russell.
Options of *pipe* Options of *messaging*
^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^
-p:: -p::
--pipe:: --pipe::
Use pipe() instead of socketpair() Use pipe() instead of socketpair()
@ -115,6 +121,72 @@ Example of *pipe*
59004 ops/sec 59004 ops/sec
--------------------- ---------------------
SUITES FOR 'mem'
~~~~~~~~~~~~~~~~
*memcpy*::
Suite for evaluating performance of simple memory copy in various ways.
Options of *memcpy*
^^^^^^^^^^^^^^^^^^^
-l::
--length::
Specify length of memory to copy (default: 1MB).
Available units are B, KB, MB, GB and TB (case insensitive).
-r::
--routine::
Specify routine to copy (default: default).
Available routines are depend on the architecture.
On x86-64, x86-64-unrolled, x86-64-movsq and x86-64-movsb are supported.
-i::
--iterations::
Repeat memcpy invocation this number of times.
-c::
--clock::
Use perf's cpu-cycles event instead of gettimeofday syscall.
-o::
--only-prefault::
Show only the result with page faults before memcpy.
-n::
--no-prefault::
Show only the result without page faults before memcpy.
*memset*::
Suite for evaluating performance of simple memory set in various ways.
Options of *memset*
^^^^^^^^^^^^^^^^^^^
-l::
--length::
Specify length of memory to set (default: 1MB).
Available units are B, KB, MB, GB and TB (case insensitive).
-r::
--routine::
Specify routine to set (default: default).
Available routines are depend on the architecture.
On x86-64, x86-64-unrolled, x86-64-stosq and x86-64-stosb are supported.
-i::
--iterations::
Repeat memset invocation this number of times.
-c::
--clock::
Use perf's cpu-cycles event instead of gettimeofday syscall.
-o::
--only-prefault::
Show only the result with page faults before memset.
-n::
--no-prefault::
Show only the result without page faults before memset.
SEE ALSO SEE ALSO
-------- --------
linkperf:perf[1] linkperf:perf[1]

View File

@ -155,7 +155,7 @@ endif
### --- END CONFIGURATION SECTION --- ### --- END CONFIGURATION SECTION ---
BASIC_CFLAGS = -Iutil/include -Iarch/$(ARCH)/include -I$(OUTPUT)/util -I$(TRACE_EVENT_DIR) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE BASIC_CFLAGS = -Iutil/include -Iarch/$(ARCH)/include -I$(OUTPUT)util -I$(TRACE_EVENT_DIR) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
BASIC_LDFLAGS = BASIC_LDFLAGS =
# Guard against environment variables # Guard against environment variables

View File

@ -32,13 +32,13 @@ static bool no_prefault;
static const struct option options[] = { static const struct option options[] = {
OPT_STRING('l', "length", &length_str, "1MB", OPT_STRING('l', "length", &length_str, "1MB",
"Specify length of memory to copy. " "Specify length of memory to copy. "
"available unit: B, MB, GB (upper and lower)"), "Available units: B, KB, MB, GB and TB (upper and lower)"),
OPT_STRING('r', "routine", &routine, "default", OPT_STRING('r', "routine", &routine, "default",
"Specify routine to copy"), "Specify routine to copy"),
OPT_INTEGER('i', "iterations", &iterations, OPT_INTEGER('i', "iterations", &iterations,
"repeat memcpy() invocation this number of times"), "repeat memcpy() invocation this number of times"),
OPT_BOOLEAN('c', "clock", &use_clock, OPT_BOOLEAN('c', "clock", &use_clock,
"Use CPU clock for measuring"), "Use cycles event instead of gettimeofday() for measuring"),
OPT_BOOLEAN('o', "only-prefault", &only_prefault, OPT_BOOLEAN('o', "only-prefault", &only_prefault,
"Show only the result with page faults before memcpy()"), "Show only the result with page faults before memcpy()"),
OPT_BOOLEAN('n', "no-prefault", &no_prefault, OPT_BOOLEAN('n', "no-prefault", &no_prefault,

View File

@ -31,14 +31,14 @@ static bool no_prefault;
static const struct option options[] = { static const struct option options[] = {
OPT_STRING('l', "length", &length_str, "1MB", OPT_STRING('l', "length", &length_str, "1MB",
"Specify length of memory to copy. " "Specify length of memory to set. "
"available unit: B, MB, GB (upper and lower)"), "Available units: B, KB, MB, GB and TB (upper and lower)"),
OPT_STRING('r', "routine", &routine, "default", OPT_STRING('r', "routine", &routine, "default",
"Specify routine to copy"), "Specify routine to set"),
OPT_INTEGER('i', "iterations", &iterations, OPT_INTEGER('i', "iterations", &iterations,
"repeat memset() invocation this number of times"), "repeat memset() invocation this number of times"),
OPT_BOOLEAN('c', "clock", &use_clock, OPT_BOOLEAN('c', "clock", &use_clock,
"Use CPU clock for measuring"), "Use cycles event instead of gettimeofday() for measuring"),
OPT_BOOLEAN('o', "only-prefault", &only_prefault, OPT_BOOLEAN('o', "only-prefault", &only_prefault,
"Show only the result with page faults before memset()"), "Show only the result with page faults before memset()"),
OPT_BOOLEAN('n', "no-prefault", &no_prefault, OPT_BOOLEAN('n', "no-prefault", &no_prefault,

View File

@ -33,7 +33,7 @@ struct bench_suite {
}; };
\ \
/* sentinel: easy for help */ /* sentinel: easy for help */
#define suite_all { "all", "test all suite (pseudo suite)", NULL } #define suite_all { "all", "Test all benchmark suites", NULL }
static struct bench_suite sched_suites[] = { static struct bench_suite sched_suites[] = {
{ "messaging", { "messaging",
@ -75,7 +75,7 @@ static struct bench_subsys subsystems[] = {
"memory access performance", "memory access performance",
mem_suites }, mem_suites },
{ "all", /* sentinel: easy for help */ { "all", /* sentinel: easy for help */
"test all subsystem (pseudo subsystem)", "all benchmark subsystem",
NULL }, NULL },
{ NULL, { NULL,
NULL, NULL,

View File

@ -57,6 +57,11 @@ static unsigned long nr_allocs, nr_cross_allocs;
#define PATH_SYS_NODE "/sys/devices/system/node" #define PATH_SYS_NODE "/sys/devices/system/node"
struct perf_kmem {
struct perf_tool tool;
struct perf_session *session;
};
static void init_cpunode_map(void) static void init_cpunode_map(void)
{ {
FILE *fp; FILE *fp;
@ -278,14 +283,16 @@ static void process_free_event(void *data,
s_alloc->alloc_cpu = -1; s_alloc->alloc_cpu = -1;
} }
static void process_raw_event(union perf_event *raw_event __used, void *data, static void process_raw_event(struct perf_tool *tool,
union perf_event *raw_event __used, void *data,
int cpu, u64 timestamp, struct thread *thread) int cpu, u64 timestamp, struct thread *thread)
{ {
struct perf_kmem *kmem = container_of(tool, struct perf_kmem, tool);
struct event_format *event; struct event_format *event;
int type; int type;
type = trace_parse_common_type(data); type = trace_parse_common_type(kmem->session->pevent, data);
event = trace_find_event(type); event = pevent_find_event(kmem->session->pevent, type);
if (!strcmp(event->name, "kmalloc") || if (!strcmp(event->name, "kmalloc") ||
!strcmp(event->name, "kmem_cache_alloc")) { !strcmp(event->name, "kmem_cache_alloc")) {
@ -306,7 +313,7 @@ static void process_raw_event(union perf_event *raw_event __used, void *data,
} }
} }
static int process_sample_event(struct perf_tool *tool __used, static int process_sample_event(struct perf_tool *tool,
union perf_event *event, union perf_event *event,
struct perf_sample *sample, struct perf_sample *sample,
struct perf_evsel *evsel __used, struct perf_evsel *evsel __used,
@ -322,16 +329,18 @@ static int process_sample_event(struct perf_tool *tool __used,
dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
process_raw_event(event, sample->raw_data, sample->cpu, process_raw_event(tool, event, sample->raw_data, sample->cpu,
sample->time, thread); sample->time, thread);
return 0; return 0;
} }
static struct perf_tool perf_kmem = { static struct perf_kmem perf_kmem = {
.sample = process_sample_event, .tool = {
.comm = perf_event__process_comm, .sample = process_sample_event,
.ordered_samples = true, .comm = perf_event__process_comm,
.ordered_samples = true,
},
}; };
static double fragmentation(unsigned long n_req, unsigned long n_alloc) static double fragmentation(unsigned long n_req, unsigned long n_alloc)
@ -486,11 +495,15 @@ static void sort_result(void)
static int __cmd_kmem(void) static int __cmd_kmem(void)
{ {
int err = -EINVAL; int err = -EINVAL;
struct perf_session *session = perf_session__new(input_name, O_RDONLY, struct perf_session *session;
0, false, &perf_kmem);
session = perf_session__new(input_name, O_RDONLY, 0, false,
&perf_kmem.tool);
if (session == NULL) if (session == NULL)
return -ENOMEM; return -ENOMEM;
perf_kmem.session = session;
if (perf_session__create_kernel_maps(session) < 0) if (perf_session__create_kernel_maps(session) < 0)
goto out_delete; goto out_delete;
@ -498,7 +511,7 @@ static int __cmd_kmem(void)
goto out_delete; goto out_delete;
setup_pager(); setup_pager();
err = perf_session__process_events(session, &perf_kmem); err = perf_session__process_events(session, &perf_kmem.tool);
if (err != 0) if (err != 0)
goto out_delete; goto out_delete;
sort_result(); sort_result();

View File

@ -724,8 +724,8 @@ process_raw_event(void *data, int cpu, u64 timestamp, struct thread *thread)
struct event_format *event; struct event_format *event;
int type; int type;
type = trace_parse_common_type(data); type = trace_parse_common_type(session->pevent, data);
event = trace_find_event(type); event = pevent_find_event(session->pevent, type);
if (!strcmp(event->name, "lock_acquire")) if (!strcmp(event->name, "lock_acquire"))
process_lock_acquire_event(data, event, cpu, timestamp, thread); process_lock_acquire_event(data, event, cpu, timestamp, thread);

View File

@ -245,11 +245,12 @@ static int process_read_event(struct perf_tool *tool,
return 0; return 0;
} }
/* For pipe mode, sample_type is not currently set */
static int perf_report__setup_sample_type(struct perf_report *rep) static int perf_report__setup_sample_type(struct perf_report *rep)
{ {
struct perf_session *self = rep->session; struct perf_session *self = rep->session;
if (!(self->sample_type & PERF_SAMPLE_CALLCHAIN)) { if (!self->fd_pipe && !(self->sample_type & PERF_SAMPLE_CALLCHAIN)) {
if (sort__has_parent) { if (sort__has_parent) {
ui__error("Selected --sort parent, but no " ui__error("Selected --sort parent, but no "
"callchain data. Did you call " "callchain data. Did you call "
@ -272,7 +273,8 @@ static int perf_report__setup_sample_type(struct perf_report *rep)
} }
if (sort__branch_mode == 1) { if (sort__branch_mode == 1) {
if (!(self->sample_type & PERF_SAMPLE_BRANCH_STACK)) { if (!self->fd_pipe &&
!(self->sample_type & PERF_SAMPLE_BRANCH_STACK)) {
ui__error("Selected -b but no branch data. " ui__error("Selected -b but no branch data. "
"Did you call perf record without -b?\n"); "Did you call perf record without -b?\n");
return -1; return -1;

View File

@ -43,6 +43,11 @@ static u64 sleep_measurement_overhead;
static unsigned long nr_tasks; static unsigned long nr_tasks;
struct perf_sched {
struct perf_tool tool;
struct perf_session *session;
};
struct sched_atom; struct sched_atom;
struct task_desc { struct task_desc {
@ -1597,6 +1602,8 @@ static int perf_sched__process_tracepoint_sample(struct perf_tool *tool,
struct perf_evsel *evsel, struct perf_evsel *evsel,
struct machine *machine) struct machine *machine)
{ {
struct perf_sched *sched = container_of(tool, struct perf_sched, tool);
struct pevent *pevent = sched->session->pevent;
struct thread *thread = machine__findnew_thread(machine, sample->pid); struct thread *thread = machine__findnew_thread(machine, sample->pid);
if (thread == NULL) { if (thread == NULL) {
@ -1612,7 +1619,8 @@ static int perf_sched__process_tracepoint_sample(struct perf_tool *tool,
tracepoint_handler f = evsel->handler.func; tracepoint_handler f = evsel->handler.func;
if (evsel->handler.data == NULL) if (evsel->handler.data == NULL)
evsel->handler.data = trace_find_event(evsel->attr.config); evsel->handler.data = pevent_find_event(pevent,
evsel->attr.config);
f(tool, evsel->handler.data, sample, machine, thread); f(tool, evsel->handler.data, sample, machine, thread);
} }
@ -1620,12 +1628,14 @@ static int perf_sched__process_tracepoint_sample(struct perf_tool *tool,
return 0; return 0;
} }
static struct perf_tool perf_sched = { static struct perf_sched perf_sched = {
.sample = perf_sched__process_tracepoint_sample, .tool = {
.comm = perf_event__process_comm, .sample = perf_sched__process_tracepoint_sample,
.lost = perf_event__process_lost, .comm = perf_event__process_comm,
.fork = perf_event__process_task, .lost = perf_event__process_lost,
.ordered_samples = true, .fork = perf_event__process_task,
.ordered_samples = true,
},
}; };
static void read_events(bool destroy, struct perf_session **psession) static void read_events(bool destroy, struct perf_session **psession)
@ -1640,16 +1650,20 @@ static void read_events(bool destroy, struct perf_session **psession)
{ "sched:sched_process_exit", process_sched_exit_event, }, { "sched:sched_process_exit", process_sched_exit_event, },
{ "sched:sched_migrate_task", process_sched_migrate_task_event, }, { "sched:sched_migrate_task", process_sched_migrate_task_event, },
}; };
struct perf_session *session = perf_session__new(input_name, O_RDONLY, struct perf_session *session;
0, false, &perf_sched);
session = perf_session__new(input_name, O_RDONLY, 0, false,
&perf_sched.tool);
if (session == NULL) if (session == NULL)
die("No Memory"); die("No Memory");
err = perf_evlist__set_tracepoints_handlers_array(session->evlist, handlers); perf_sched.session = session;
err = perf_session__set_tracepoints_handlers(session, handlers);
assert(err == 0); assert(err == 0);
if (perf_session__has_traces(session, "record -R")) { if (perf_session__has_traces(session, "record -R")) {
err = perf_session__process_events(session, &perf_sched); err = perf_session__process_events(session, &perf_sched.tool);
if (err) if (err)
die("Failed to process events, error %d", err); die("Failed to process events, error %d", err);

View File

@ -28,6 +28,11 @@ static bool system_wide;
static const char *cpu_list; static const char *cpu_list;
static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
struct perf_script {
struct perf_tool tool;
struct perf_session *session;
};
enum perf_output_field { enum perf_output_field {
PERF_OUTPUT_COMM = 1U << 0, PERF_OUTPUT_COMM = 1U << 0,
PERF_OUTPUT_TID = 1U << 1, PERF_OUTPUT_TID = 1U << 1,
@ -257,7 +262,8 @@ static int perf_session__check_output_opt(struct perf_session *session)
return 0; return 0;
} }
static void print_sample_start(struct perf_sample *sample, static void print_sample_start(struct pevent *pevent,
struct perf_sample *sample,
struct thread *thread, struct thread *thread,
struct perf_evsel *evsel) struct perf_evsel *evsel)
{ {
@ -302,8 +308,14 @@ static void print_sample_start(struct perf_sample *sample,
if (PRINT_FIELD(EVNAME)) { if (PRINT_FIELD(EVNAME)) {
if (attr->type == PERF_TYPE_TRACEPOINT) { if (attr->type == PERF_TYPE_TRACEPOINT) {
type = trace_parse_common_type(sample->raw_data); /*
event = trace_find_event(type); * XXX Do we really need this here?
* perf_evlist__set_tracepoint_names should have done
* this already
*/
type = trace_parse_common_type(pevent,
sample->raw_data);
event = pevent_find_event(pevent, type);
if (event) if (event)
evname = event->name; evname = event->name;
} else } else
@ -404,6 +416,7 @@ static void print_sample_bts(union perf_event *event,
} }
static void process_event(union perf_event *event __unused, static void process_event(union perf_event *event __unused,
struct pevent *pevent,
struct perf_sample *sample, struct perf_sample *sample,
struct perf_evsel *evsel, struct perf_evsel *evsel,
struct machine *machine, struct machine *machine,
@ -414,7 +427,7 @@ static void process_event(union perf_event *event __unused,
if (output[attr->type].fields == 0) if (output[attr->type].fields == 0)
return; return;
print_sample_start(sample, thread, evsel); print_sample_start(pevent, sample, thread, evsel);
if (is_bts_event(attr)) { if (is_bts_event(attr)) {
print_sample_bts(event, sample, evsel, machine, thread); print_sample_bts(event, sample, evsel, machine, thread);
@ -422,7 +435,7 @@ static void process_event(union perf_event *event __unused,
} }
if (PRINT_FIELD(TRACE)) if (PRINT_FIELD(TRACE))
print_trace_event(sample->cpu, sample->raw_data, print_trace_event(pevent, sample->cpu, sample->raw_data,
sample->raw_size); sample->raw_size);
if (PRINT_FIELD(ADDR)) if (PRINT_FIELD(ADDR))
@ -453,7 +466,8 @@ static int default_stop_script(void)
return 0; return 0;
} }
static int default_generate_script(const char *outfile __unused) static int default_generate_script(struct pevent *pevent __unused,
const char *outfile __unused)
{ {
return 0; return 0;
} }
@ -491,6 +505,7 @@ static int process_sample_event(struct perf_tool *tool __used,
struct machine *machine) struct machine *machine)
{ {
struct addr_location al; struct addr_location al;
struct perf_script *scr = container_of(tool, struct perf_script, tool);
struct thread *thread = machine__findnew_thread(machine, event->ip.tid); struct thread *thread = machine__findnew_thread(machine, event->ip.tid);
if (thread == NULL) { if (thread == NULL) {
@ -522,24 +537,27 @@ static int process_sample_event(struct perf_tool *tool __used,
if (cpu_list && !test_bit(sample->cpu, cpu_bitmap)) if (cpu_list && !test_bit(sample->cpu, cpu_bitmap))
return 0; return 0;
scripting_ops->process_event(event, sample, evsel, machine, thread); scripting_ops->process_event(event, scr->session->pevent,
sample, evsel, machine, thread);
evsel->hists.stats.total_period += sample->period; evsel->hists.stats.total_period += sample->period;
return 0; return 0;
} }
static struct perf_tool perf_script = { static struct perf_script perf_script = {
.sample = process_sample_event, .tool = {
.mmap = perf_event__process_mmap, .sample = process_sample_event,
.comm = perf_event__process_comm, .mmap = perf_event__process_mmap,
.exit = perf_event__process_task, .comm = perf_event__process_comm,
.fork = perf_event__process_task, .exit = perf_event__process_task,
.attr = perf_event__process_attr, .fork = perf_event__process_task,
.event_type = perf_event__process_event_type, .attr = perf_event__process_attr,
.tracing_data = perf_event__process_tracing_data, .event_type = perf_event__process_event_type,
.build_id = perf_event__process_build_id, .tracing_data = perf_event__process_tracing_data,
.ordered_samples = true, .build_id = perf_event__process_build_id,
.ordering_requires_timestamps = true, .ordered_samples = true,
.ordering_requires_timestamps = true,
},
}; };
extern volatile int session_done; extern volatile int session_done;
@ -555,7 +573,7 @@ static int __cmd_script(struct perf_session *session)
signal(SIGINT, sig_handler); signal(SIGINT, sig_handler);
ret = perf_session__process_events(session, &perf_script); ret = perf_session__process_events(session, &perf_script.tool);
if (debug_mode) if (debug_mode)
pr_err("Misordered timestamps: %" PRIu64 "\n", nr_unordered); pr_err("Misordered timestamps: %" PRIu64 "\n", nr_unordered);
@ -1337,10 +1355,13 @@ int cmd_script(int argc, const char **argv, const char *prefix __used)
if (!script_name) if (!script_name)
setup_pager(); setup_pager();
session = perf_session__new(input_name, O_RDONLY, 0, false, &perf_script); session = perf_session__new(input_name, O_RDONLY, 0, false,
&perf_script.tool);
if (session == NULL) if (session == NULL)
return -ENOMEM; return -ENOMEM;
perf_script.session = session;
if (cpu_list) { if (cpu_list) {
if (perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap)) if (perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap))
return -1; return -1;
@ -1386,7 +1407,8 @@ int cmd_script(int argc, const char **argv, const char *prefix __used)
return -1; return -1;
} }
err = scripting_ops->generate_script("perf-script"); err = scripting_ops->generate_script(session->pevent,
"perf-script");
goto out; goto out;
} }

View File

@ -224,8 +224,8 @@ out_free_attrs:
return err; return err;
} }
static struct perf_evsel * struct perf_evsel *
perf_evlist__find_tracepoint_by_id(struct perf_evlist *evlist, int id) perf_evlist__find_tracepoint_by_id(struct perf_evlist *evlist, int id)
{ {
struct perf_evsel *evsel; struct perf_evsel *evsel;

View File

@ -73,6 +73,9 @@ int perf_evlist__set_tracepoints_handlers(struct perf_evlist *evlist,
#define perf_evlist__set_tracepoints_handlers_array(evlist, array) \ #define perf_evlist__set_tracepoints_handlers_array(evlist, array) \
perf_evlist__set_tracepoints_handlers(evlist, array, ARRAY_SIZE(array)) perf_evlist__set_tracepoints_handlers(evlist, array, ARRAY_SIZE(array))
struct perf_evsel *
perf_evlist__find_tracepoint_by_id(struct perf_evlist *evlist, int id);
void perf_evlist__id_add(struct perf_evlist *evlist, struct perf_evsel *evsel, void perf_evlist__id_add(struct perf_evlist *evlist, struct perf_evsel *evsel,
int cpu, int thread, u64 id); int cpu, int thread, u64 id);

View File

@ -15,7 +15,6 @@
#include "cpumap.h" #include "cpumap.h"
#include "thread_map.h" #include "thread_map.h"
#include "target.h" #include "target.h"
#include "../../include/linux/perf_event.h"
#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
#define GROUP_FD(group_fd, cpu) (*(int *)xyarray__entry(group_fd, cpu, 0)) #define GROUP_FD(group_fd, cpu) (*(int *)xyarray__entry(group_fd, cpu, 0))

View File

@ -1474,15 +1474,15 @@ out:
static int process_tracing_data(struct perf_file_section *section __unused, static int process_tracing_data(struct perf_file_section *section __unused,
struct perf_header *ph __unused, struct perf_header *ph __unused,
int feat __unused, int fd) int feat __unused, int fd, void *data)
{ {
trace_report(fd, false); trace_report(fd, data, false);
return 0; return 0;
} }
static int process_build_id(struct perf_file_section *section, static int process_build_id(struct perf_file_section *section,
struct perf_header *ph, struct perf_header *ph,
int feat __unused, int fd) int feat __unused, int fd, void *data __used)
{ {
if (perf_header__read_build_ids(ph, fd, section->offset, section->size)) if (perf_header__read_build_ids(ph, fd, section->offset, section->size))
pr_debug("Failed to read buildids, continuing...\n"); pr_debug("Failed to read buildids, continuing...\n");
@ -1493,7 +1493,7 @@ struct feature_ops {
int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist); int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist);
void (*print)(struct perf_header *h, int fd, FILE *fp); void (*print)(struct perf_header *h, int fd, FILE *fp);
int (*process)(struct perf_file_section *section, int (*process)(struct perf_file_section *section,
struct perf_header *h, int feat, int fd); struct perf_header *h, int feat, int fd, void *data);
const char *name; const char *name;
bool full_only; bool full_only;
}; };
@ -1988,7 +1988,7 @@ int perf_file_header__read(struct perf_file_header *header,
static int perf_file_section__process(struct perf_file_section *section, static int perf_file_section__process(struct perf_file_section *section,
struct perf_header *ph, struct perf_header *ph,
int feat, int fd, void *data __used) int feat, int fd, void *data)
{ {
if (lseek(fd, section->offset, SEEK_SET) == (off_t)-1) { if (lseek(fd, section->offset, SEEK_SET) == (off_t)-1) {
pr_debug("Failed to lseek to %" PRIu64 " offset for feature " pr_debug("Failed to lseek to %" PRIu64 " offset for feature "
@ -2004,7 +2004,7 @@ static int perf_file_section__process(struct perf_file_section *section,
if (!feat_ops[feat].process) if (!feat_ops[feat].process)
return 0; return 0;
return feat_ops[feat].process(section, ph, feat, fd); return feat_ops[feat].process(section, ph, feat, fd, data);
} }
static int perf_file_header__read_pipe(struct perf_pipe_file_header *header, static int perf_file_header__read_pipe(struct perf_pipe_file_header *header,
@ -2093,9 +2093,11 @@ static int read_attr(int fd, struct perf_header *ph,
return ret <= 0 ? -1 : 0; return ret <= 0 ? -1 : 0;
} }
static int perf_evsel__set_tracepoint_name(struct perf_evsel *evsel) static int perf_evsel__set_tracepoint_name(struct perf_evsel *evsel,
struct pevent *pevent)
{ {
struct event_format *event = trace_find_event(evsel->attr.config); struct event_format *event = pevent_find_event(pevent,
evsel->attr.config);
char bf[128]; char bf[128];
if (event == NULL) if (event == NULL)
@ -2109,13 +2111,14 @@ static int perf_evsel__set_tracepoint_name(struct perf_evsel *evsel)
return 0; return 0;
} }
static int perf_evlist__set_tracepoint_names(struct perf_evlist *evlist) static int perf_evlist__set_tracepoint_names(struct perf_evlist *evlist,
struct pevent *pevent)
{ {
struct perf_evsel *pos; struct perf_evsel *pos;
list_for_each_entry(pos, &evlist->entries, node) { list_for_each_entry(pos, &evlist->entries, node) {
if (pos->attr.type == PERF_TYPE_TRACEPOINT && if (pos->attr.type == PERF_TYPE_TRACEPOINT &&
perf_evsel__set_tracepoint_name(pos)) perf_evsel__set_tracepoint_name(pos, pevent))
return -1; return -1;
} }
@ -2198,12 +2201,12 @@ int perf_session__read_header(struct perf_session *session, int fd)
event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type); event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type);
} }
perf_header__process_sections(header, fd, NULL, perf_header__process_sections(header, fd, &session->pevent,
perf_file_section__process); perf_file_section__process);
lseek(fd, header->data_offset, SEEK_SET); lseek(fd, header->data_offset, SEEK_SET);
if (perf_evlist__set_tracepoint_names(session->evlist)) if (perf_evlist__set_tracepoint_names(session->evlist, session->pevent))
goto out_delete_evlist; goto out_delete_evlist;
header->frozen = 1; header->frozen = 1;
@ -2419,8 +2422,8 @@ int perf_event__process_tracing_data(union perf_event *event,
lseek(session->fd, offset + sizeof(struct tracing_data_event), lseek(session->fd, offset + sizeof(struct tracing_data_event),
SEEK_SET); SEEK_SET);
size_read = trace_report(session->fd, session->repipe); size_read = trace_report(session->fd, &session->pevent,
session->repipe);
padding = ALIGN(size_read, sizeof(u64)) - size_read; padding = ALIGN(size_read, sizeof(u64)) - size_read;
if (read(session->fd, buf, padding) < 0) if (read(session->fd, buf, padding) < 0)

View File

@ -413,19 +413,20 @@ static int test__checkevent_pmu_name(struct perf_evlist *evlist)
{ {
struct perf_evsel *evsel; struct perf_evsel *evsel;
/* cpu/config=1,name=krava1/u */ /* cpu/config=1,name=krava/u */
evsel = list_entry(evlist->entries.next, struct perf_evsel, node); evsel = list_entry(evlist->entries.next, struct perf_evsel, node);
TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries); TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type); TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config); TEST_ASSERT_VAL("wrong config", 1 == evsel->attr.config);
TEST_ASSERT_VAL("wrong name", !strcmp(perf_evsel__name(evsel), "krava")); TEST_ASSERT_VAL("wrong name", !strcmp(perf_evsel__name(evsel), "krava"));
/* cpu/config=2/" */ /* cpu/config=2/u" */
evsel = list_entry(evsel->node.next, struct perf_evsel, node); evsel = list_entry(evsel->node.next, struct perf_evsel, node);
TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries); TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->nr_entries);
TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type); TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type);
TEST_ASSERT_VAL("wrong config", 2 == evsel->attr.config); TEST_ASSERT_VAL("wrong config", 2 == evsel->attr.config);
TEST_ASSERT_VAL("wrong name", !strcmp(perf_evsel__name(evsel), "raw 0x2")); TEST_ASSERT_VAL("wrong name",
!strcmp(perf_evsel__name(evsel), "raw 0x2:u"));
return 0; return 0;
} }

View File

@ -233,7 +233,8 @@ static void define_event_symbols(struct event_format *event,
define_event_symbols(event, ev_name, args->next); define_event_symbols(event, ev_name, args->next);
} }
static inline struct event_format *find_cache_event(int type) static inline
struct event_format *find_cache_event(struct pevent *pevent, int type)
{ {
static char ev_name[256]; static char ev_name[256];
struct event_format *event; struct event_format *event;
@ -241,7 +242,7 @@ static inline struct event_format *find_cache_event(int type)
if (events[type]) if (events[type])
return events[type]; return events[type];
events[type] = event = trace_find_event(type); events[type] = event = pevent_find_event(pevent, type);
if (!event) if (!event)
return NULL; return NULL;
@ -252,7 +253,8 @@ static inline struct event_format *find_cache_event(int type)
return event; return event;
} }
static void perl_process_tracepoint(union perf_event *pevent __unused, static void perl_process_tracepoint(union perf_event *perf_event __unused,
struct pevent *pevent,
struct perf_sample *sample, struct perf_sample *sample,
struct perf_evsel *evsel, struct perf_evsel *evsel,
struct machine *machine __unused, struct machine *machine __unused,
@ -275,13 +277,13 @@ static void perl_process_tracepoint(union perf_event *pevent __unused,
if (evsel->attr.type != PERF_TYPE_TRACEPOINT) if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
return; return;
type = trace_parse_common_type(data); type = trace_parse_common_type(pevent, data);
event = find_cache_event(type); event = find_cache_event(pevent, type);
if (!event) if (!event)
die("ug! no event found for type %d", type); die("ug! no event found for type %d", type);
pid = trace_parse_common_pid(data); pid = trace_parse_common_pid(pevent, data);
sprintf(handler, "%s::%s", event->system, event->name); sprintf(handler, "%s::%s", event->system, event->name);
@ -314,7 +316,8 @@ static void perl_process_tracepoint(union perf_event *pevent __unused,
offset = field->offset; offset = field->offset;
XPUSHs(sv_2mortal(newSVpv((char *)data + offset, 0))); XPUSHs(sv_2mortal(newSVpv((char *)data + offset, 0)));
} else { /* FIELD_IS_NUMERIC */ } else { /* FIELD_IS_NUMERIC */
val = read_size(data + field->offset, field->size); val = read_size(pevent, data + field->offset,
field->size);
if (field->flags & FIELD_IS_SIGNED) { if (field->flags & FIELD_IS_SIGNED) {
XPUSHs(sv_2mortal(newSViv(val))); XPUSHs(sv_2mortal(newSViv(val)));
} else { } else {
@ -368,14 +371,15 @@ static void perl_process_event_generic(union perf_event *pevent __unused,
LEAVE; LEAVE;
} }
static void perl_process_event(union perf_event *pevent, static void perl_process_event(union perf_event *event,
struct pevent *pevent,
struct perf_sample *sample, struct perf_sample *sample,
struct perf_evsel *evsel, struct perf_evsel *evsel,
struct machine *machine, struct machine *machine,
struct thread *thread) struct thread *thread)
{ {
perl_process_tracepoint(pevent, sample, evsel, machine, thread); perl_process_tracepoint(event, pevent, sample, evsel, machine, thread);
perl_process_event_generic(pevent, sample, evsel, machine, thread); perl_process_event_generic(event, sample, evsel, machine, thread);
} }
static void run_start_sub(void) static void run_start_sub(void)
@ -448,7 +452,7 @@ static int perl_stop_script(void)
return 0; return 0;
} }
static int perl_generate_script(const char *outfile) static int perl_generate_script(struct pevent *pevent, const char *outfile)
{ {
struct event_format *event = NULL; struct event_format *event = NULL;
struct format_field *f; struct format_field *f;
@ -495,7 +499,7 @@ static int perl_generate_script(const char *outfile)
fprintf(ofp, "sub trace_begin\n{\n\t# optional\n}\n\n"); fprintf(ofp, "sub trace_begin\n{\n\t# optional\n}\n\n");
fprintf(ofp, "sub trace_end\n{\n\t# optional\n}\n\n"); fprintf(ofp, "sub trace_end\n{\n\t# optional\n}\n\n");
while ((event = trace_find_next_event(event))) { while ((event = trace_find_next_event(pevent, event))) {
fprintf(ofp, "sub %s::%s\n{\n", event->system, event->name); fprintf(ofp, "sub %s::%s\n{\n", event->system, event->name);
fprintf(ofp, "\tmy ("); fprintf(ofp, "\tmy (");

View File

@ -190,7 +190,8 @@ static void define_event_symbols(struct event_format *event,
define_event_symbols(event, ev_name, args->next); define_event_symbols(event, ev_name, args->next);
} }
static inline struct event_format *find_cache_event(int type) static inline
struct event_format *find_cache_event(struct pevent *pevent, int type)
{ {
static char ev_name[256]; static char ev_name[256];
struct event_format *event; struct event_format *event;
@ -198,7 +199,7 @@ static inline struct event_format *find_cache_event(int type)
if (events[type]) if (events[type])
return events[type]; return events[type];
events[type] = event = trace_find_event(type); events[type] = event = pevent_find_event(pevent, type);
if (!event) if (!event)
return NULL; return NULL;
@ -209,7 +210,8 @@ static inline struct event_format *find_cache_event(int type)
return event; return event;
} }
static void python_process_event(union perf_event *pevent __unused, static void python_process_event(union perf_event *perf_event __unused,
struct pevent *pevent,
struct perf_sample *sample, struct perf_sample *sample,
struct perf_evsel *evsel __unused, struct perf_evsel *evsel __unused,
struct machine *machine __unused, struct machine *machine __unused,
@ -233,13 +235,13 @@ static void python_process_event(union perf_event *pevent __unused,
if (!t) if (!t)
Py_FatalError("couldn't create Python tuple"); Py_FatalError("couldn't create Python tuple");
type = trace_parse_common_type(data); type = trace_parse_common_type(pevent, data);
event = find_cache_event(type); event = find_cache_event(pevent, type);
if (!event) if (!event)
die("ug! no event found for type %d", type); die("ug! no event found for type %d", type);
pid = trace_parse_common_pid(data); pid = trace_parse_common_pid(pevent, data);
sprintf(handler_name, "%s__%s", event->system, event->name); sprintf(handler_name, "%s__%s", event->system, event->name);
@ -284,7 +286,8 @@ static void python_process_event(union perf_event *pevent __unused,
offset = field->offset; offset = field->offset;
obj = PyString_FromString((char *)data + offset); obj = PyString_FromString((char *)data + offset);
} else { /* FIELD_IS_NUMERIC */ } else { /* FIELD_IS_NUMERIC */
val = read_size(data + field->offset, field->size); val = read_size(pevent, data + field->offset,
field->size);
if (field->flags & FIELD_IS_SIGNED) { if (field->flags & FIELD_IS_SIGNED) {
if ((long long)val >= LONG_MIN && if ((long long)val >= LONG_MIN &&
(long long)val <= LONG_MAX) (long long)val <= LONG_MAX)
@ -438,7 +441,7 @@ out:
return err; return err;
} }
static int python_generate_script(const char *outfile) static int python_generate_script(struct pevent *pevent, const char *outfile)
{ {
struct event_format *event = NULL; struct event_format *event = NULL;
struct format_field *f; struct format_field *f;
@ -487,7 +490,7 @@ static int python_generate_script(const char *outfile)
fprintf(ofp, "def trace_end():\n"); fprintf(ofp, "def trace_end():\n");
fprintf(ofp, "\tprint \"in trace_end\"\n\n"); fprintf(ofp, "\tprint \"in trace_end\"\n\n");
while ((event = trace_find_next_event(event))) { while ((event = trace_find_next_event(pevent, event))) {
fprintf(ofp, "def %s__%s(", event->system, event->name); fprintf(ofp, "def %s__%s(", event->system, event->name);
fprintf(ofp, "event_name, "); fprintf(ofp, "event_name, ");
fprintf(ofp, "context, "); fprintf(ofp, "context, ");

View File

@ -14,6 +14,7 @@
#include "sort.h" #include "sort.h"
#include "util.h" #include "util.h"
#include "cpumap.h" #include "cpumap.h"
#include "event-parse.h"
static int perf_session__open(struct perf_session *self, bool force) static int perf_session__open(struct perf_session *self, bool force)
{ {
@ -1610,3 +1611,58 @@ void perf_session__fprintf_info(struct perf_session *session, FILE *fp,
perf_header__fprintf_info(session, fp, full); perf_header__fprintf_info(session, fp, full);
fprintf(fp, "# ========\n#\n"); fprintf(fp, "# ========\n#\n");
} }
int __perf_session__set_tracepoints_handlers(struct perf_session *session,
const struct perf_evsel_str_handler *assocs,
size_t nr_assocs)
{
struct perf_evlist *evlist = session->evlist;
struct event_format *format;
struct perf_evsel *evsel;
char *tracepoint, *name;
size_t i;
int err;
for (i = 0; i < nr_assocs; i++) {
err = -ENOMEM;
tracepoint = strdup(assocs[i].name);
if (tracepoint == NULL)
goto out;
err = -ENOENT;
name = strchr(tracepoint, ':');
if (name == NULL)
goto out_free;
*name++ = '\0';
format = pevent_find_event_by_name(session->pevent,
tracepoint, name);
if (format == NULL) {
/*
* Adding a handler for an event not in the session,
* just ignore it.
*/
goto next;
}
evsel = perf_evlist__find_tracepoint_by_id(evlist, format->id);
if (evsel == NULL)
goto next;
err = -EEXIST;
if (evsel->handler.func != NULL)
goto out_free;
evsel->handler.func = assocs[i].handler;
next:
free(tracepoint);
}
err = 0;
out:
return err;
out_free:
free(tracepoint);
goto out;
}

View File

@ -33,6 +33,7 @@ struct perf_session {
struct machine host_machine; struct machine host_machine;
struct rb_root machines; struct rb_root machines;
struct perf_evlist *evlist; struct perf_evlist *evlist;
struct pevent *pevent;
/* /*
* FIXME: Need to split this up further, we need global * FIXME: Need to split this up further, we need global
* stats + per event stats. 'perf diff' also needs * stats + per event stats. 'perf diff' also needs
@ -158,4 +159,13 @@ int perf_session__cpu_bitmap(struct perf_session *session,
const char *cpu_list, unsigned long *cpu_bitmap); const char *cpu_list, unsigned long *cpu_bitmap);
void perf_session__fprintf_info(struct perf_session *s, FILE *fp, bool full); void perf_session__fprintf_info(struct perf_session *s, FILE *fp, bool full);
struct perf_evsel_str_handler;
int __perf_session__set_tracepoints_handlers(struct perf_session *session,
const struct perf_evsel_str_handler *assocs,
size_t nr_assocs);
#define perf_session__set_tracepoints_handlers(session, array) \
__perf_session__set_tracepoints_handlers(session, array, ARRAY_SIZE(array))
#endif /* __PERF_SESSION_H */ #endif /* __PERF_SESSION_H */

View File

@ -1590,11 +1590,62 @@ out:
return err; return err;
} }
static int filename__read_debuglink(const char *filename,
char *debuglink, size_t size)
{
int fd, err = -1;
Elf *elf;
GElf_Ehdr ehdr;
GElf_Shdr shdr;
Elf_Data *data;
Elf_Scn *sec;
Elf_Kind ek;
fd = open(filename, O_RDONLY);
if (fd < 0)
goto out;
elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
if (elf == NULL) {
pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename);
goto out_close;
}
ek = elf_kind(elf);
if (ek != ELF_K_ELF)
goto out_close;
if (gelf_getehdr(elf, &ehdr) == NULL) {
pr_err("%s: cannot get elf header.\n", __func__);
goto out_close;
}
sec = elf_section_by_name(elf, &ehdr, &shdr,
".gnu_debuglink", NULL);
if (sec == NULL)
goto out_close;
data = elf_getdata(sec, NULL);
if (data == NULL)
goto out_close;
/* the start of this section is a zero-terminated string */
strncpy(debuglink, data->d_buf, size);
elf_end(elf);
out_close:
close(fd);
out:
return err;
}
char dso__symtab_origin(const struct dso *dso) char dso__symtab_origin(const struct dso *dso)
{ {
static const char origin[] = { static const char origin[] = {
[SYMTAB__KALLSYMS] = 'k', [SYMTAB__KALLSYMS] = 'k',
[SYMTAB__JAVA_JIT] = 'j', [SYMTAB__JAVA_JIT] = 'j',
[SYMTAB__DEBUGLINK] = 'l',
[SYMTAB__BUILD_ID_CACHE] = 'B', [SYMTAB__BUILD_ID_CACHE] = 'B',
[SYMTAB__FEDORA_DEBUGINFO] = 'f', [SYMTAB__FEDORA_DEBUGINFO] = 'f',
[SYMTAB__UBUNTU_DEBUGINFO] = 'u', [SYMTAB__UBUNTU_DEBUGINFO] = 'u',
@ -1662,10 +1713,22 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
*/ */
want_symtab = 1; want_symtab = 1;
restart: restart:
for (dso->symtab_type = SYMTAB__BUILD_ID_CACHE; for (dso->symtab_type = SYMTAB__DEBUGLINK;
dso->symtab_type != SYMTAB__NOT_FOUND; dso->symtab_type != SYMTAB__NOT_FOUND;
dso->symtab_type++) { dso->symtab_type++) {
switch (dso->symtab_type) { switch (dso->symtab_type) {
case SYMTAB__DEBUGLINK: {
char *debuglink;
strncpy(name, dso->long_name, size);
debuglink = name + dso->long_name_len;
while (debuglink != name && *debuglink != '/')
debuglink--;
if (*debuglink == '/')
debuglink++;
filename__read_debuglink(dso->long_name, debuglink,
size - (debuglink - name));
}
break;
case SYMTAB__BUILD_ID_CACHE: case SYMTAB__BUILD_ID_CACHE:
/* skip the locally configured cache if a symfs is given */ /* skip the locally configured cache if a symfs is given */
if (symbol_conf.symfs[0] || if (symbol_conf.symfs[0] ||

View File

@ -257,6 +257,7 @@ enum symtab_type {
SYMTAB__KALLSYMS = 0, SYMTAB__KALLSYMS = 0,
SYMTAB__GUEST_KALLSYMS, SYMTAB__GUEST_KALLSYMS,
SYMTAB__JAVA_JIT, SYMTAB__JAVA_JIT,
SYMTAB__DEBUGLINK,
SYMTAB__BUILD_ID_CACHE, SYMTAB__BUILD_ID_CACHE,
SYMTAB__FEDORA_DEBUGINFO, SYMTAB__FEDORA_DEBUGINFO,
SYMTAB__UBUNTU_DEBUGINFO, SYMTAB__UBUNTU_DEBUGINFO,

View File

@ -32,29 +32,25 @@ int header_page_size_size;
int header_page_ts_size; int header_page_ts_size;
int header_page_data_offset; int header_page_data_offset;
struct pevent *perf_pevent;
static struct pevent *pevent;
bool latency_format; bool latency_format;
int read_trace_init(int file_bigendian, int host_bigendian) struct pevent *read_trace_init(int file_bigendian, int host_bigendian)
{ {
if (pevent) struct pevent *pevent = pevent_alloc();
return 0;
perf_pevent = pevent_alloc(); if (pevent != NULL) {
pevent = perf_pevent; pevent_set_flag(pevent, PEVENT_NSEC_OUTPUT);
pevent_set_file_bigendian(pevent, file_bigendian);
pevent_set_host_bigendian(pevent, host_bigendian);
}
pevent_set_flag(pevent, PEVENT_NSEC_OUTPUT); return pevent;
pevent_set_file_bigendian(pevent, file_bigendian);
pevent_set_host_bigendian(pevent, host_bigendian);
return 0;
} }
static int get_common_field(struct scripting_context *context, static int get_common_field(struct scripting_context *context,
int *offset, int *size, const char *type) int *offset, int *size, const char *type)
{ {
struct pevent *pevent = context->pevent;
struct event_format *event; struct event_format *event;
struct format_field *field; struct format_field *field;
@ -150,7 +146,7 @@ void *raw_field_ptr(struct event_format *event, const char *name, void *data)
return data + field->offset; return data + field->offset;
} }
int trace_parse_common_type(void *data) int trace_parse_common_type(struct pevent *pevent, void *data)
{ {
struct pevent_record record; struct pevent_record record;
@ -158,7 +154,7 @@ int trace_parse_common_type(void *data)
return pevent_data_type(pevent, &record); return pevent_data_type(pevent, &record);
} }
int trace_parse_common_pid(void *data) int trace_parse_common_pid(struct pevent *pevent, void *data)
{ {
struct pevent_record record; struct pevent_record record;
@ -166,27 +162,21 @@ int trace_parse_common_pid(void *data)
return pevent_data_pid(pevent, &record); return pevent_data_pid(pevent, &record);
} }
unsigned long long read_size(void *ptr, int size) unsigned long long read_size(struct pevent *pevent, void *ptr, int size)
{ {
return pevent_read_number(pevent, ptr, size); return pevent_read_number(pevent, ptr, size);
} }
struct event_format *trace_find_event(int type) void print_trace_event(struct pevent *pevent, int cpu, void *data, int size)
{
return pevent_find_event(pevent, type);
}
void print_trace_event(int cpu, void *data, int size)
{ {
struct event_format *event; struct event_format *event;
struct pevent_record record; struct pevent_record record;
struct trace_seq s; struct trace_seq s;
int type; int type;
type = trace_parse_common_type(data); type = trace_parse_common_type(pevent, data);
event = trace_find_event(type); event = pevent_find_event(pevent, type);
if (!event) { if (!event) {
warning("ug! no event found for type %d", type); warning("ug! no event found for type %d", type);
return; return;
@ -203,8 +193,8 @@ void print_trace_event(int cpu, void *data, int size)
printf("\n"); printf("\n");
} }
void print_event(int cpu, void *data, int size, unsigned long long nsecs, void print_event(struct pevent *pevent, int cpu, void *data, int size,
char *comm) unsigned long long nsecs, char *comm)
{ {
struct pevent_record record; struct pevent_record record;
struct trace_seq s; struct trace_seq s;
@ -227,7 +217,8 @@ void print_event(int cpu, void *data, int size, unsigned long long nsecs,
printf("\n"); printf("\n");
} }
void parse_proc_kallsyms(char *file, unsigned int size __unused) void parse_proc_kallsyms(struct pevent *pevent,
char *file, unsigned int size __unused)
{ {
unsigned long long addr; unsigned long long addr;
char *func; char *func;
@ -258,7 +249,8 @@ void parse_proc_kallsyms(char *file, unsigned int size __unused)
} }
} }
void parse_ftrace_printk(char *file, unsigned int size __unused) void parse_ftrace_printk(struct pevent *pevent,
char *file, unsigned int size __unused)
{ {
unsigned long long addr; unsigned long long addr;
char *printk; char *printk;
@ -282,17 +274,19 @@ void parse_ftrace_printk(char *file, unsigned int size __unused)
} }
} }
int parse_ftrace_file(char *buf, unsigned long size) int parse_ftrace_file(struct pevent *pevent, char *buf, unsigned long size)
{ {
return pevent_parse_event(pevent, buf, size, "ftrace"); return pevent_parse_event(pevent, buf, size, "ftrace");
} }
int parse_event_file(char *buf, unsigned long size, char *sys) int parse_event_file(struct pevent *pevent,
char *buf, unsigned long size, char *sys)
{ {
return pevent_parse_event(pevent, buf, size, sys); return pevent_parse_event(pevent, buf, size, sys);
} }
struct event_format *trace_find_next_event(struct event_format *event) struct event_format *trace_find_next_event(struct pevent *pevent,
struct event_format *event)
{ {
static int idx; static int idx;

View File

@ -114,20 +114,20 @@ static void skip(int size)
}; };
} }
static unsigned int read4(void) static unsigned int read4(struct pevent *pevent)
{ {
unsigned int data; unsigned int data;
read_or_die(&data, 4); read_or_die(&data, 4);
return __data2host4(perf_pevent, data); return __data2host4(pevent, data);
} }
static unsigned long long read8(void) static unsigned long long read8(struct pevent *pevent)
{ {
unsigned long long data; unsigned long long data;
read_or_die(&data, 8); read_or_die(&data, 8);
return __data2host8(perf_pevent, data); return __data2host8(pevent, data);
} }
static char *read_string(void) static char *read_string(void)
@ -168,12 +168,12 @@ static char *read_string(void)
return str; return str;
} }
static void read_proc_kallsyms(void) static void read_proc_kallsyms(struct pevent *pevent)
{ {
unsigned int size; unsigned int size;
char *buf; char *buf;
size = read4(); size = read4(pevent);
if (!size) if (!size)
return; return;
@ -181,29 +181,29 @@ static void read_proc_kallsyms(void)
read_or_die(buf, size); read_or_die(buf, size);
buf[size] = '\0'; buf[size] = '\0';
parse_proc_kallsyms(buf, size); parse_proc_kallsyms(pevent, buf, size);
free(buf); free(buf);
} }
static void read_ftrace_printk(void) static void read_ftrace_printk(struct pevent *pevent)
{ {
unsigned int size; unsigned int size;
char *buf; char *buf;
size = read4(); size = read4(pevent);
if (!size) if (!size)
return; return;
buf = malloc_or_die(size); buf = malloc_or_die(size);
read_or_die(buf, size); read_or_die(buf, size);
parse_ftrace_printk(buf, size); parse_ftrace_printk(pevent, buf, size);
free(buf); free(buf);
} }
static void read_header_files(void) static void read_header_files(struct pevent *pevent)
{ {
unsigned long long size; unsigned long long size;
char *header_event; char *header_event;
@ -214,7 +214,7 @@ static void read_header_files(void)
if (memcmp(buf, "header_page", 12) != 0) if (memcmp(buf, "header_page", 12) != 0)
die("did not read header page"); die("did not read header page");
size = read8(); size = read8(pevent);
skip(size); skip(size);
/* /*
@ -227,47 +227,48 @@ static void read_header_files(void)
if (memcmp(buf, "header_event", 13) != 0) if (memcmp(buf, "header_event", 13) != 0)
die("did not read header event"); die("did not read header event");
size = read8(); size = read8(pevent);
header_event = malloc_or_die(size); header_event = malloc_or_die(size);
read_or_die(header_event, size); read_or_die(header_event, size);
free(header_event); free(header_event);
} }
static void read_ftrace_file(unsigned long long size) static void read_ftrace_file(struct pevent *pevent, unsigned long long size)
{ {
char *buf; char *buf;
buf = malloc_or_die(size); buf = malloc_or_die(size);
read_or_die(buf, size); read_or_die(buf, size);
parse_ftrace_file(buf, size); parse_ftrace_file(pevent, buf, size);
free(buf); free(buf);
} }
static void read_event_file(char *sys, unsigned long long size) static void read_event_file(struct pevent *pevent, char *sys,
unsigned long long size)
{ {
char *buf; char *buf;
buf = malloc_or_die(size); buf = malloc_or_die(size);
read_or_die(buf, size); read_or_die(buf, size);
parse_event_file(buf, size, sys); parse_event_file(pevent, buf, size, sys);
free(buf); free(buf);
} }
static void read_ftrace_files(void) static void read_ftrace_files(struct pevent *pevent)
{ {
unsigned long long size; unsigned long long size;
int count; int count;
int i; int i;
count = read4(); count = read4(pevent);
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
size = read8(); size = read8(pevent);
read_ftrace_file(size); read_ftrace_file(pevent, size);
} }
} }
static void read_event_files(void) static void read_event_files(struct pevent *pevent)
{ {
unsigned long long size; unsigned long long size;
char *sys; char *sys;
@ -275,15 +276,15 @@ static void read_event_files(void)
int count; int count;
int i,x; int i,x;
systems = read4(); systems = read4(pevent);
for (i = 0; i < systems; i++) { for (i = 0; i < systems; i++) {
sys = read_string(); sys = read_string();
count = read4(); count = read4(pevent);
for (x=0; x < count; x++) { for (x=0; x < count; x++) {
size = read8(); size = read8(pevent);
read_event_file(sys, size); read_event_file(pevent, sys, size);
} }
} }
} }
@ -377,7 +378,7 @@ static int calc_index(void *ptr, int cpu)
return (unsigned long)ptr - (unsigned long)cpu_data[cpu].page; return (unsigned long)ptr - (unsigned long)cpu_data[cpu].page;
} }
struct pevent_record *trace_peek_data(int cpu) struct pevent_record *trace_peek_data(struct pevent *pevent, int cpu)
{ {
struct pevent_record *data; struct pevent_record *data;
void *page = cpu_data[cpu].page; void *page = cpu_data[cpu].page;
@ -399,15 +400,15 @@ struct pevent_record *trace_peek_data(int cpu)
/* FIXME: handle header page */ /* FIXME: handle header page */
if (header_page_ts_size != 8) if (header_page_ts_size != 8)
die("expected a long long type for timestamp"); die("expected a long long type for timestamp");
cpu_data[cpu].timestamp = data2host8(perf_pevent, ptr); cpu_data[cpu].timestamp = data2host8(pevent, ptr);
ptr += 8; ptr += 8;
switch (header_page_size_size) { switch (header_page_size_size) {
case 4: case 4:
cpu_data[cpu].page_size = data2host4(perf_pevent, ptr); cpu_data[cpu].page_size = data2host4(pevent, ptr);
ptr += 4; ptr += 4;
break; break;
case 8: case 8:
cpu_data[cpu].page_size = data2host8(perf_pevent, ptr); cpu_data[cpu].page_size = data2host8(pevent, ptr);
ptr += 8; ptr += 8;
break; break;
default: default:
@ -421,10 +422,10 @@ read_again:
if (idx >= cpu_data[cpu].page_size) { if (idx >= cpu_data[cpu].page_size) {
get_next_page(cpu); get_next_page(cpu);
return trace_peek_data(cpu); return trace_peek_data(pevent, cpu);
} }
type_len_ts = data2host4(perf_pevent, ptr); type_len_ts = data2host4(pevent, ptr);
ptr += 4; ptr += 4;
type_len = type_len4host(type_len_ts); type_len = type_len4host(type_len_ts);
@ -434,14 +435,14 @@ read_again:
case RINGBUF_TYPE_PADDING: case RINGBUF_TYPE_PADDING:
if (!delta) if (!delta)
die("error, hit unexpected end of page"); die("error, hit unexpected end of page");
length = data2host4(perf_pevent, ptr); length = data2host4(pevent, ptr);
ptr += 4; ptr += 4;
length *= 4; length *= 4;
ptr += length; ptr += length;
goto read_again; goto read_again;
case RINGBUF_TYPE_TIME_EXTEND: case RINGBUF_TYPE_TIME_EXTEND:
extend = data2host4(perf_pevent, ptr); extend = data2host4(pevent, ptr);
ptr += 4; ptr += 4;
extend <<= TS_SHIFT; extend <<= TS_SHIFT;
extend += delta; extend += delta;
@ -452,7 +453,7 @@ read_again:
ptr += 12; ptr += 12;
break; break;
case 0: case 0:
length = data2host4(perf_pevent, ptr); length = data2host4(pevent, ptr);
ptr += 4; ptr += 4;
die("here! length=%d", length); die("here! length=%d", length);
break; break;
@ -477,17 +478,17 @@ read_again:
return data; return data;
} }
struct pevent_record *trace_read_data(int cpu) struct pevent_record *trace_read_data(struct pevent *pevent, int cpu)
{ {
struct pevent_record *data; struct pevent_record *data;
data = trace_peek_data(cpu); data = trace_peek_data(pevent, cpu);
cpu_data[cpu].next = NULL; cpu_data[cpu].next = NULL;
return data; return data;
} }
ssize_t trace_report(int fd, bool __repipe) ssize_t trace_report(int fd, struct pevent **ppevent, bool __repipe)
{ {
char buf[BUFSIZ]; char buf[BUFSIZ];
char test[] = { 23, 8, 68 }; char test[] = { 23, 8, 68 };
@ -519,30 +520,32 @@ ssize_t trace_report(int fd, bool __repipe)
file_bigendian = buf[0]; file_bigendian = buf[0];
host_bigendian = bigendian(); host_bigendian = bigendian();
read_trace_init(file_bigendian, host_bigendian); *ppevent = read_trace_init(file_bigendian, host_bigendian);
if (*ppevent == NULL)
die("read_trace_init failed");
read_or_die(buf, 1); read_or_die(buf, 1);
long_size = buf[0]; long_size = buf[0];
page_size = read4(); page_size = read4(*ppevent);
read_header_files(); read_header_files(*ppevent);
read_ftrace_files(); read_ftrace_files(*ppevent);
read_event_files(); read_event_files(*ppevent);
read_proc_kallsyms(); read_proc_kallsyms(*ppevent);
read_ftrace_printk(); read_ftrace_printk(*ppevent);
size = calc_data_size - 1; size = calc_data_size - 1;
calc_data_size = 0; calc_data_size = 0;
repipe = false; repipe = false;
if (show_funcs) { if (show_funcs) {
pevent_print_funcs(perf_pevent); pevent_print_funcs(*ppevent);
return size; return size;
} }
if (show_printk) { if (show_printk) {
pevent_print_printk(perf_pevent); pevent_print_printk(*ppevent);
return size; return size;
} }

View File

@ -36,6 +36,7 @@ static int stop_script_unsupported(void)
} }
static void process_event_unsupported(union perf_event *event __unused, static void process_event_unsupported(union perf_event *event __unused,
struct pevent *pevent __unused,
struct perf_sample *sample __unused, struct perf_sample *sample __unused,
struct perf_evsel *evsel __unused, struct perf_evsel *evsel __unused,
struct machine *machine __unused, struct machine *machine __unused,
@ -61,7 +62,8 @@ static int python_start_script_unsupported(const char *script __unused,
return -1; return -1;
} }
static int python_generate_script_unsupported(const char *outfile __unused) static int python_generate_script_unsupported(struct pevent *pevent __unused,
const char *outfile __unused)
{ {
print_python_unsupported_msg(); print_python_unsupported_msg();
@ -122,7 +124,8 @@ static int perl_start_script_unsupported(const char *script __unused,
return -1; return -1;
} }
static int perl_generate_script_unsupported(const char *outfile __unused) static int perl_generate_script_unsupported(struct pevent *pevent __unused,
const char *outfile __unused)
{ {
print_perl_unsupported_msg(); print_perl_unsupported_msg();

View File

@ -8,6 +8,7 @@
struct machine; struct machine;
struct perf_sample; struct perf_sample;
union perf_event; union perf_event;
struct perf_tool;
struct thread; struct thread;
extern int header_page_size_size; extern int header_page_size_size;
@ -29,35 +30,36 @@ enum {
int bigendian(void); int bigendian(void);
int read_trace_init(int file_bigendian, int host_bigendian); struct pevent *read_trace_init(int file_bigendian, int host_bigendian);
void print_trace_event(int cpu, void *data, int size); void print_trace_event(struct pevent *pevent, int cpu, void *data, int size);
void print_event(int cpu, void *data, int size, unsigned long long nsecs, void print_event(struct pevent *pevent, int cpu, void *data, int size,
char *comm); unsigned long long nsecs, char *comm);
int parse_ftrace_file(char *buf, unsigned long size); int parse_ftrace_file(struct pevent *pevent, char *buf, unsigned long size);
int parse_event_file(char *buf, unsigned long size, char *sys); int parse_event_file(struct pevent *pevent,
char *buf, unsigned long size, char *sys);
struct pevent_record *trace_peek_data(int cpu); struct pevent_record *trace_peek_data(struct pevent *pevent, int cpu);
struct event_format *trace_find_event(int type);
unsigned long long unsigned long long
raw_field_value(struct event_format *event, const char *name, void *data); raw_field_value(struct event_format *event, const char *name, void *data);
void *raw_field_ptr(struct event_format *event, const char *name, void *data); void *raw_field_ptr(struct event_format *event, const char *name, void *data);
void parse_proc_kallsyms(char *file, unsigned int size __unused); void parse_proc_kallsyms(struct pevent *pevent, char *file, unsigned int size);
void parse_ftrace_printk(char *file, unsigned int size __unused); void parse_ftrace_printk(struct pevent *pevent, char *file, unsigned int size);
ssize_t trace_report(int fd, bool repipe); ssize_t trace_report(int fd, struct pevent **pevent, bool repipe);
int trace_parse_common_type(void *data); int trace_parse_common_type(struct pevent *pevent, void *data);
int trace_parse_common_pid(void *data); int trace_parse_common_pid(struct pevent *pevent, void *data);
struct event_format *trace_find_next_event(struct event_format *event); struct event_format *trace_find_next_event(struct pevent *pevent,
unsigned long long read_size(void *ptr, int size); struct event_format *event);
unsigned long long read_size(struct pevent *pevent, void *ptr, int size);
unsigned long long eval_flag(const char *flag); unsigned long long eval_flag(const char *flag);
struct pevent_record *trace_read_data(int cpu); struct pevent_record *trace_read_data(struct pevent *pevent, int cpu);
int read_tracing_data(int fd, struct list_head *pattrs); int read_tracing_data(int fd, struct list_head *pattrs);
struct tracing_data { struct tracing_data {
@ -77,11 +79,12 @@ struct scripting_ops {
int (*start_script) (const char *script, int argc, const char **argv); int (*start_script) (const char *script, int argc, const char **argv);
int (*stop_script) (void); int (*stop_script) (void);
void (*process_event) (union perf_event *event, void (*process_event) (union perf_event *event,
struct pevent *pevent,
struct perf_sample *sample, struct perf_sample *sample,
struct perf_evsel *evsel, struct perf_evsel *evsel,
struct machine *machine, struct machine *machine,
struct thread *thread); struct thread *thread);
int (*generate_script) (const char *outfile); int (*generate_script) (struct pevent *pevent, const char *outfile);
}; };
int script_spec_register(const char *spec, struct scripting_ops *ops); int script_spec_register(const char *spec, struct scripting_ops *ops);
@ -90,6 +93,7 @@ void setup_perl_scripting(void);
void setup_python_scripting(void); void setup_python_scripting(void);
struct scripting_context { struct scripting_context {
struct pevent *pevent;
void *event_data; void *event_data;
}; };