Commit 5a982132 authored by Ingo Molnar's avatar Ingo Molnar

Merge tag 'perf-core-for-mingo' of...

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

Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo:

 * Add missing 'finished_round' event forwarding in 'perf inject', from Adrian Hunter.

 * Assorted tidy ups, from Adrian Hunter.

 * Fall back to sysfs event names when parsing fails, from Andi Kleen.

 * List pmu events in perf list, from Andi Kleen.

 * Cleanup some memory allocation/freeing uses, from David Ahern.

 * Add option to collapse undesired parts of call graph, from Greg Price.

 * Prep work for multi perf data file storage, from Jiri Olsa.

 * Add support for more than two files comparision in 'perf diff', from Jiri Olsa

 * A few more 'perf test' improvements, from Jiri Olsa

 * libtraceevent cleanups, from Namhyung Kim.

 * Remove odd build stall in 'perf sched' by moving a large struct initialization
   from a local variable to a global one, from Namhyung Kim.

 * Add support for callchains in the gtk UI, from Namhyung Kim.

 * Do not apply symfs for an absolute vmlinux path, fix from Namhyung Kim.

 * Use default include path notation for libtraceevent, from Robert Richter.

 * Fix 'make tools/perf', from Robert Richter.

 * Make Power7 events available, from Runzhen Wang.

 * Add --objdump option to 'perf top', from Sukadev Bhattiprolu.
Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parents e43fff2b 2a08c3ec
...@@ -142,11 +142,11 @@ extern ssize_t power_events_sysfs_show(struct device *dev, ...@@ -142,11 +142,11 @@ extern ssize_t power_events_sysfs_show(struct device *dev,
#define EVENT_PTR(_id, _suffix) &EVENT_VAR(_id, _suffix).attr.attr #define EVENT_PTR(_id, _suffix) &EVENT_VAR(_id, _suffix).attr.attr
#define EVENT_ATTR(_name, _id, _suffix) \ #define EVENT_ATTR(_name, _id, _suffix) \
PMU_EVENT_ATTR(_name, EVENT_VAR(_id, _suffix), PME_PM_##_id, \ PMU_EVENT_ATTR(_name, EVENT_VAR(_id, _suffix), PME_##_id, \
power_events_sysfs_show) power_events_sysfs_show)
#define GENERIC_EVENT_ATTR(_name, _id) EVENT_ATTR(_name, _id, _g) #define GENERIC_EVENT_ATTR(_name, _id) EVENT_ATTR(_name, _id, _g)
#define GENERIC_EVENT_PTR(_id) EVENT_PTR(_id, _g) #define GENERIC_EVENT_PTR(_id) EVENT_PTR(_id, _g)
#define POWER_EVENT_ATTR(_name, _id) EVENT_ATTR(PM_##_name, _id, _p) #define POWER_EVENT_ATTR(_name, _id) EVENT_ATTR(_name, _id, _p)
#define POWER_EVENT_PTR(_id) EVENT_PTR(_id, _p) #define POWER_EVENT_PTR(_id) EVENT_PTR(_id, _p)
This diff is collapsed.
...@@ -53,37 +53,13 @@ ...@@ -53,37 +53,13 @@
/* /*
* Power7 event codes. * Power7 event codes.
*/ */
#define PME_PM_CYC 0x1e #define EVENT(_name, _code) \
#define PME_PM_GCT_NOSLOT_CYC 0x100f8 PME_##_name = _code,
#define PME_PM_CMPLU_STALL 0x4000a
#define PME_PM_INST_CMPL 0x2 enum {
#define PME_PM_LD_REF_L1 0xc880 #include "power7-events-list.h"
#define PME_PM_LD_MISS_L1 0x400f0 };
#define PME_PM_BRU_FIN 0x10068 #undef EVENT
#define PME_PM_BR_MPRED 0x400f6
#define PME_PM_CMPLU_STALL_FXU 0x20014
#define PME_PM_CMPLU_STALL_DIV 0x40014
#define PME_PM_CMPLU_STALL_SCALAR 0x40012
#define PME_PM_CMPLU_STALL_SCALAR_LONG 0x20018
#define PME_PM_CMPLU_STALL_VECTOR 0x2001c
#define PME_PM_CMPLU_STALL_VECTOR_LONG 0x4004a
#define PME_PM_CMPLU_STALL_LSU 0x20012
#define PME_PM_CMPLU_STALL_REJECT 0x40016
#define PME_PM_CMPLU_STALL_ERAT_MISS 0x40018
#define PME_PM_CMPLU_STALL_DCACHE_MISS 0x20016
#define PME_PM_CMPLU_STALL_STORE 0x2004a
#define PME_PM_CMPLU_STALL_THRD 0x1001c
#define PME_PM_CMPLU_STALL_IFU 0x4004c
#define PME_PM_CMPLU_STALL_BRU 0x4004e
#define PME_PM_GCT_NOSLOT_IC_MISS 0x2001a
#define PME_PM_GCT_NOSLOT_BR_MPRED 0x4001a
#define PME_PM_GCT_NOSLOT_BR_MPRED_IC_MISS 0x4001c
#define PME_PM_GRP_CMPL 0x30004
#define PME_PM_1PLUS_PPC_CMPL 0x100f2
#define PME_PM_CMPLU_STALL_DFU 0x2003c
#define PME_PM_RUN_CYC 0x200f4
#define PME_PM_RUN_INST_CMPL 0x400fa
/* /*
* Layout of constraint bits: * Layout of constraint bits:
...@@ -398,96 +374,36 @@ static int power7_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = { ...@@ -398,96 +374,36 @@ static int power7_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = {
}; };
GENERIC_EVENT_ATTR(cpu-cycles, CYC); GENERIC_EVENT_ATTR(cpu-cycles, PM_CYC);
GENERIC_EVENT_ATTR(stalled-cycles-frontend, GCT_NOSLOT_CYC); GENERIC_EVENT_ATTR(stalled-cycles-frontend, PM_GCT_NOSLOT_CYC);
GENERIC_EVENT_ATTR(stalled-cycles-backend, CMPLU_STALL); GENERIC_EVENT_ATTR(stalled-cycles-backend, PM_CMPLU_STALL);
GENERIC_EVENT_ATTR(instructions, INST_CMPL); GENERIC_EVENT_ATTR(instructions, PM_INST_CMPL);
GENERIC_EVENT_ATTR(cache-references, LD_REF_L1); GENERIC_EVENT_ATTR(cache-references, PM_LD_REF_L1);
GENERIC_EVENT_ATTR(cache-misses, LD_MISS_L1); GENERIC_EVENT_ATTR(cache-misses, PM_LD_MISS_L1);
GENERIC_EVENT_ATTR(branch-instructions, BRU_FIN); GENERIC_EVENT_ATTR(branch-instructions, PM_BRU_FIN);
GENERIC_EVENT_ATTR(branch-misses, BR_MPRED); GENERIC_EVENT_ATTR(branch-misses, PM_BR_MPRED);
POWER_EVENT_ATTR(CYC, CYC); #define EVENT(_name, _code) POWER_EVENT_ATTR(_name, _name);
POWER_EVENT_ATTR(GCT_NOSLOT_CYC, GCT_NOSLOT_CYC); #include "power7-events-list.h"
POWER_EVENT_ATTR(CMPLU_STALL, CMPLU_STALL); #undef EVENT
POWER_EVENT_ATTR(INST_CMPL, INST_CMPL);
POWER_EVENT_ATTR(LD_REF_L1, LD_REF_L1); #define EVENT(_name, _code) POWER_EVENT_PTR(_name),
POWER_EVENT_ATTR(LD_MISS_L1, LD_MISS_L1);
POWER_EVENT_ATTR(BRU_FIN, BRU_FIN)
POWER_EVENT_ATTR(BR_MPRED, BR_MPRED);
POWER_EVENT_ATTR(CMPLU_STALL_FXU, CMPLU_STALL_FXU);
POWER_EVENT_ATTR(CMPLU_STALL_DIV, CMPLU_STALL_DIV);
POWER_EVENT_ATTR(CMPLU_STALL_SCALAR, CMPLU_STALL_SCALAR);
POWER_EVENT_ATTR(CMPLU_STALL_SCALAR_LONG, CMPLU_STALL_SCALAR_LONG);
POWER_EVENT_ATTR(CMPLU_STALL_VECTOR, CMPLU_STALL_VECTOR);
POWER_EVENT_ATTR(CMPLU_STALL_VECTOR_LONG, CMPLU_STALL_VECTOR_LONG);
POWER_EVENT_ATTR(CMPLU_STALL_LSU, CMPLU_STALL_LSU);
POWER_EVENT_ATTR(CMPLU_STALL_REJECT, CMPLU_STALL_REJECT);
POWER_EVENT_ATTR(CMPLU_STALL_ERAT_MISS, CMPLU_STALL_ERAT_MISS);
POWER_EVENT_ATTR(CMPLU_STALL_DCACHE_MISS, CMPLU_STALL_DCACHE_MISS);
POWER_EVENT_ATTR(CMPLU_STALL_STORE, CMPLU_STALL_STORE);
POWER_EVENT_ATTR(CMPLU_STALL_THRD, CMPLU_STALL_THRD);
POWER_EVENT_ATTR(CMPLU_STALL_IFU, CMPLU_STALL_IFU);
POWER_EVENT_ATTR(CMPLU_STALL_BRU, CMPLU_STALL_BRU);
POWER_EVENT_ATTR(GCT_NOSLOT_IC_MISS, GCT_NOSLOT_IC_MISS);
POWER_EVENT_ATTR(GCT_NOSLOT_BR_MPRED, GCT_NOSLOT_BR_MPRED);
POWER_EVENT_ATTR(GCT_NOSLOT_BR_MPRED_IC_MISS, GCT_NOSLOT_BR_MPRED_IC_MISS);
POWER_EVENT_ATTR(GRP_CMPL, GRP_CMPL);
POWER_EVENT_ATTR(1PLUS_PPC_CMPL, 1PLUS_PPC_CMPL);
POWER_EVENT_ATTR(CMPLU_STALL_DFU, CMPLU_STALL_DFU);
POWER_EVENT_ATTR(RUN_CYC, RUN_CYC);
POWER_EVENT_ATTR(RUN_INST_CMPL, RUN_INST_CMPL);
static struct attribute *power7_events_attr[] = { static struct attribute *power7_events_attr[] = {
GENERIC_EVENT_PTR(CYC), GENERIC_EVENT_PTR(PM_CYC),
GENERIC_EVENT_PTR(GCT_NOSLOT_CYC), GENERIC_EVENT_PTR(PM_GCT_NOSLOT_CYC),
GENERIC_EVENT_PTR(CMPLU_STALL), GENERIC_EVENT_PTR(PM_CMPLU_STALL),
GENERIC_EVENT_PTR(INST_CMPL), GENERIC_EVENT_PTR(PM_INST_CMPL),
GENERIC_EVENT_PTR(LD_REF_L1), GENERIC_EVENT_PTR(PM_LD_REF_L1),
GENERIC_EVENT_PTR(LD_MISS_L1), GENERIC_EVENT_PTR(PM_LD_MISS_L1),
GENERIC_EVENT_PTR(BRU_FIN), GENERIC_EVENT_PTR(PM_BRU_FIN),
GENERIC_EVENT_PTR(BR_MPRED), GENERIC_EVENT_PTR(PM_BR_MPRED),
POWER_EVENT_PTR(CYC), #include "power7-events-list.h"
POWER_EVENT_PTR(GCT_NOSLOT_CYC), #undef EVENT
POWER_EVENT_PTR(CMPLU_STALL),
POWER_EVENT_PTR(INST_CMPL),
POWER_EVENT_PTR(LD_REF_L1),
POWER_EVENT_PTR(LD_MISS_L1),
POWER_EVENT_PTR(BRU_FIN),
POWER_EVENT_PTR(BR_MPRED),
POWER_EVENT_PTR(CMPLU_STALL_FXU),
POWER_EVENT_PTR(CMPLU_STALL_DIV),
POWER_EVENT_PTR(CMPLU_STALL_SCALAR),
POWER_EVENT_PTR(CMPLU_STALL_SCALAR_LONG),
POWER_EVENT_PTR(CMPLU_STALL_VECTOR),
POWER_EVENT_PTR(CMPLU_STALL_VECTOR_LONG),
POWER_EVENT_PTR(CMPLU_STALL_LSU),
POWER_EVENT_PTR(CMPLU_STALL_REJECT),
POWER_EVENT_PTR(CMPLU_STALL_ERAT_MISS),
POWER_EVENT_PTR(CMPLU_STALL_DCACHE_MISS),
POWER_EVENT_PTR(CMPLU_STALL_STORE),
POWER_EVENT_PTR(CMPLU_STALL_THRD),
POWER_EVENT_PTR(CMPLU_STALL_IFU),
POWER_EVENT_PTR(CMPLU_STALL_BRU),
POWER_EVENT_PTR(GCT_NOSLOT_IC_MISS),
POWER_EVENT_PTR(GCT_NOSLOT_BR_MPRED),
POWER_EVENT_PTR(GCT_NOSLOT_BR_MPRED_IC_MISS),
POWER_EVENT_PTR(GRP_CMPL),
POWER_EVENT_PTR(1PLUS_PPC_CMPL),
POWER_EVENT_PTR(CMPLU_STALL_DFU),
POWER_EVENT_PTR(RUN_CYC),
POWER_EVENT_PTR(RUN_INST_CMPL),
NULL NULL
}; };
static struct attribute_group power7_pmu_events_group = { static struct attribute_group power7_pmu_events_group = {
.name = "events", .name = "events",
.attrs = power7_events_attr, .attrs = power7_events_attr,
......
...@@ -39,13 +39,8 @@ bindir_relative = bin ...@@ -39,13 +39,8 @@ bindir_relative = bin
bindir = $(prefix)/$(bindir_relative) bindir = $(prefix)/$(bindir_relative)
man_dir = $(prefix)/share/man man_dir = $(prefix)/share/man
man_dir_SQ = '$(subst ','\'',$(man_dir))' man_dir_SQ = '$(subst ','\'',$(man_dir))'
html_install = $(prefix)/share/kernelshark/html
html_install_SQ = '$(subst ','\'',$(html_install))'
img_install = $(prefix)/share/kernelshark/html/images
img_install_SQ = '$(subst ','\'',$(img_install))'
export man_dir man_dir_SQ html_install html_install_SQ INSTALL export man_dir man_dir_SQ INSTALL
export img_install img_install_SQ
export DESTDIR DESTDIR_SQ export DESTDIR DESTDIR_SQ
# copy a bit from Linux kbuild # copy a bit from Linux kbuild
...@@ -76,10 +71,7 @@ $(if $(BUILD_OUTPUT),, \ ...@@ -76,10 +71,7 @@ $(if $(BUILD_OUTPUT),, \
all: sub-make all: sub-make
gui: force $(MAKECMDGOALS): sub-make
$(call build_output, all_cmd)
$(filter-out gui,$(MAKECMDGOALS)): sub-make
sub-make: force sub-make: force
$(call build_output, $(MAKECMDGOALS)) $(call build_output, $(MAKECMDGOALS))
...@@ -189,6 +181,7 @@ $(obj)/%.o: $(src)/%.c ...@@ -189,6 +181,7 @@ $(obj)/%.o: $(src)/%.c
$(Q)$(call do_compile) $(Q)$(call do_compile)
PEVENT_LIB_OBJS = event-parse.o trace-seq.o parse-filter.o parse-utils.o PEVENT_LIB_OBJS = event-parse.o trace-seq.o parse-filter.o parse-utils.o
PEVENT_LIB_OBJS += kbuffer-parse.o
ALL_OBJS = $(PEVENT_LIB_OBJS) ALL_OBJS = $(PEVENT_LIB_OBJS)
...@@ -258,9 +251,6 @@ define check_deps ...@@ -258,9 +251,6 @@ define check_deps
$(RM) $@.$$$$ $(RM) $@.$$$$
endef endef
$(gui_deps): ks_version.h
$(non_gui_deps): tc_version.h
$(all_deps): .%.d: $(src)/%.c $(all_deps): .%.d: $(src)/%.c
$(Q)$(call check_deps) $(Q)$(call check_deps)
...@@ -300,7 +290,7 @@ define do_install ...@@ -300,7 +290,7 @@ define do_install
$(INSTALL) $1 '$(DESTDIR_SQ)$2' $(INSTALL) $1 '$(DESTDIR_SQ)$2'
endef endef
install_lib: all_cmd install_plugins install_python install_lib: all_cmd
$(Q)$(call do_install,$(LIB_FILE),$(bindir_SQ)) $(Q)$(call do_install,$(LIB_FILE),$(bindir_SQ))
install: install_lib install: install_lib
......
...@@ -5450,10 +5450,9 @@ int pevent_register_print_function(struct pevent *pevent, ...@@ -5450,10 +5450,9 @@ int pevent_register_print_function(struct pevent *pevent,
* If @id is >= 0, then it is used to find the event. * If @id is >= 0, then it is used to find the event.
* else @sys_name and @event_name are used. * else @sys_name and @event_name are used.
*/ */
int pevent_register_event_handler(struct pevent *pevent, int pevent_register_event_handler(struct pevent *pevent, int id,
int id, char *sys_name, char *event_name, const char *sys_name, const char *event_name,
pevent_event_handler_func func, pevent_event_handler_func func, void *context)
void *context)
{ {
struct event_format *event; struct event_format *event;
struct event_handler *handle; struct event_handler *handle;
......
...@@ -69,6 +69,7 @@ struct trace_seq { ...@@ -69,6 +69,7 @@ struct trace_seq {
}; };
void trace_seq_init(struct trace_seq *s); void trace_seq_init(struct trace_seq *s);
void trace_seq_reset(struct trace_seq *s);
void trace_seq_destroy(struct trace_seq *s); void trace_seq_destroy(struct trace_seq *s);
extern int trace_seq_printf(struct trace_seq *s, const char *fmt, ...) extern int trace_seq_printf(struct trace_seq *s, const char *fmt, ...)
...@@ -399,6 +400,7 @@ struct pevent { ...@@ -399,6 +400,7 @@ struct pevent {
int cpus; int cpus;
int long_size; int long_size;
int page_size;
struct cmdline *cmdlines; struct cmdline *cmdlines;
struct cmdline_list *cmdlist; struct cmdline_list *cmdlist;
...@@ -561,7 +563,8 @@ int pevent_print_num_field(struct trace_seq *s, const char *fmt, ...@@ -561,7 +563,8 @@ int pevent_print_num_field(struct trace_seq *s, const char *fmt,
struct event_format *event, const char *name, struct event_format *event, const char *name,
struct pevent_record *record, int err); struct pevent_record *record, int err);
int pevent_register_event_handler(struct pevent *pevent, int id, char *sys_name, char *event_name, int pevent_register_event_handler(struct pevent *pevent, int id,
const char *sys_name, const char *event_name,
pevent_event_handler_func func, void *context); pevent_event_handler_func func, void *context);
int pevent_register_print_function(struct pevent *pevent, int pevent_register_print_function(struct pevent *pevent,
pevent_func_handler func, pevent_func_handler func,
...@@ -619,6 +622,16 @@ static inline void pevent_set_long_size(struct pevent *pevent, int long_size) ...@@ -619,6 +622,16 @@ static inline void pevent_set_long_size(struct pevent *pevent, int long_size)
pevent->long_size = long_size; pevent->long_size = long_size;
} }
static inline int pevent_get_page_size(struct pevent *pevent)
{
return pevent->page_size;
}
static inline void pevent_set_page_size(struct pevent *pevent, int _page_size)
{
pevent->page_size = _page_size;
}
static inline int pevent_is_file_bigendian(struct pevent *pevent) static inline int pevent_is_file_bigendian(struct pevent *pevent)
{ {
return pevent->file_bigendian; return pevent->file_bigendian;
......
This diff is collapsed.
/*
* Copyright (C) 2012 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License (not later!)
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
#ifndef _KBUFFER_H
#define _KBUFFER_H
#ifndef TS_SHIFT
#define TS_SHIFT 27
#endif
enum kbuffer_endian {
KBUFFER_ENDIAN_BIG,
KBUFFER_ENDIAN_LITTLE,
};
enum kbuffer_long_size {
KBUFFER_LSIZE_4,
KBUFFER_LSIZE_8,
};
enum {
KBUFFER_TYPE_PADDING = 29,
KBUFFER_TYPE_TIME_EXTEND = 30,
KBUFFER_TYPE_TIME_STAMP = 31,
};
struct kbuffer;
struct kbuffer *kbuffer_alloc(enum kbuffer_long_size size, enum kbuffer_endian endian);
void kbuffer_free(struct kbuffer *kbuf);
int kbuffer_load_subbuffer(struct kbuffer *kbuf, void *subbuffer);
void *kbuffer_read_event(struct kbuffer *kbuf, unsigned long long *ts);
void *kbuffer_next_event(struct kbuffer *kbuf, unsigned long long *ts);
unsigned long long kbuffer_timestamp(struct kbuffer *kbuf);
void *kbuffer_translate_data(int swap, void *data, unsigned int *size);
void *kbuffer_read_at_offset(struct kbuffer *kbuf, int offset, unsigned long long *ts);
int kbuffer_curr_index(struct kbuffer *kbuf);
int kbuffer_curr_offset(struct kbuffer *kbuf);
int kbuffer_curr_size(struct kbuffer *kbuf);
int kbuffer_event_size(struct kbuffer *kbuf);
int kbuffer_missed_events(struct kbuffer *kbuf);
int kbuffer_subbuffer_size(struct kbuffer *kbuf);
void kbuffer_set_old_format(struct kbuffer *kbuf);
#endif /* _K_BUFFER_H */
...@@ -48,6 +48,19 @@ void trace_seq_init(struct trace_seq *s) ...@@ -48,6 +48,19 @@ void trace_seq_init(struct trace_seq *s)
s->buffer = malloc_or_die(s->buffer_size); s->buffer = malloc_or_die(s->buffer_size);
} }
/**
* trace_seq_reset - re-initialize the trace_seq structure
* @s: a pointer to the trace_seq structure to reset
*/
void trace_seq_reset(struct trace_seq *s)
{
if (!s)
return;
TRACE_SEQ_CHECK(s);
s->len = 0;
s->readpos = 0;
}
/** /**
* trace_seq_destroy - free up memory of a trace_seq * trace_seq_destroy - free up memory of a trace_seq
* @s: a pointer to the trace_seq to free the buffer * @s: a pointer to the trace_seq to free the buffer
......
...@@ -3,17 +3,17 @@ perf-diff(1) ...@@ -3,17 +3,17 @@ perf-diff(1)
NAME NAME
---- ----
perf-diff - Read two perf.data files and display the differential profile perf-diff - Read perf.data files and display the differential profile
SYNOPSIS SYNOPSIS
-------- --------
[verse] [verse]
'perf diff' [oldfile] [newfile] 'perf diff' [baseline file] [data file1] [[data file2] ... ]
DESCRIPTION DESCRIPTION
----------- -----------
This command displays the performance difference amongst two perf.data files This command displays the performance difference amongst two or more perf.data
captured via perf record. files captured via perf record.
If no parameters are passed it will assume perf.data.old and perf.data. If no parameters are passed it will assume perf.data.old and perf.data.
...@@ -75,8 +75,6 @@ OPTIONS ...@@ -75,8 +75,6 @@ OPTIONS
-c:: -c::
--compute:: --compute::
Differential computation selection - delta,ratio,wdiff (default is delta). Differential computation selection - delta,ratio,wdiff (default is delta).
If '+' is specified as a first character, the output is sorted based
on the computation results.
See COMPARISON METHODS section for more info. See COMPARISON METHODS section for more info.
-p:: -p::
...@@ -87,6 +85,63 @@ OPTIONS ...@@ -87,6 +85,63 @@ OPTIONS
--formula:: --formula::
Show formula for given computation. Show formula for given computation.
-o::
--order::
Specify compute sorting column number.
COMPARISON
----------
The comparison is governed by the baseline file. The baseline perf.data
file is iterated for samples. All other perf.data files specified on
the command line are searched for the baseline sample pair. If the pair
is found, specified computation is made and result is displayed.
All samples from non-baseline perf.data files, that do not match any
baseline entry, are displayed with empty space within baseline column
and possible computation results (delta) in their related column.
Example files samples:
- file A with samples f1, f2, f3, f4, f6
- file B with samples f2, f4, f5
- file C with samples f1, f2, f5
Example output:
x - computation takes place for pair
b - baseline sample percentage
- perf diff A B C
baseline/A compute/B compute/C samples
---------------------------------------
b x f1
b x x f2
b f3
b x f4
b f6
x x f5
- perf diff B A C
baseline/B compute/A compute/C samples
---------------------------------------
b x x f2
b x f4
b x f5
x x f1
x f3
x f6
- perf diff C B A
baseline/C compute/B compute/A samples
---------------------------------------
b x f1
b x x f2
b x f5
x f3
x x f4
x f6
COMPARISON METHODS COMPARISON METHODS
------------------ ------------------
delta delta
...@@ -96,7 +151,7 @@ If specified the 'Delta' column is displayed with value 'd' computed as: ...@@ -96,7 +151,7 @@ If specified the 'Delta' column is displayed with value 'd' computed as:
d = A->period_percent - B->period_percent d = A->period_percent - B->period_percent
with: with:
- A/B being matching hist entry from first/second file specified - A/B being matching hist entry from data/baseline file specified
(or perf.data/perf.data.old) respectively. (or perf.data/perf.data.old) respectively.
- period_percent being the % of the hist entry period value within - period_percent being the % of the hist entry period value within
...@@ -109,24 +164,26 @@ If specified the 'Ratio' column is displayed with value 'r' computed as: ...@@ -109,24 +164,26 @@ If specified the 'Ratio' column is displayed with value 'r' computed as:
r = A->period / B->period r = A->period / B->period
with: with:
- A/B being matching hist entry from first/second file specified - A/B being matching hist entry from data/baseline file specified
(or perf.data/perf.data.old) respectively. (or perf.data/perf.data.old) respectively.
- period being the hist entry period value - period being the hist entry period value
wdiff wdiff:WEIGHT-B,WEIGHT-A
~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~
If specified the 'Weighted diff' column is displayed with value 'd' computed as: If specified the 'Weighted diff' column is displayed with value 'd' computed as:
d = B->period * WEIGHT-A - A->period * WEIGHT-B d = B->period * WEIGHT-A - A->period * WEIGHT-B
- A/B being matching hist entry from first/second file specified - A/B being matching hist entry from data/baseline file specified
(or perf.data/perf.data.old) respectively. (or perf.data/perf.data.old) respectively.
- period being the hist entry period value - period being the hist entry period value
- WEIGHT-A/WEIGHT-B being user suplied weights in the the '-c' option - WEIGHT-A/WEIGHT-B being user suplied weights in the the '-c' option
behind ':' separator like '-c wdiff:1,2'. behind ':' separator like '-c wdiff:1,2'.
- WIEGHT-A being the weight of the data file
- WIEGHT-B being the weight of the baseline data file
SEE ALSO SEE ALSO
-------- --------
......
...@@ -8,7 +8,7 @@ perf-list - List all symbolic event types ...@@ -8,7 +8,7 @@ perf-list - List all symbolic event types
SYNOPSIS SYNOPSIS
-------- --------
[verse] [verse]
'perf list' [hw|sw|cache|tracepoint|event_glob] 'perf list' [hw|sw|cache|tracepoint|pmu|event_glob]
DESCRIPTION DESCRIPTION
----------- -----------
...@@ -104,6 +104,8 @@ To limit the list use: ...@@ -104,6 +104,8 @@ To limit the list use:
'subsys_glob:event_glob' to filter by tracepoint subsystems such as sched, 'subsys_glob:event_glob' to filter by tracepoint subsystems such as sched,
block, etc. block, etc.
. 'pmu' to print the kernel supplied PMU events.
. If none of the above is matched, it will apply the supplied glob to all . If none of the above is matched, it will apply the supplied glob to all
events, printing the ones that match. events, printing the ones that match.
......
...@@ -135,6 +135,11 @@ OPTIONS ...@@ -135,6 +135,11 @@ OPTIONS
--inverted:: --inverted::
alias for inverted caller based call graph. alias for inverted caller based call graph.
--ignore-callees=<regex>::
Ignore callees of the function(s) matching the given regex.
This has the effect of collecting the callers of each such
function into one place in the call-graph tree.
--pretty=<key>:: --pretty=<key>::
Pretty printing style. key: normal, raw Pretty printing style. key: normal, raw
......
...@@ -155,6 +155,11 @@ Default is to monitor all CPUS. ...@@ -155,6 +155,11 @@ Default is to monitor all CPUS.
Default: fractal,0.5,callee. Default: fractal,0.5,callee.
--ignore-callees=<regex>::
Ignore callees of the function(s) matching the given regex.
This has the effect of collecting the callers of each such
function into one place in the call-graph tree.
--percent-limit:: --percent-limit::
Do not show entries which have an overhead under that percent. Do not show entries which have an overhead under that percent.
(Default: 0). (Default: 0).
......
...@@ -124,7 +124,7 @@ strip-libs = $(filter-out -l%,$(1)) ...@@ -124,7 +124,7 @@ strip-libs = $(filter-out -l%,$(1))
ifneq ($(OUTPUT),) ifneq ($(OUTPUT),)
TE_PATH=$(OUTPUT) TE_PATH=$(OUTPUT)
ifneq ($(subdir),) ifneq ($(subdir),)
LK_PATH=$(objtree)/lib/lk/ LK_PATH=$(OUTPUT)/../lib/lk/
else else
LK_PATH=$(OUTPUT) LK_PATH=$(OUTPUT)
endif endif
...@@ -281,7 +281,7 @@ LIB_H += util/cpumap.h ...@@ -281,7 +281,7 @@ LIB_H += util/cpumap.h
LIB_H += util/top.h LIB_H += util/top.h
LIB_H += $(ARCH_INCLUDE) LIB_H += $(ARCH_INCLUDE)
LIB_H += util/cgroup.h LIB_H += util/cgroup.h
LIB_H += $(TRACE_EVENT_DIR)event-parse.h LIB_H += $(LIB_INCLUDE)traceevent/event-parse.h
LIB_H += util/target.h LIB_H += util/target.h
LIB_H += util/rblist.h LIB_H += util/rblist.h
LIB_H += util/intlist.h LIB_H += util/intlist.h
......
This diff is collapsed.
...@@ -38,8 +38,7 @@ struct event_entry { ...@@ -38,8 +38,7 @@ struct event_entry {
}; };
static int perf_event__repipe_synth(struct perf_tool *tool, static int perf_event__repipe_synth(struct perf_tool *tool,
union perf_event *event, union perf_event *event)
struct machine *machine __maybe_unused)
{ {
struct perf_inject *inject = container_of(tool, struct perf_inject, tool); struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
uint32_t size; uint32_t size;
...@@ -65,39 +64,28 @@ static int perf_event__repipe_op2_synth(struct perf_tool *tool, ...@@ -65,39 +64,28 @@ static int perf_event__repipe_op2_synth(struct perf_tool *tool,
struct perf_session *session struct perf_session *session
__maybe_unused) __maybe_unused)
{ {
return perf_event__repipe_synth(tool, event, NULL); return perf_event__repipe_synth(tool, event);
} }
static int perf_event__repipe_event_type_synth(struct perf_tool *tool, static int perf_event__repipe_attr(struct perf_tool *tool,
union perf_event *event) union perf_event *event,
{ struct perf_evlist **pevlist)
return perf_event__repipe_synth(tool, event, NULL);
}
static int perf_event__repipe_tracing_data_synth(union perf_event *event,
struct perf_session *session
__maybe_unused)
{
return perf_event__repipe_synth(NULL, event, NULL);
}
static int perf_event__repipe_attr(union perf_event *event,
struct perf_evlist **pevlist __maybe_unused)
{ {
int ret; int ret;
ret = perf_event__process_attr(event, pevlist);
ret = perf_event__process_attr(tool, event, pevlist);
if (ret) if (ret)
return ret; return ret;
return perf_event__repipe_synth(NULL, event, NULL); return perf_event__repipe_synth(tool, event);
} }
static int perf_event__repipe(struct perf_tool *tool, static int perf_event__repipe(struct perf_tool *tool,
union perf_event *event, union perf_event *event,
struct perf_sample *sample __maybe_unused, struct perf_sample *sample __maybe_unused,
struct machine *machine) struct machine *machine __maybe_unused)
{ {
return perf_event__repipe_synth(tool, event, machine); return perf_event__repipe_synth(tool, event);
} }
typedef int (*inject_handler)(struct perf_tool *tool, typedef int (*inject_handler)(struct perf_tool *tool,
...@@ -119,7 +107,7 @@ static int perf_event__repipe_sample(struct perf_tool *tool, ...@@ -119,7 +107,7 @@ static int perf_event__repipe_sample(struct perf_tool *tool,
build_id__mark_dso_hit(tool, event, sample, evsel, machine); build_id__mark_dso_hit(tool, event, sample, evsel, machine);
return perf_event__repipe_synth(tool, event, machine); return perf_event__repipe_synth(tool, event);
} }
static int perf_event__repipe_mmap(struct perf_tool *tool, static int perf_event__repipe_mmap(struct perf_tool *tool,
...@@ -148,13 +136,14 @@ static int perf_event__repipe_fork(struct perf_tool *tool, ...@@ -148,13 +136,14 @@ static int perf_event__repipe_fork(struct perf_tool *tool,
return err; return err;
} }
static int perf_event__repipe_tracing_data(union perf_event *event, static int perf_event__repipe_tracing_data(struct perf_tool *tool,
union perf_event *event,
struct perf_session *session) struct perf_session *session)
{ {
int err; int err;
perf_event__repipe_synth(NULL, event, NULL); perf_event__repipe_synth(tool, event);
err = perf_event__process_tracing_data(event, session); err = perf_event__process_tracing_data(tool, event, session);
return err; return err;
} }
...@@ -407,8 +396,8 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -407,8 +396,8 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
.throttle = perf_event__repipe, .throttle = perf_event__repipe,
.unthrottle = perf_event__repipe, .unthrottle = perf_event__repipe,
.attr = perf_event__repipe_attr, .attr = perf_event__repipe_attr,
.event_type = perf_event__repipe_event_type_synth, .tracing_data = perf_event__repipe_op2_synth,
.tracing_data = perf_event__repipe_tracing_data_synth, .finished_round = perf_event__repipe_op2_synth,
.build_id = perf_event__repipe_op2_synth, .build_id = perf_event__repipe_op2_synth,
}, },
.input_name = "-", .input_name = "-",
......
...@@ -313,7 +313,7 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused, ...@@ -313,7 +313,7 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
return -1; return -1;
} }
dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); dump_printf(" ... thread: %s:%d\n", thread->comm, thread->tid);
if (evsel->handler.func != NULL) { if (evsel->handler.func != NULL) {
tracepoint_handler f = evsel->handler.func; tracepoint_handler f = evsel->handler.func;
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "util/parse-events.h" #include "util/parse-events.h"
#include "util/cache.h" #include "util/cache.h"
#include "util/pmu.h"
int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused) int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused)
{ {
...@@ -37,6 +38,8 @@ int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -37,6 +38,8 @@ int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused)
else if (strcmp(argv[i], "cache") == 0 || else if (strcmp(argv[i], "cache") == 0 ||
strcmp(argv[i], "hwcache") == 0) strcmp(argv[i], "hwcache") == 0)
print_hwcache_events(NULL, false); print_hwcache_events(NULL, false);
else if (strcmp(argv[i], "pmu") == 0)
print_pmu_events(NULL, false);
else if (strcmp(argv[i], "--raw-dump") == 0) else if (strcmp(argv[i], "--raw-dump") == 0)
print_events(NULL, true); print_events(NULL, true);
else { else {
......
...@@ -474,13 +474,6 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv) ...@@ -474,13 +474,6 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
goto out_delete_session; goto out_delete_session;
} }
err = perf_event__synthesize_event_types(tool, process_synthesized_event,
machine);
if (err < 0) {
pr_err("Couldn't synthesize event_types.\n");
goto out_delete_session;
}
if (have_tracepoints(&evsel_list->entries)) { if (have_tracepoints(&evsel_list->entries)) {
/* /*
* FIXME err <= 0 here actually means that * FIXME err <= 0 here actually means that
...@@ -904,7 +897,6 @@ const struct option record_options[] = { ...@@ -904,7 +897,6 @@ const struct option record_options[] = {
int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused) int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
{ {
int err = -ENOMEM; int err = -ENOMEM;
struct perf_evsel *pos;
struct perf_evlist *evsel_list; struct perf_evlist *evsel_list;
struct perf_record *rec = &record; struct perf_record *rec = &record;
char errbuf[BUFSIZ]; char errbuf[BUFSIZ];
...@@ -968,11 +960,6 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -968,11 +960,6 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
if (perf_evlist__create_maps(evsel_list, &rec->opts.target) < 0) if (perf_evlist__create_maps(evsel_list, &rec->opts.target) < 0)
usage_with_options(record_usage, record_options); usage_with_options(record_usage, record_options);
list_for_each_entry(pos, &evsel_list->entries, node) {
if (perf_header__push_event(pos->attr.config, perf_evsel__name(pos)))
goto out_free_fd;
}
if (rec->opts.user_interval != ULLONG_MAX) if (rec->opts.user_interval != ULLONG_MAX)
rec->opts.default_interval = rec->opts.user_interval; rec->opts.default_interval = rec->opts.user_interval;
if (rec->opts.user_freq != UINT_MAX) if (rec->opts.user_freq != UINT_MAX)
......
...@@ -89,7 +89,7 @@ static int perf_report__add_mem_hist_entry(struct perf_tool *tool, ...@@ -89,7 +89,7 @@ static int perf_report__add_mem_hist_entry(struct perf_tool *tool,
if ((sort__has_parent || symbol_conf.use_callchain) && if ((sort__has_parent || symbol_conf.use_callchain) &&
sample->callchain) { sample->callchain) {
err = machine__resolve_callchain(machine, evsel, al->thread, err = machine__resolve_callchain(machine, evsel, al->thread,
sample, &parent); sample, &parent, al);
if (err) if (err)
return err; return err;
} }
...@@ -180,7 +180,7 @@ static int perf_report__add_branch_hist_entry(struct perf_tool *tool, ...@@ -180,7 +180,7 @@ static int perf_report__add_branch_hist_entry(struct perf_tool *tool,
if ((sort__has_parent || symbol_conf.use_callchain) if ((sort__has_parent || symbol_conf.use_callchain)
&& sample->callchain) { && sample->callchain) {
err = machine__resolve_callchain(machine, evsel, al->thread, err = machine__resolve_callchain(machine, evsel, al->thread,
sample, &parent); sample, &parent, al);
if (err) if (err)
return err; return err;
} }
...@@ -254,7 +254,7 @@ static int perf_evsel__add_hist_entry(struct perf_evsel *evsel, ...@@ -254,7 +254,7 @@ static int perf_evsel__add_hist_entry(struct perf_evsel *evsel,
if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) { if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) {
err = machine__resolve_callchain(machine, evsel, al->thread, err = machine__resolve_callchain(machine, evsel, al->thread,
sample, &parent); sample, &parent, al);
if (err) if (err)
return err; return err;
} }
...@@ -497,7 +497,7 @@ static int __cmd_report(struct perf_report *rep) ...@@ -497,7 +497,7 @@ static int __cmd_report(struct perf_report *rep)
ret = perf_session__cpu_bitmap(session, rep->cpu_list, ret = perf_session__cpu_bitmap(session, rep->cpu_list,
rep->cpu_bitmap); rep->cpu_bitmap);
if (ret) if (ret)
goto out_delete; return ret;
} }
if (use_browser <= 0) if (use_browser <= 0)
...@@ -508,11 +508,11 @@ static int __cmd_report(struct perf_report *rep) ...@@ -508,11 +508,11 @@ static int __cmd_report(struct perf_report *rep)
ret = perf_report__setup_sample_type(rep); ret = perf_report__setup_sample_type(rep);
if (ret) if (ret)
goto out_delete; return ret;
ret = perf_session__process_events(session, &rep->tool); ret = perf_session__process_events(session, &rep->tool);
if (ret) if (ret)
goto out_delete; return ret;
kernel_map = session->machines.host.vmlinux_maps[MAP__FUNCTION]; kernel_map = session->machines.host.vmlinux_maps[MAP__FUNCTION];
kernel_kmap = map__kmap(kernel_map); kernel_kmap = map__kmap(kernel_map);
...@@ -547,7 +547,7 @@ static int __cmd_report(struct perf_report *rep) ...@@ -547,7 +547,7 @@ static int __cmd_report(struct perf_report *rep)
if (dump_trace) { if (dump_trace) {
perf_session__fprintf_nr_events(session, stdout); perf_session__fprintf_nr_events(session, stdout);
goto out_delete; return 0;
} }
nr_samples = 0; nr_samples = 0;
...@@ -572,7 +572,7 @@ static int __cmd_report(struct perf_report *rep) ...@@ -572,7 +572,7 @@ static int __cmd_report(struct perf_report *rep)
if (nr_samples == 0) { if (nr_samples == 0) {
ui__error("The %s file has no samples!\n", session->filename); ui__error("The %s file has no samples!\n", session->filename);
goto out_delete; return 0;
} }
list_for_each_entry(pos, &session->evlist->entries, node) list_for_each_entry(pos, &session->evlist->entries, node)
...@@ -598,19 +598,6 @@ static int __cmd_report(struct perf_report *rep) ...@@ -598,19 +598,6 @@ static int __cmd_report(struct perf_report *rep)
} else } else
perf_evlist__tty_browse_hists(session->evlist, rep, help); perf_evlist__tty_browse_hists(session->evlist, rep, help);
out_delete:
/*
* Speed up the exit process, for large files this can
* take quite a while.
*
* XXX Enable this when using valgrind or if we ever
* librarize this command.
*
* Also experiment with obstacks to see how much speed
* up we'll get here.
*
* perf_session__delete(session);
*/
return ret; return ret;
} }
...@@ -694,6 +681,24 @@ parse_callchain_opt(const struct option *opt, const char *arg, int unset) ...@@ -694,6 +681,24 @@ parse_callchain_opt(const struct option *opt, const char *arg, int unset)
return 0; return 0;
} }
int
report_parse_ignore_callees_opt(const struct option *opt __maybe_unused,
const char *arg, int unset __maybe_unused)
{
if (arg) {
int err = regcomp(&ignore_callees_regex, arg, REG_EXTENDED);
if (err) {
char buf[BUFSIZ];
regerror(err, &ignore_callees_regex, buf, sizeof(buf));
pr_err("Invalid --ignore-callees regex: %s\n%s", arg, buf);
return -1;
}
have_ignore_callees = 1;
}
return 0;
}
static int static int
parse_branch_mode(const struct option *opt __maybe_unused, parse_branch_mode(const struct option *opt __maybe_unused,
const char *str __maybe_unused, int unset) const char *str __maybe_unused, int unset)
...@@ -736,7 +741,6 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -736,7 +741,6 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
.lost = perf_event__process_lost, .lost = perf_event__process_lost,
.read = process_read_event, .read = process_read_event,
.attr = perf_event__process_attr, .attr = perf_event__process_attr,
.event_type = perf_event__process_event_type,
.tracing_data = perf_event__process_tracing_data, .tracing_data = perf_event__process_tracing_data,
.build_id = perf_event__process_build_id, .build_id = perf_event__process_build_id,
.ordered_samples = true, .ordered_samples = true,
...@@ -784,6 +788,9 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -784,6 +788,9 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
"Default: fractal,0.5,callee", &parse_callchain_opt, callchain_default_opt), "Default: fractal,0.5,callee", &parse_callchain_opt, callchain_default_opt),
OPT_BOOLEAN('G', "inverted", &report.inverted_callchain, OPT_BOOLEAN('G', "inverted", &report.inverted_callchain,
"alias for inverted call graph"), "alias for inverted call graph"),
OPT_CALLBACK(0, "ignore-callees", NULL, "regex",
"ignore callees of these functions in call graphs",
report_parse_ignore_callees_opt),
OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]", OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
"only consider symbols in these dsos"), "only consider symbols in these dsos"),
OPT_STRING('c', "comms", &symbol_conf.comm_list_str, "comm[,comm...]", OPT_STRING('c', "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
...@@ -853,7 +860,6 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -853,7 +860,6 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
setup_browser(true); setup_browser(true);
else { else {
use_browser = 0; use_browser = 0;
perf_hpp__column_enable(PERF_HPP__OVERHEAD);
perf_hpp__init(); perf_hpp__init();
} }
...@@ -931,14 +937,6 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -931,14 +937,6 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
if (parent_pattern != default_parent_pattern) { if (parent_pattern != default_parent_pattern) {
if (sort_dimension__add("parent") < 0) if (sort_dimension__add("parent") < 0)
goto error; goto error;
/*
* Only show the parent fields if we explicitly
* sort that way. If we only use parent machinery
* for filtering, we don't want it.
*/
if (!strstr(sort_order, "parent"))
sort_parent.elide = 1;
} }
if (argc) { if (argc) {
......
...@@ -1075,7 +1075,7 @@ static int latency_migrate_task_event(struct perf_sched *sched, ...@@ -1075,7 +1075,7 @@ static int latency_migrate_task_event(struct perf_sched *sched,
if (!atoms) { if (!atoms) {
if (thread_atoms_insert(sched, migrant)) if (thread_atoms_insert(sched, migrant))
return -1; return -1;
register_pid(sched, migrant->pid, migrant->comm); register_pid(sched, migrant->tid, migrant->comm);
atoms = thread_atoms_search(&sched->atom_root, migrant, &sched->cmp_pid); atoms = thread_atoms_search(&sched->atom_root, migrant, &sched->cmp_pid);
if (!atoms) { if (!atoms) {
pr_err("migration-event: Internal tree error"); pr_err("migration-event: Internal tree error");
...@@ -1115,7 +1115,7 @@ static void output_lat_thread(struct perf_sched *sched, struct work_atoms *work_ ...@@ -1115,7 +1115,7 @@ static void output_lat_thread(struct perf_sched *sched, struct work_atoms *work_
sched->all_runtime += work_list->total_runtime; sched->all_runtime += work_list->total_runtime;
sched->all_count += work_list->nb_atoms; sched->all_count += work_list->nb_atoms;
ret = printf(" %s:%d ", work_list->thread->comm, work_list->thread->pid); ret = printf(" %s:%d ", work_list->thread->comm, work_list->thread->tid);
for (i = 0; i < 24 - ret; i++) for (i = 0; i < 24 - ret; i++)
printf(" "); printf(" ");
...@@ -1131,9 +1131,9 @@ static void output_lat_thread(struct perf_sched *sched, struct work_atoms *work_ ...@@ -1131,9 +1131,9 @@ static void output_lat_thread(struct perf_sched *sched, struct work_atoms *work_
static int pid_cmp(struct work_atoms *l, struct work_atoms *r) static int pid_cmp(struct work_atoms *l, struct work_atoms *r)
{ {
if (l->thread->pid < r->thread->pid) if (l->thread->tid < r->thread->tid)
return -1; return -1;
if (l->thread->pid > r->thread->pid) if (l->thread->tid > r->thread->tid)
return 1; return 1;
return 0; return 0;
...@@ -1321,7 +1321,7 @@ static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel, ...@@ -1321,7 +1321,7 @@ static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel,
printf("*"); printf("*");
if (sched->curr_thread[cpu]) { if (sched->curr_thread[cpu]) {
if (sched->curr_thread[cpu]->pid) if (sched->curr_thread[cpu]->tid)
printf("%2s ", sched->curr_thread[cpu]->shortname); printf("%2s ", sched->curr_thread[cpu]->shortname);
else else
printf(". "); printf(". ");
...@@ -1332,7 +1332,7 @@ static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel, ...@@ -1332,7 +1332,7 @@ static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel,
printf(" %12.6f secs ", (double)timestamp/1e9); printf(" %12.6f secs ", (double)timestamp/1e9);
if (new_shortname) { if (new_shortname) {
printf("%s => %s:%d\n", printf("%s => %s:%d\n",
sched_in->shortname, sched_in->comm, sched_in->pid); sched_in->shortname, sched_in->comm, sched_in->tid);
} else { } else {
printf("\n"); printf("\n");
} }
...@@ -1662,28 +1662,29 @@ static int __cmd_record(int argc, const char **argv) ...@@ -1662,28 +1662,29 @@ static int __cmd_record(int argc, const char **argv)
return cmd_record(i, rec_argv, NULL); return cmd_record(i, rec_argv, NULL);
} }
static const char default_sort_order[] = "avg, max, switch, runtime";
static struct perf_sched sched = {
.tool = {
.sample = perf_sched__process_tracepoint_sample,
.comm = perf_event__process_comm,
.lost = perf_event__process_lost,
.fork = perf_event__process_fork,
.ordered_samples = true,
},
.cmp_pid = LIST_HEAD_INIT(sched.cmp_pid),
.sort_list = LIST_HEAD_INIT(sched.sort_list),
.start_work_mutex = PTHREAD_MUTEX_INITIALIZER,
.work_done_wait_mutex = PTHREAD_MUTEX_INITIALIZER,
.curr_pid = { [0 ... MAX_CPUS - 1] = -1 },
.sort_order = default_sort_order,
.replay_repeat = 10,
.profile_cpu = -1,
.next_shortname1 = 'A',
.next_shortname2 = '0',
};
int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused) int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)
{ {
const char default_sort_order[] = "avg, max, switch, runtime";
struct perf_sched sched = {
.tool = {
.sample = perf_sched__process_tracepoint_sample,
.comm = perf_event__process_comm,
.lost = perf_event__process_lost,
.fork = perf_event__process_fork,
.ordered_samples = true,
},
.cmp_pid = LIST_HEAD_INIT(sched.cmp_pid),
.sort_list = LIST_HEAD_INIT(sched.sort_list),
.start_work_mutex = PTHREAD_MUTEX_INITIALIZER,
.work_done_wait_mutex = PTHREAD_MUTEX_INITIALIZER,
.curr_pid = { [0 ... MAX_CPUS - 1] = -1 },
.sort_order = default_sort_order,
.replay_repeat = 10,
.profile_cpu = -1,
.next_shortname1 = 'A',
.next_shortname2 = '0',
};
const struct option latency_options[] = { const struct option latency_options[] = {
OPT_STRING('s', "sort", &sched.sort_order, "key[,key2...]", OPT_STRING('s', "sort", &sched.sort_order, "key[,key2...]",
"sort by key(s): runtime, switch, avg, max"), "sort by key(s): runtime, switch, avg, max"),
......
...@@ -24,6 +24,7 @@ static u64 last_timestamp; ...@@ -24,6 +24,7 @@ static u64 last_timestamp;
static u64 nr_unordered; static u64 nr_unordered;
extern const struct option record_options[]; extern const struct option record_options[];
static bool no_callchain; static bool no_callchain;
static bool latency_format;
static bool system_wide; 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);
...@@ -523,7 +524,6 @@ static struct perf_tool perf_script = { ...@@ -523,7 +524,6 @@ static struct perf_tool perf_script = {
.exit = perf_event__process_exit, .exit = perf_event__process_exit,
.fork = perf_event__process_fork, .fork = perf_event__process_fork,
.attr = perf_event__process_attr, .attr = perf_event__process_attr,
.event_type = perf_event__process_event_type,
.tracing_data = perf_event__process_tracing_data, .tracing_data = perf_event__process_tracing_data,
.build_id = perf_event__process_build_id, .build_id = perf_event__process_build_id,
.ordered_samples = true, .ordered_samples = true,
......
...@@ -12,6 +12,8 @@ ...@@ -12,6 +12,8 @@
* of the License. * of the License.
*/ */
#include <traceevent/event-parse.h>
#include "builtin.h" #include "builtin.h"
#include "util/util.h" #include "util/util.h"
...@@ -19,6 +21,7 @@ ...@@ -19,6 +21,7 @@
#include "util/color.h" #include "util/color.h"
#include <linux/list.h> #include <linux/list.h>
#include "util/cache.h" #include "util/cache.h"
#include "util/evlist.h"
#include "util/evsel.h" #include "util/evsel.h"
#include <linux/rbtree.h> #include <linux/rbtree.h>
#include "util/symbol.h" #include "util/symbol.h"
...@@ -328,25 +331,6 @@ struct wakeup_entry { ...@@ -328,25 +331,6 @@ struct wakeup_entry {
int success; int success;
}; };
/*
* trace_flag_type is an enumeration that holds different
* states when a trace occurs. These are:
* IRQS_OFF - interrupts were disabled
* IRQS_NOSUPPORT - arch does not support irqs_disabled_flags
* NEED_RESCED - reschedule is requested
* HARDIRQ - inside an interrupt handler
* SOFTIRQ - inside a softirq handler
*/
enum trace_flag_type {
TRACE_FLAG_IRQS_OFF = 0x01,
TRACE_FLAG_IRQS_NOSUPPORT = 0x02,
TRACE_FLAG_NEED_RESCHED = 0x04,
TRACE_FLAG_HARDIRQ = 0x08,
TRACE_FLAG_SOFTIRQ = 0x10,
};
struct sched_switch { struct sched_switch {
struct trace_entry te; struct trace_entry te;
char prev_comm[TASK_COMM_LEN]; char prev_comm[TASK_COMM_LEN];
...@@ -479,6 +463,8 @@ static void sched_switch(int cpu, u64 timestamp, struct trace_entry *te) ...@@ -479,6 +463,8 @@ static void sched_switch(int cpu, u64 timestamp, struct trace_entry *te)
} }
} }
typedef int (*tracepoint_handler)(struct perf_evsel *evsel,
struct perf_sample *sample);
static int process_sample_event(struct perf_tool *tool __maybe_unused, static int process_sample_event(struct perf_tool *tool __maybe_unused,
union perf_event *event __maybe_unused, union perf_event *event __maybe_unused,
...@@ -486,8 +472,6 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused, ...@@ -486,8 +472,6 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
struct perf_evsel *evsel, struct perf_evsel *evsel,
struct machine *machine __maybe_unused) struct machine *machine __maybe_unused)
{ {
struct trace_entry *te;
if (evsel->attr.sample_type & PERF_SAMPLE_TIME) { if (evsel->attr.sample_type & PERF_SAMPLE_TIME) {
if (!first_time || first_time > sample->time) if (!first_time || first_time > sample->time)
first_time = sample->time; first_time = sample->time;
...@@ -495,69 +479,90 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused, ...@@ -495,69 +479,90 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
last_time = sample->time; last_time = sample->time;
} }
te = (void *)sample->raw_data; if (sample->cpu > numcpus)
if ((evsel->attr.sample_type & PERF_SAMPLE_RAW) && sample->raw_size > 0) { numcpus = sample->cpu;
char *event_str;
#ifdef SUPPORT_OLD_POWER_EVENTS if (evsel->handler.func != NULL) {
struct power_entry_old *peo; tracepoint_handler f = evsel->handler.func;
peo = (void *)te; return f(evsel, sample);
#endif }
/*
* FIXME: use evsel, its already mapped from id to perf_evsel, return 0;
* remove perf_header__find_event infrastructure bits. }
* Mapping all these "power:cpu_idle" strings to the tracepoint
* ID and then just comparing against evsel->attr.config. static int
* process_sample_cpu_idle(struct perf_evsel *evsel __maybe_unused,
* e.g.: struct perf_sample *sample)
* {
* if (evsel->attr.config == power_cpu_idle_id) struct power_processor_entry *ppe = sample->raw_data;
*/
event_str = perf_header__find_event(te->type); if (ppe->state == (u32) PWR_EVENT_EXIT)
c_state_end(ppe->cpu_id, sample->time);
if (!event_str) else
return 0; c_state_start(ppe->cpu_id, sample->time, ppe->state);
return 0;
if (sample->cpu > numcpus) }
numcpus = sample->cpu;
static int
if (strcmp(event_str, "power:cpu_idle") == 0) { process_sample_cpu_frequency(struct perf_evsel *evsel __maybe_unused,
struct power_processor_entry *ppe = (void *)te; struct perf_sample *sample)
if (ppe->state == (u32)PWR_EVENT_EXIT) {
c_state_end(ppe->cpu_id, sample->time); struct power_processor_entry *ppe = sample->raw_data;
else
c_state_start(ppe->cpu_id, sample->time, p_state_change(ppe->cpu_id, sample->time, ppe->state);
ppe->state); return 0;
} }
else if (strcmp(event_str, "power:cpu_frequency") == 0) {
struct power_processor_entry *ppe = (void *)te; static int
p_state_change(ppe->cpu_id, sample->time, ppe->state); process_sample_sched_wakeup(struct perf_evsel *evsel __maybe_unused,
} struct perf_sample *sample)
{
struct trace_entry *te = sample->raw_data;
sched_wakeup(sample->cpu, sample->time, sample->pid, te);
return 0;
}
else if (strcmp(event_str, "sched:sched_wakeup") == 0) static int
sched_wakeup(sample->cpu, sample->time, sample->pid, te); process_sample_sched_switch(struct perf_evsel *evsel __maybe_unused,
struct perf_sample *sample)
{
struct trace_entry *te = sample->raw_data;
else if (strcmp(event_str, "sched:sched_switch") == 0) sched_switch(sample->cpu, sample->time, te);
sched_switch(sample->cpu, sample->time, te); return 0;
}
#ifdef SUPPORT_OLD_POWER_EVENTS #ifdef SUPPORT_OLD_POWER_EVENTS
if (use_old_power_events) { static int
if (strcmp(event_str, "power:power_start") == 0) process_sample_power_start(struct perf_evsel *evsel __maybe_unused,
c_state_start(peo->cpu_id, sample->time, struct perf_sample *sample)
peo->value); {
struct power_entry_old *peo = sample->raw_data;
else if (strcmp(event_str, "power:power_end") == 0)
c_state_end(sample->cpu, sample->time); c_state_start(peo->cpu_id, sample->time, peo->value);
else if (strcmp(event_str,
"power:power_frequency") == 0)
p_state_change(peo->cpu_id, sample->time,
peo->value);
}
#endif
}
return 0; return 0;
} }
static int
process_sample_power_end(struct perf_evsel *evsel __maybe_unused,
struct perf_sample *sample)
{
c_state_end(sample->cpu, sample->time);
return 0;
}
static int
process_sample_power_frequency(struct perf_evsel *evsel __maybe_unused,
struct perf_sample *sample)
{
struct power_entry_old *peo = sample->raw_data;
p_state_change(peo->cpu_id, sample->time, peo->value);
return 0;
}
#endif /* SUPPORT_OLD_POWER_EVENTS */
/* /*
* After the last sample we need to wrap up the current C/P state * After the last sample we need to wrap up the current C/P state
* and close out each CPU for these. * and close out each CPU for these.
...@@ -974,6 +979,17 @@ static int __cmd_timechart(const char *output_name) ...@@ -974,6 +979,17 @@ static int __cmd_timechart(const char *output_name)
.sample = process_sample_event, .sample = process_sample_event,
.ordered_samples = true, .ordered_samples = true,
}; };
const struct perf_evsel_str_handler power_tracepoints[] = {
{ "power:cpu_idle", process_sample_cpu_idle },
{ "power:cpu_frequency", process_sample_cpu_frequency },
{ "sched:sched_wakeup", process_sample_sched_wakeup },
{ "sched:sched_switch", process_sample_sched_switch },
#ifdef SUPPORT_OLD_POWER_EVENTS
{ "power:power_start", process_sample_power_start },
{ "power:power_end", process_sample_power_end },
{ "power:power_frequency", process_sample_power_frequency },
#endif
};
struct perf_session *session = perf_session__new(input_name, O_RDONLY, struct perf_session *session = perf_session__new(input_name, O_RDONLY,
0, false, &perf_timechart); 0, false, &perf_timechart);
int ret = -EINVAL; int ret = -EINVAL;
...@@ -984,6 +1000,12 @@ static int __cmd_timechart(const char *output_name) ...@@ -984,6 +1000,12 @@ static int __cmd_timechart(const char *output_name)
if (!perf_session__has_traces(session, "timechart record")) if (!perf_session__has_traces(session, "timechart record"))
goto out_delete; goto out_delete;
if (perf_session__set_tracepoints_handlers(session,
power_tracepoints)) {
pr_err("Initializing session tracepoint handlers failed\n");
goto out_delete;
}
ret = perf_session__process_events(session, &perf_timechart); ret = perf_session__process_events(session, &perf_timechart);
if (ret) if (ret)
goto out_delete; goto out_delete;
......
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
#include "util/xyarray.h" #include "util/xyarray.h"
#include "util/sort.h" #include "util/sort.h"
#include "util/intlist.h" #include "util/intlist.h"
#include "arch/common.h"
#include "util/debug.h" #include "util/debug.h"
...@@ -772,8 +773,7 @@ static void perf_event__process_sample(struct perf_tool *tool, ...@@ -772,8 +773,7 @@ static void perf_event__process_sample(struct perf_tool *tool,
sample->callchain) { sample->callchain) {
err = machine__resolve_callchain(machine, evsel, err = machine__resolve_callchain(machine, evsel,
al.thread, sample, al.thread, sample,
&parent); &parent, &al);
if (err) if (err)
return; return;
} }
...@@ -939,6 +939,12 @@ static int __cmd_top(struct perf_top *top) ...@@ -939,6 +939,12 @@ static int __cmd_top(struct perf_top *top)
if (top->session == NULL) if (top->session == NULL)
return -ENOMEM; return -ENOMEM;
if (!objdump_path) {
ret = perf_session_env__lookup_objdump(&top->session->header.env);
if (ret)
goto out_delete;
}
ret = perf_top__setup_sample_type(top); ret = perf_top__setup_sample_type(top);
if (ret) if (ret)
goto out_delete; goto out_delete;
...@@ -1102,6 +1108,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -1102,6 +1108,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
OPT_CALLBACK_DEFAULT('G', "call-graph", &top.record_opts, OPT_CALLBACK_DEFAULT('G', "call-graph", &top.record_opts,
"mode[,dump_size]", record_callchain_help, "mode[,dump_size]", record_callchain_help,
&parse_callchain_opt, "fp"), &parse_callchain_opt, "fp"),
OPT_CALLBACK(0, "ignore-callees", NULL, "regex",
"ignore callees of these functions in call graphs",
report_parse_ignore_callees_opt),
OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period, OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period,
"Show a column with the sum of periods"), "Show a column with the sum of periods"),
OPT_STRING(0, "dsos", &symbol_conf.dso_list_str, "dso[,dso...]", OPT_STRING(0, "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
...@@ -1114,6 +1123,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -1114,6 +1123,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
"Interleave source code with assembly code (default)"), "Interleave source code with assembly code (default)"),
OPT_BOOLEAN(0, "asm-raw", &symbol_conf.annotate_asm_raw, OPT_BOOLEAN(0, "asm-raw", &symbol_conf.annotate_asm_raw,
"Display raw encoding of assembly instructions (default)"), "Display raw encoding of assembly instructions (default)"),
OPT_STRING(0, "objdump", &objdump_path, "path",
"objdump binary to use for disassembly and annotations"),
OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
"Specify disassembler style (e.g. -M intel for intel syntax)"), "Specify disassembler style (e.g. -M intel for intel syntax)"),
OPT_STRING('u', "uid", &target->uid_str, "user", "user to profile"), OPT_STRING('u', "uid", &target->uid_str, "user", "user to profile"),
......
#include <traceevent/event-parse.h>
#include "builtin.h" #include "builtin.h"
#include "util/color.h" #include "util/color.h"
#include "util/evlist.h" #include "util/evlist.h"
...@@ -5,7 +6,6 @@ ...@@ -5,7 +6,6 @@
#include "util/thread.h" #include "util/thread.h"
#include "util/parse-options.h" #include "util/parse-options.h"
#include "util/thread_map.h" #include "util/thread_map.h"
#include "event-parse.h"
#include <libaudit.h> #include <libaudit.h>
#include <stdlib.h> #include <stdlib.h>
...@@ -142,7 +142,7 @@ static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thre ...@@ -142,7 +142,7 @@ static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thre
printed += fprintf_duration(duration, fp); printed += fprintf_duration(duration, fp);
if (trace->multiple_threads) if (trace->multiple_threads)
printed += fprintf(fp, "%d ", thread->pid); printed += fprintf(fp, "%d ", thread->tid);
return printed; return printed;
} }
...@@ -593,7 +593,7 @@ static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp) ...@@ -593,7 +593,7 @@ static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
color = PERF_COLOR_YELLOW; color = PERF_COLOR_YELLOW;
printed += color_fprintf(fp, color, "%20s", thread->comm); printed += color_fprintf(fp, color, "%20s", thread->comm);
printed += fprintf(fp, " - %-5d :%11lu [", thread->pid, ttrace->nr_events); printed += fprintf(fp, " - %-5d :%11lu [", thread->tid, ttrace->nr_events);
printed += color_fprintf(fp, color, "%5.1f%%", ratio); printed += color_fprintf(fp, color, "%5.1f%%", ratio);
printed += fprintf(fp, " ] %10.3f ms\n", ttrace->runtime_ms); printed += fprintf(fp, " ] %10.3f ms\n", ttrace->runtime_ms);
} }
......
...@@ -46,6 +46,8 @@ ifneq ($(obj-perf),) ...@@ -46,6 +46,8 @@ ifneq ($(obj-perf),)
obj-perf := $(abspath $(obj-perf))/ obj-perf := $(abspath $(obj-perf))/
endif endif
LIB_INCLUDE := $(srctree)/tools/lib/
# include ARCH specific config # include ARCH specific config
-include $(src-perf)/arch/$(ARCH)/Makefile -include $(src-perf)/arch/$(ARCH)/Makefile
...@@ -121,8 +123,7 @@ endif ...@@ -121,8 +123,7 @@ endif
CFLAGS += -I$(src-perf)/util CFLAGS += -I$(src-perf)/util
CFLAGS += -I$(src-perf) CFLAGS += -I$(src-perf)
CFLAGS += -I$(TRACE_EVENT_DIR) CFLAGS += -I$(LIB_INCLUDE)
CFLAGS += -I$(srctree)/tools/lib/
CFLAGS += -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE CFLAGS += -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
......
...@@ -10,14 +10,6 @@ ...@@ -10,14 +10,6 @@
#include "symbol.h" #include "symbol.h"
#include "tests.h" #include "tests.h"
#define TEST_ASSERT_VAL(text, cond) \
do { \
if (!(cond)) { \
pr_debug("FAILED %s:%d %s\n", __FILE__, __LINE__, text); \
return -1; \
} \
} while (0)
static char *test_file(int size) static char *test_file(int size)
{ {
static char buf_templ[] = "/tmp/test-XXXXXX"; static char buf_templ[] = "/tmp/test-XXXXXX";
......
#include <traceevent/event-parse.h>
#include "evsel.h" #include "evsel.h"
#include "tests.h" #include "tests.h"
#include "event-parse.h"
static int perf_evsel__test_field(struct perf_evsel *evsel, const char *name, static int perf_evsel__test_field(struct perf_evsel *evsel, const char *name,
int size, bool should_be_signed) int size, bool should_be_signed)
...@@ -49,7 +49,7 @@ int test__perf_evsel__tp_sched_test(void) ...@@ -49,7 +49,7 @@ int test__perf_evsel__tp_sched_test(void)
if (perf_evsel__test_field(evsel, "prev_prio", 4, true)) if (perf_evsel__test_field(evsel, "prev_prio", 4, true))
ret = -1; ret = -1;
if (perf_evsel__test_field(evsel, "prev_state", 8, true)) if (perf_evsel__test_field(evsel, "prev_state", sizeof(long), true))
ret = -1; ret = -1;
if (perf_evsel__test_field(evsel, "next_comm", 16, true)) if (perf_evsel__test_field(evsel, "next_comm", 16, true))
......
...@@ -7,14 +7,6 @@ ...@@ -7,14 +7,6 @@
#include "tests.h" #include "tests.h"
#include <linux/hw_breakpoint.h> #include <linux/hw_breakpoint.h>
#define TEST_ASSERT_VAL(text, cond) \
do { \
if (!(cond)) { \
pr_debug("FAILED %s:%d %s\n", __FILE__, __LINE__, text); \
return -1; \
} \
} while (0)
#define PERF_TP_SAMPLE_TYPE (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | \ #define PERF_TP_SAMPLE_TYPE (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | \
PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD) PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD)
...@@ -1254,24 +1246,20 @@ static int test_events(struct evlist_test *events, unsigned cnt) ...@@ -1254,24 +1246,20 @@ static int test_events(struct evlist_test *events, unsigned cnt)
static int test_term(struct terms_test *t) static int test_term(struct terms_test *t)
{ {
struct list_head *terms; struct list_head terms;
int ret; int ret;
terms = malloc(sizeof(*terms)); INIT_LIST_HEAD(&terms);
if (!terms)
return -ENOMEM;
INIT_LIST_HEAD(terms);
ret = parse_events_terms(terms, t->str); ret = parse_events_terms(&terms, t->str);
if (ret) { if (ret) {
pr_debug("failed to parse terms '%s', err %d\n", pr_debug("failed to parse terms '%s', err %d\n",
t->str , ret); t->str , ret);
return ret; return ret;
} }
ret = t->check(terms); ret = t->check(&terms);
parse_events__free_terms(terms); parse_events__free_terms(&terms);
return ret; return ret;
} }
......
#ifndef TESTS_H #ifndef TESTS_H
#define TESTS_H #define TESTS_H
#define TEST_ASSERT_VAL(text, cond) \
do { \
if (!(cond)) { \
pr_debug("FAILED %s:%d %s\n", __FILE__, __LINE__, text); \
return -1; \
} \
} while (0)
enum { enum {
TEST_OK = 0, TEST_OK = 0,
TEST_FAIL = -1, TEST_FAIL = -1,
......
...@@ -139,11 +139,18 @@ int test__vmlinux_matches_kallsyms(void) ...@@ -139,11 +139,18 @@ int test__vmlinux_matches_kallsyms(void)
* _really_ have a problem. * _really_ have a problem.
*/ */
s64 skew = sym->end - pair->end; s64 skew = sym->end - pair->end;
if (llabs(skew) < page_size) if (llabs(skew) >= page_size)
continue; pr_debug("%#" PRIx64 ": diff end addr for %s v: %#" PRIx64 " k: %#" PRIx64 "\n",
sym->start, sym->name, sym->end, pair->end);
/*
* Do not count this as a failure, because we
* could really find a case where it's not
* possible to get proper function end from
* kallsyms.
*/
continue;
pr_debug("%#" PRIx64 ": diff end addr for %s v: %#" PRIx64 " k: %#" PRIx64 "\n",
sym->start, sym->name, sym->end, pair->end);
} else { } else {
struct rb_node *nnd; struct rb_node *nnd;
detour: detour:
......
...@@ -685,8 +685,10 @@ static u64 __hpp_get_##_field(struct hist_entry *he) \ ...@@ -685,8 +685,10 @@ static u64 __hpp_get_##_field(struct hist_entry *he) \
return he->stat._field; \ return he->stat._field; \
} \ } \
\ \
static int hist_browser__hpp_color_##_type(struct perf_hpp *hpp, \ static int \
struct hist_entry *he) \ hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,\
struct perf_hpp *hpp, \
struct hist_entry *he) \
{ \ { \
return __hpp__color_fmt(hpp, he, __hpp_get_##_field, _cb); \ return __hpp__color_fmt(hpp, he, __hpp_get_##_field, _cb); \
} }
...@@ -701,8 +703,6 @@ __HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us, NULL) ...@@ -701,8 +703,6 @@ __HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us, NULL)
void hist_browser__init_hpp(void) void hist_browser__init_hpp(void)
{ {
perf_hpp__column_enable(PERF_HPP__OVERHEAD);
perf_hpp__init(); perf_hpp__init();
perf_hpp__format[PERF_HPP__OVERHEAD].color = perf_hpp__format[PERF_HPP__OVERHEAD].color =
...@@ -762,9 +762,9 @@ static int hist_browser__show_entry(struct hist_browser *browser, ...@@ -762,9 +762,9 @@ static int hist_browser__show_entry(struct hist_browser *browser,
first = false; first = false;
if (fmt->color) { if (fmt->color) {
width -= fmt->color(&hpp, entry); width -= fmt->color(fmt, &hpp, entry);
} else { } else {
width -= fmt->entry(&hpp, entry); width -= fmt->entry(fmt, &hpp, entry);
slsmg_printf("%s", s); slsmg_printf("%s", s);
} }
} }
...@@ -1256,7 +1256,7 @@ static int hists__browser_title(struct hists *hists, char *bf, size_t size, ...@@ -1256,7 +1256,7 @@ static int hists__browser_title(struct hists *hists, char *bf, size_t size,
printed += scnprintf(bf + printed, size - printed, printed += scnprintf(bf + printed, size - printed,
", Thread: %s(%d)", ", Thread: %s(%d)",
(thread->comm_set ? thread->comm : ""), (thread->comm_set ? thread->comm : ""),
thread->pid); thread->tid);
if (dso) if (dso)
printed += scnprintf(bf + printed, size - printed, printed += scnprintf(bf + printed, size - printed,
", DSO: %s", dso->short_name); ", DSO: %s", dso->short_name);
...@@ -1579,7 +1579,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, ...@@ -1579,7 +1579,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
asprintf(&options[nr_options], "Zoom %s %s(%d) thread", asprintf(&options[nr_options], "Zoom %s %s(%d) thread",
(browser->hists->thread_filter ? "out of" : "into"), (browser->hists->thread_filter ? "out of" : "into"),
(thread->comm_set ? thread->comm : ""), (thread->comm_set ? thread->comm : ""),
thread->pid) > 0) thread->tid) > 0)
zoom_thread = nr_options++; zoom_thread = nr_options++;
if (dso != NULL && if (dso != NULL &&
...@@ -1702,7 +1702,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, ...@@ -1702,7 +1702,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
} else { } else {
ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"", ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"",
thread->comm_set ? thread->comm : "", thread->comm_set ? thread->comm : "",
thread->pid); thread->tid);
browser->hists->thread_filter = thread; browser->hists->thread_filter = thread;
sort_thread.elide = true; sort_thread.elide = true;
pstack__push(fstack, &browser->hists->thread_filter); pstack__push(fstack, &browser->hists->thread_filter);
......
...@@ -91,7 +91,8 @@ static u64 he_get_##_field(struct hist_entry *he) \ ...@@ -91,7 +91,8 @@ static u64 he_get_##_field(struct hist_entry *he) \
return he->stat._field; \ return he->stat._field; \
} \ } \
\ \
static int perf_gtk__hpp_color_##_type(struct perf_hpp *hpp, \ static int perf_gtk__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \
struct perf_hpp *hpp, \
struct hist_entry *he) \ struct hist_entry *he) \
{ \ { \
return __hpp__color_fmt(hpp, he, he_get_##_field); \ return __hpp__color_fmt(hpp, he, he_get_##_field); \
...@@ -124,6 +125,81 @@ void perf_gtk__init_hpp(void) ...@@ -124,6 +125,81 @@ void perf_gtk__init_hpp(void)
perf_gtk__hpp_color_overhead_guest_us; perf_gtk__hpp_color_overhead_guest_us;
} }
static void callchain_list__sym_name(struct callchain_list *cl,
char *bf, size_t bfsize)
{
if (cl->ms.sym)
scnprintf(bf, bfsize, "%s", cl->ms.sym->name);
else
scnprintf(bf, bfsize, "%#" PRIx64, cl->ip);
}
static void perf_gtk__add_callchain(struct rb_root *root, GtkTreeStore *store,
GtkTreeIter *parent, int col, u64 total)
{
struct rb_node *nd;
bool has_single_node = (rb_first(root) == rb_last(root));
for (nd = rb_first(root); nd; nd = rb_next(nd)) {
struct callchain_node *node;
struct callchain_list *chain;
GtkTreeIter iter, new_parent;
bool need_new_parent;
double percent;
u64 hits, child_total;
node = rb_entry(nd, struct callchain_node, rb_node);
hits = callchain_cumul_hits(node);
percent = 100.0 * hits / total;
new_parent = *parent;
need_new_parent = !has_single_node && (node->val_nr > 1);
list_for_each_entry(chain, &node->val, list) {
char buf[128];
gtk_tree_store_append(store, &iter, &new_parent);
scnprintf(buf, sizeof(buf), "%5.2f%%", percent);
gtk_tree_store_set(store, &iter, 0, buf, -1);
callchain_list__sym_name(chain, buf, sizeof(buf));
gtk_tree_store_set(store, &iter, col, buf, -1);
if (need_new_parent) {
/*
* Only show the top-most symbol in a callchain
* if it's not the only callchain.
*/
new_parent = iter;
need_new_parent = false;
}
}
if (callchain_param.mode == CHAIN_GRAPH_REL)
child_total = node->children_hit;
else
child_total = total;
/* Now 'iter' contains info of the last callchain_list */
perf_gtk__add_callchain(&node->rb_root, store, &iter, col,
child_total);
}
}
static void on_row_activated(GtkTreeView *view, GtkTreePath *path,
GtkTreeViewColumn *col __maybe_unused,
gpointer user_data __maybe_unused)
{
bool expanded = gtk_tree_view_row_expanded(view, path);
if (expanded)
gtk_tree_view_collapse_row(view, path);
else
gtk_tree_view_expand_row(view, path, FALSE);
}
static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists, static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
float min_pcnt) float min_pcnt)
{ {
...@@ -131,10 +207,11 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists, ...@@ -131,10 +207,11 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
GType col_types[MAX_COLUMNS]; GType col_types[MAX_COLUMNS];
GtkCellRenderer *renderer; GtkCellRenderer *renderer;
struct sort_entry *se; struct sort_entry *se;
GtkListStore *store; GtkTreeStore *store;
struct rb_node *nd; struct rb_node *nd;
GtkWidget *view; GtkWidget *view;
int col_idx; int col_idx;
int sym_col = -1;
int nr_cols; int nr_cols;
char s[512]; char s[512];
...@@ -153,10 +230,13 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists, ...@@ -153,10 +230,13 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
if (se->elide) if (se->elide)
continue; continue;
if (se == &sort_sym)
sym_col = nr_cols;
col_types[nr_cols++] = G_TYPE_STRING; col_types[nr_cols++] = G_TYPE_STRING;
} }
store = gtk_list_store_newv(nr_cols, col_types); store = gtk_tree_store_newv(nr_cols, col_types);
view = gtk_tree_view_new(); view = gtk_tree_view_new();
...@@ -165,7 +245,7 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists, ...@@ -165,7 +245,7 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
col_idx = 0; col_idx = 0;
perf_hpp__for_each_format(fmt) { perf_hpp__for_each_format(fmt) {
fmt->header(&hpp); fmt->header(fmt, &hpp);
gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
-1, ltrim(s), -1, ltrim(s),
...@@ -183,6 +263,18 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists, ...@@ -183,6 +263,18 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
col_idx++, NULL); col_idx++, NULL);
} }
for (col_idx = 0; col_idx < nr_cols; col_idx++) {
GtkTreeViewColumn *column;
column = gtk_tree_view_get_column(GTK_TREE_VIEW(view), col_idx);
gtk_tree_view_column_set_resizable(column, TRUE);
if (col_idx == sym_col) {
gtk_tree_view_set_expander_column(GTK_TREE_VIEW(view),
column);
}
}
gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store)); gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
g_object_unref(GTK_TREE_MODEL(store)); g_object_unref(GTK_TREE_MODEL(store));
...@@ -199,17 +291,17 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists, ...@@ -199,17 +291,17 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
if (percent < min_pcnt) if (percent < min_pcnt)
continue; continue;
gtk_list_store_append(store, &iter); gtk_tree_store_append(store, &iter, NULL);
col_idx = 0; col_idx = 0;
perf_hpp__for_each_format(fmt) { perf_hpp__for_each_format(fmt) {
if (fmt->color) if (fmt->color)
fmt->color(&hpp, h); fmt->color(fmt, &hpp, h);
else else
fmt->entry(&hpp, h); fmt->entry(fmt, &hpp, h);
gtk_list_store_set(store, &iter, col_idx++, s, -1); gtk_tree_store_set(store, &iter, col_idx++, s, -1);
} }
list_for_each_entry(se, &hist_entry__sort_list, list) { list_for_each_entry(se, &hist_entry__sort_list, list) {
...@@ -219,10 +311,26 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists, ...@@ -219,10 +311,26 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
se->se_snprintf(h, s, ARRAY_SIZE(s), se->se_snprintf(h, s, ARRAY_SIZE(s),
hists__col_len(hists, se->se_width_idx)); hists__col_len(hists, se->se_width_idx));
gtk_list_store_set(store, &iter, col_idx++, s, -1); gtk_tree_store_set(store, &iter, col_idx++, s, -1);
}
if (symbol_conf.use_callchain && sort__has_sym) {
u64 total;
if (callchain_param.mode == CHAIN_GRAPH_REL)
total = h->stat.period;
else
total = hists->stats.total_period;
perf_gtk__add_callchain(&h->sorted_chain, store, &iter,
sym_col, total);
} }
} }
gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(view), TRUE);
g_signal_connect(view, "row-activated",
G_CALLBACK(on_row_activated), NULL);
gtk_container_add(GTK_CONTAINER(window), view); gtk_container_add(GTK_CONTAINER(window), view);
} }
......
#include <math.h> #include <math.h>
#include <linux/compiler.h>
#include "../util/hist.h" #include "../util/hist.h"
#include "../util/util.h" #include "../util/util.h"
...@@ -79,7 +80,8 @@ static int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he, ...@@ -79,7 +80,8 @@ static int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
} }
#define __HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \ #define __HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \
static int hpp__header_##_type(struct perf_hpp *hpp) \ static int hpp__header_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \
struct perf_hpp *hpp) \
{ \ { \
int len = _min_width; \ int len = _min_width; \
\ \
...@@ -92,7 +94,8 @@ static int hpp__header_##_type(struct perf_hpp *hpp) \ ...@@ -92,7 +94,8 @@ static int hpp__header_##_type(struct perf_hpp *hpp) \
} }
#define __HPP_WIDTH_FN(_type, _min_width, _unit_width) \ #define __HPP_WIDTH_FN(_type, _min_width, _unit_width) \
static int hpp__width_##_type(struct perf_hpp *hpp __maybe_unused) \ static int hpp__width_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \
struct perf_hpp *hpp __maybe_unused) \
{ \ { \
int len = _min_width; \ int len = _min_width; \
\ \
...@@ -110,14 +113,16 @@ static u64 he_get_##_field(struct hist_entry *he) \ ...@@ -110,14 +113,16 @@ static u64 he_get_##_field(struct hist_entry *he) \
return he->stat._field; \ return he->stat._field; \
} \ } \
\ \
static int hpp__color_##_type(struct perf_hpp *hpp, struct hist_entry *he) \ static int hpp__color_##_type(struct perf_hpp_fmt *fmt __maybe_unused, \
struct perf_hpp *hpp, struct hist_entry *he) \
{ \ { \
return __hpp__fmt(hpp, he, he_get_##_field, " %6.2f%%", \ return __hpp__fmt(hpp, he, he_get_##_field, " %6.2f%%", \
(hpp_snprint_fn)percent_color_snprintf, true); \ (hpp_snprint_fn)percent_color_snprintf, true); \
} }
#define __HPP_ENTRY_PERCENT_FN(_type, _field) \ #define __HPP_ENTRY_PERCENT_FN(_type, _field) \
static int hpp__entry_##_type(struct perf_hpp *hpp, struct hist_entry *he) \ static int hpp__entry_##_type(struct perf_hpp_fmt *_fmt __maybe_unused, \
struct perf_hpp *hpp, struct hist_entry *he) \
{ \ { \
const char *fmt = symbol_conf.field_sep ? " %.2f" : " %6.2f%%"; \ const char *fmt = symbol_conf.field_sep ? " %.2f" : " %6.2f%%"; \
return __hpp__fmt(hpp, he, he_get_##_field, fmt, \ return __hpp__fmt(hpp, he, he_get_##_field, fmt, \
...@@ -130,7 +135,8 @@ static u64 he_get_raw_##_field(struct hist_entry *he) \ ...@@ -130,7 +135,8 @@ static u64 he_get_raw_##_field(struct hist_entry *he) \
return he->stat._field; \ return he->stat._field; \
} \ } \
\ \
static int hpp__entry_##_type(struct perf_hpp *hpp, struct hist_entry *he) \ static int hpp__entry_##_type(struct perf_hpp_fmt *_fmt __maybe_unused, \
struct perf_hpp *hpp, struct hist_entry *he) \
{ \ { \
const char *fmt = symbol_conf.field_sep ? " %"PRIu64 : " %11"PRIu64; \ const char *fmt = symbol_conf.field_sep ? " %"PRIu64 : " %11"PRIu64; \
return __hpp__fmt(hpp, he, he_get_raw_##_field, fmt, scnprintf, false); \ return __hpp__fmt(hpp, he, he_get_raw_##_field, fmt, scnprintf, false); \
...@@ -157,196 +163,6 @@ HPP_PERCENT_FNS(overhead_guest_us, "guest usr", period_guest_us, 9, 8) ...@@ -157,196 +163,6 @@ HPP_PERCENT_FNS(overhead_guest_us, "guest usr", period_guest_us, 9, 8)
HPP_RAW_FNS(samples, "Samples", nr_events, 12, 12) HPP_RAW_FNS(samples, "Samples", nr_events, 12, 12)
HPP_RAW_FNS(period, "Period", period, 12, 12) HPP_RAW_FNS(period, "Period", period, 12, 12)
static int hpp__header_baseline(struct perf_hpp *hpp)
{
return scnprintf(hpp->buf, hpp->size, "Baseline");
}
static int hpp__width_baseline(struct perf_hpp *hpp __maybe_unused)
{
return 8;
}
static double baseline_percent(struct hist_entry *he)
{
struct hist_entry *pair = hist_entry__next_pair(he);
struct hists *pair_hists = pair ? pair->hists : NULL;
double percent = 0.0;
if (pair) {
u64 total_period = pair_hists->stats.total_period;
u64 base_period = pair->stat.period;
percent = 100.0 * base_period / total_period;
}
return percent;
}
static int hpp__color_baseline(struct perf_hpp *hpp, struct hist_entry *he)
{
double percent = baseline_percent(he);
if (hist_entry__has_pairs(he) || symbol_conf.field_sep)
return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", percent);
else
return scnprintf(hpp->buf, hpp->size, " ");
}
static int hpp__entry_baseline(struct perf_hpp *hpp, struct hist_entry *he)
{
double percent = baseline_percent(he);
const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%%";
if (hist_entry__has_pairs(he) || symbol_conf.field_sep)
return scnprintf(hpp->buf, hpp->size, fmt, percent);
else
return scnprintf(hpp->buf, hpp->size, " ");
}
static int hpp__header_period_baseline(struct perf_hpp *hpp)
{
const char *fmt = symbol_conf.field_sep ? "%s" : "%12s";
return scnprintf(hpp->buf, hpp->size, fmt, "Period Base");
}
static int hpp__width_period_baseline(struct perf_hpp *hpp __maybe_unused)
{
return 12;
}
static int hpp__entry_period_baseline(struct perf_hpp *hpp, struct hist_entry *he)
{
struct hist_entry *pair = hist_entry__next_pair(he);
u64 period = pair ? pair->stat.period : 0;
const char *fmt = symbol_conf.field_sep ? "%" PRIu64 : "%12" PRIu64;
return scnprintf(hpp->buf, hpp->size, fmt, period);
}
static int hpp__header_delta(struct perf_hpp *hpp)
{
const char *fmt = symbol_conf.field_sep ? "%s" : "%7s";
return scnprintf(hpp->buf, hpp->size, fmt, "Delta");
}
static int hpp__width_delta(struct perf_hpp *hpp __maybe_unused)
{
return 7;
}
static int hpp__entry_delta(struct perf_hpp *hpp, struct hist_entry *he)
{
struct hist_entry *pair = hist_entry__next_pair(he);
const char *fmt = symbol_conf.field_sep ? "%s" : "%7.7s";
char buf[32] = " ";
double diff = 0.0;
if (pair) {
if (he->diff.computed)
diff = he->diff.period_ratio_delta;
else
diff = perf_diff__compute_delta(he, pair);
} else
diff = perf_diff__period_percent(he, he->stat.period);
if (fabs(diff) >= 0.01)
scnprintf(buf, sizeof(buf), "%+4.2F%%", diff);
return scnprintf(hpp->buf, hpp->size, fmt, buf);
}
static int hpp__header_ratio(struct perf_hpp *hpp)
{
const char *fmt = symbol_conf.field_sep ? "%s" : "%14s";
return scnprintf(hpp->buf, hpp->size, fmt, "Ratio");
}
static int hpp__width_ratio(struct perf_hpp *hpp __maybe_unused)
{
return 14;
}
static int hpp__entry_ratio(struct perf_hpp *hpp, struct hist_entry *he)
{
struct hist_entry *pair = hist_entry__next_pair(he);
const char *fmt = symbol_conf.field_sep ? "%s" : "%14s";
char buf[32] = " ";
double ratio = 0.0;
if (pair) {
if (he->diff.computed)
ratio = he->diff.period_ratio;
else
ratio = perf_diff__compute_ratio(he, pair);
}
if (ratio > 0.0)
scnprintf(buf, sizeof(buf), "%+14.6F", ratio);
return scnprintf(hpp->buf, hpp->size, fmt, buf);
}
static int hpp__header_wdiff(struct perf_hpp *hpp)
{
const char *fmt = symbol_conf.field_sep ? "%s" : "%14s";
return scnprintf(hpp->buf, hpp->size, fmt, "Weighted diff");
}
static int hpp__width_wdiff(struct perf_hpp *hpp __maybe_unused)
{
return 14;
}
static int hpp__entry_wdiff(struct perf_hpp *hpp, struct hist_entry *he)
{
struct hist_entry *pair = hist_entry__next_pair(he);
const char *fmt = symbol_conf.field_sep ? "%s" : "%14s";
char buf[32] = " ";
s64 wdiff = 0;
if (pair) {
if (he->diff.computed)
wdiff = he->diff.wdiff;
else
wdiff = perf_diff__compute_wdiff(he, pair);
}
if (wdiff != 0)
scnprintf(buf, sizeof(buf), "%14ld", wdiff);
return scnprintf(hpp->buf, hpp->size, fmt, buf);
}
static int hpp__header_formula(struct perf_hpp *hpp)
{
const char *fmt = symbol_conf.field_sep ? "%s" : "%70s";
return scnprintf(hpp->buf, hpp->size, fmt, "Formula");
}
static int hpp__width_formula(struct perf_hpp *hpp __maybe_unused)
{
return 70;
}
static int hpp__entry_formula(struct perf_hpp *hpp, struct hist_entry *he)
{
struct hist_entry *pair = hist_entry__next_pair(he);
const char *fmt = symbol_conf.field_sep ? "%s" : "%-70s";
char buf[96] = " ";
if (pair)
perf_diff__formula(he, pair, buf, sizeof(buf));
return scnprintf(hpp->buf, hpp->size, fmt, buf);
}
#define HPP__COLOR_PRINT_FNS(_name) \ #define HPP__COLOR_PRINT_FNS(_name) \
{ \ { \
.header = hpp__header_ ## _name, \ .header = hpp__header_ ## _name, \
...@@ -363,19 +179,13 @@ static int hpp__entry_formula(struct perf_hpp *hpp, struct hist_entry *he) ...@@ -363,19 +179,13 @@ static int hpp__entry_formula(struct perf_hpp *hpp, struct hist_entry *he)
} }
struct perf_hpp_fmt perf_hpp__format[] = { struct perf_hpp_fmt perf_hpp__format[] = {
HPP__COLOR_PRINT_FNS(baseline),
HPP__COLOR_PRINT_FNS(overhead), HPP__COLOR_PRINT_FNS(overhead),
HPP__COLOR_PRINT_FNS(overhead_sys), HPP__COLOR_PRINT_FNS(overhead_sys),
HPP__COLOR_PRINT_FNS(overhead_us), HPP__COLOR_PRINT_FNS(overhead_us),
HPP__COLOR_PRINT_FNS(overhead_guest_sys), HPP__COLOR_PRINT_FNS(overhead_guest_sys),
HPP__COLOR_PRINT_FNS(overhead_guest_us), HPP__COLOR_PRINT_FNS(overhead_guest_us),
HPP__PRINT_FNS(samples), HPP__PRINT_FNS(samples),
HPP__PRINT_FNS(period), HPP__PRINT_FNS(period)
HPP__PRINT_FNS(period_baseline),
HPP__PRINT_FNS(delta),
HPP__PRINT_FNS(ratio),
HPP__PRINT_FNS(wdiff),
HPP__PRINT_FNS(formula)
}; };
LIST_HEAD(perf_hpp__list); LIST_HEAD(perf_hpp__list);
...@@ -396,6 +206,8 @@ LIST_HEAD(perf_hpp__list); ...@@ -396,6 +206,8 @@ LIST_HEAD(perf_hpp__list);
void perf_hpp__init(void) void perf_hpp__init(void)
{ {
perf_hpp__column_enable(PERF_HPP__OVERHEAD);
if (symbol_conf.show_cpu_utilization) { if (symbol_conf.show_cpu_utilization) {
perf_hpp__column_enable(PERF_HPP__OVERHEAD_SYS); perf_hpp__column_enable(PERF_HPP__OVERHEAD_SYS);
perf_hpp__column_enable(PERF_HPP__OVERHEAD_US); perf_hpp__column_enable(PERF_HPP__OVERHEAD_US);
...@@ -424,46 +236,6 @@ void perf_hpp__column_enable(unsigned col) ...@@ -424,46 +236,6 @@ void perf_hpp__column_enable(unsigned col)
perf_hpp__column_register(&perf_hpp__format[col]); perf_hpp__column_register(&perf_hpp__format[col]);
} }
static inline void advance_hpp(struct perf_hpp *hpp, int inc)
{
hpp->buf += inc;
hpp->size -= inc;
}
int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he,
bool color)
{
const char *sep = symbol_conf.field_sep;
struct perf_hpp_fmt *fmt;
char *start = hpp->buf;
int ret;
bool first = true;
if (symbol_conf.exclude_other && !he->parent)
return 0;
perf_hpp__for_each_format(fmt) {
/*
* If there's no field_sep, we still need
* to display initial ' '.
*/
if (!sep || !first) {
ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: " ");
advance_hpp(hpp, ret);
} else
first = false;
if (color && fmt->color)
ret = fmt->color(hpp, he);
else
ret = fmt->entry(hpp, he);
advance_hpp(hpp, ret);
}
return hpp->buf - start;
}
int hist_entry__sort_snprintf(struct hist_entry *he, char *s, size_t size, int hist_entry__sort_snprintf(struct hist_entry *he, char *s, size_t size,
struct hists *hists) struct hists *hists)
{ {
...@@ -499,7 +271,7 @@ unsigned int hists__sort_list_width(struct hists *hists) ...@@ -499,7 +271,7 @@ unsigned int hists__sort_list_width(struct hists *hists)
if (i) if (i)
ret += 2; ret += 2;
ret += fmt->width(&dummy_hpp); ret += fmt->width(fmt, &dummy_hpp);
} }
list_for_each_entry(se, &hist_entry__sort_list, list) list_for_each_entry(se, &hist_entry__sort_list, list)
......
...@@ -30,7 +30,6 @@ void setup_browser(bool fallback_to_pager) ...@@ -30,7 +30,6 @@ void setup_browser(bool fallback_to_pager)
if (fallback_to_pager) if (fallback_to_pager)
setup_pager(); setup_pager();
perf_hpp__column_enable(PERF_HPP__OVERHEAD);
perf_hpp__init(); perf_hpp__init();
break; break;
} }
......
...@@ -308,6 +308,47 @@ static size_t hist_entry__callchain_fprintf(struct hist_entry *he, ...@@ -308,6 +308,47 @@ static size_t hist_entry__callchain_fprintf(struct hist_entry *he,
return hist_entry_callchain__fprintf(he, total_period, left_margin, fp); return hist_entry_callchain__fprintf(he, total_period, left_margin, fp);
} }
static inline void advance_hpp(struct perf_hpp *hpp, int inc)
{
hpp->buf += inc;
hpp->size -= inc;
}
static int hist_entry__period_snprintf(struct perf_hpp *hpp,
struct hist_entry *he,
bool color)
{
const char *sep = symbol_conf.field_sep;
struct perf_hpp_fmt *fmt;
char *start = hpp->buf;
int ret;
bool first = true;
if (symbol_conf.exclude_other && !he->parent)
return 0;
perf_hpp__for_each_format(fmt) {
/*
* If there's no field_sep, we still need
* to display initial ' '.
*/
if (!sep || !first) {
ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: " ");
advance_hpp(hpp, ret);
} else
first = false;
if (color && fmt->color)
ret = fmt->color(fmt, hpp, he);
else
ret = fmt->entry(fmt, hpp, he);
advance_hpp(hpp, ret);
}
return hpp->buf - start;
}
static int hist_entry__fprintf(struct hist_entry *he, size_t size, static int hist_entry__fprintf(struct hist_entry *he, size_t size,
struct hists *hists, FILE *fp) struct hists *hists, FILE *fp)
{ {
...@@ -365,7 +406,7 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, ...@@ -365,7 +406,7 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
else else
first = false; first = false;
fmt->header(&dummy_hpp); fmt->header(fmt, &dummy_hpp);
fprintf(fp, "%s", bf); fprintf(fp, "%s", bf);
} }
...@@ -410,7 +451,7 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, ...@@ -410,7 +451,7 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
else else
first = false; first = false;
width = fmt->width(&dummy_hpp); width = fmt->width(fmt, &dummy_hpp);
for (i = 0; i < width; i++) for (i = 0; i < width; i++)
fprintf(fp, "."); fprintf(fp, ".");
} }
......
...@@ -41,7 +41,7 @@ static inline int cpu_map__nr(const struct cpu_map *map) ...@@ -41,7 +41,7 @@ static inline int cpu_map__nr(const struct cpu_map *map)
return map ? map->nr : 1; return map ? map->nr : 1;
} }
static inline bool cpu_map__all(const struct cpu_map *map) static inline bool cpu_map__empty(const struct cpu_map *map)
{ {
return map ? map->map[0] == -1 : true; return map ? map->map[0] == -1 : true;
} }
......
...@@ -686,7 +686,7 @@ int perf_event__preprocess_sample(const union perf_event *event, ...@@ -686,7 +686,7 @@ int perf_event__preprocess_sample(const union perf_event *event,
!strlist__has_entry(symbol_conf.comm_list, thread->comm)) !strlist__has_entry(symbol_conf.comm_list, thread->comm))
goto out_filtered; goto out_filtered;
dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); dump_printf(" ... thread: %s:%d\n", thread->comm, thread->tid);
/* /*
* Have we already created the kernel maps for this machine? * Have we already created the kernel maps for this machine?
* *
......
...@@ -116,7 +116,7 @@ struct build_id_event { ...@@ -116,7 +116,7 @@ struct build_id_event {
enum perf_user_event_type { /* above any possible kernel type */ enum perf_user_event_type { /* above any possible kernel type */
PERF_RECORD_USER_TYPE_START = 64, PERF_RECORD_USER_TYPE_START = 64,
PERF_RECORD_HEADER_ATTR = 64, PERF_RECORD_HEADER_ATTR = 64,
PERF_RECORD_HEADER_EVENT_TYPE = 65, PERF_RECORD_HEADER_EVENT_TYPE = 65, /* depreceated */
PERF_RECORD_HEADER_TRACING_DATA = 66, PERF_RECORD_HEADER_TRACING_DATA = 66,
PERF_RECORD_HEADER_BUILD_ID = 67, PERF_RECORD_HEADER_BUILD_ID = 67,
PERF_RECORD_FINISHED_ROUND = 68, PERF_RECORD_FINISHED_ROUND = 68,
......
...@@ -403,16 +403,20 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx) ...@@ -403,16 +403,20 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx)
return event; return event;
} }
static void __perf_evlist__munmap(struct perf_evlist *evlist, int idx)
{
if (evlist->mmap[idx].base != NULL) {
munmap(evlist->mmap[idx].base, evlist->mmap_len);
evlist->mmap[idx].base = NULL;
}
}
void perf_evlist__munmap(struct perf_evlist *evlist) void perf_evlist__munmap(struct perf_evlist *evlist)
{ {
int i; int i;
for (i = 0; i < evlist->nr_mmaps; i++) { for (i = 0; i < evlist->nr_mmaps; i++)
if (evlist->mmap[i].base != NULL) { __perf_evlist__munmap(evlist, i);
munmap(evlist->mmap[i].base, evlist->mmap_len);
evlist->mmap[i].base = NULL;
}
}
free(evlist->mmap); free(evlist->mmap);
evlist->mmap = NULL; evlist->mmap = NULL;
...@@ -421,7 +425,7 @@ void perf_evlist__munmap(struct perf_evlist *evlist) ...@@ -421,7 +425,7 @@ void perf_evlist__munmap(struct perf_evlist *evlist)
static int perf_evlist__alloc_mmap(struct perf_evlist *evlist) static int perf_evlist__alloc_mmap(struct perf_evlist *evlist)
{ {
evlist->nr_mmaps = cpu_map__nr(evlist->cpus); evlist->nr_mmaps = cpu_map__nr(evlist->cpus);
if (cpu_map__all(evlist->cpus)) if (cpu_map__empty(evlist->cpus))
evlist->nr_mmaps = thread_map__nr(evlist->threads); evlist->nr_mmaps = thread_map__nr(evlist->threads);
evlist->mmap = zalloc(evlist->nr_mmaps * sizeof(struct perf_mmap)); evlist->mmap = zalloc(evlist->nr_mmaps * sizeof(struct perf_mmap));
return evlist->mmap != NULL ? 0 : -ENOMEM; return evlist->mmap != NULL ? 0 : -ENOMEM;
...@@ -477,12 +481,8 @@ static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot, int m ...@@ -477,12 +481,8 @@ static int perf_evlist__mmap_per_cpu(struct perf_evlist *evlist, int prot, int m
return 0; return 0;
out_unmap: out_unmap:
for (cpu = 0; cpu < nr_cpus; cpu++) { for (cpu = 0; cpu < nr_cpus; cpu++)
if (evlist->mmap[cpu].base != NULL) { __perf_evlist__munmap(evlist, cpu);
munmap(evlist->mmap[cpu].base, evlist->mmap_len);
evlist->mmap[cpu].base = NULL;
}
}
return -1; return -1;
} }
...@@ -517,12 +517,8 @@ static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot, in ...@@ -517,12 +517,8 @@ static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot, in
return 0; return 0;
out_unmap: out_unmap:
for (thread = 0; thread < nr_threads; thread++) { for (thread = 0; thread < nr_threads; thread++)
if (evlist->mmap[thread].base != NULL) { __perf_evlist__munmap(evlist, thread);
munmap(evlist->mmap[thread].base, evlist->mmap_len);
evlist->mmap[thread].base = NULL;
}
}
return -1; return -1;
} }
...@@ -573,7 +569,7 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages, ...@@ -573,7 +569,7 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
return -ENOMEM; return -ENOMEM;
} }
if (cpu_map__all(cpus)) if (cpu_map__empty(cpus))
return perf_evlist__mmap_per_thread(evlist, prot, mask); return perf_evlist__mmap_per_thread(evlist, prot, mask);
return perf_evlist__mmap_per_cpu(evlist, prot, mask); return perf_evlist__mmap_per_cpu(evlist, prot, mask);
...@@ -838,7 +834,7 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist, ...@@ -838,7 +834,7 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist,
int perf_evlist__start_workload(struct perf_evlist *evlist) int perf_evlist__start_workload(struct perf_evlist *evlist)
{ {
if (evlist->workload.cork_fd > 0) { if (evlist->workload.cork_fd > 0) {
char bf; char bf = 0;
int ret; int ret;
/* /*
* Remove the cork, let it rip! * Remove the cork, let it rip!
......
...@@ -9,17 +9,17 @@ ...@@ -9,17 +9,17 @@
#include <byteswap.h> #include <byteswap.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include "asm/bug.h"
#include <lk/debugfs.h> #include <lk/debugfs.h>
#include "event-parse.h" #include <traceevent/event-parse.h>
#include <linux/hw_breakpoint.h>
#include <linux/perf_event.h>
#include "asm/bug.h"
#include "evsel.h" #include "evsel.h"
#include "evlist.h" #include "evlist.h"
#include "util.h" #include "util.h"
#include "cpumap.h" #include "cpumap.h"
#include "thread_map.h" #include "thread_map.h"
#include "target.h" #include "target.h"
#include <linux/hw_breakpoint.h>
#include <linux/perf_event.h>
#include "perf_regs.h" #include "perf_regs.h"
static struct { static struct {
......
...@@ -25,41 +25,9 @@ ...@@ -25,41 +25,9 @@
static bool no_buildid_cache = false; static bool no_buildid_cache = false;
static int trace_event_count;
static struct perf_trace_event_type *trace_events;
static u32 header_argc; static u32 header_argc;
static const char **header_argv; static const char **header_argv;
int perf_header__push_event(u64 id, const char *name)
{
struct perf_trace_event_type *nevents;
if (strlen(name) > MAX_EVENT_NAME)
pr_warning("Event %s will be truncated\n", name);
nevents = realloc(trace_events, (trace_event_count + 1) * sizeof(*trace_events));
if (nevents == NULL)
return -ENOMEM;
trace_events = nevents;
memset(&trace_events[trace_event_count], 0, sizeof(struct perf_trace_event_type));
trace_events[trace_event_count].event_id = id;
strncpy(trace_events[trace_event_count].name, name, MAX_EVENT_NAME - 1);
trace_event_count++;
return 0;
}
char *perf_header__find_event(u64 id)
{
int i;
for (i = 0 ; i < trace_event_count; i++) {
if (trace_events[i].event_id == id)
return trace_events[i].name;
}
return NULL;
}
/* /*
* magic2 = "PERFILE2" * magic2 = "PERFILE2"
* must be a numerical value to let the endianness * must be a numerical value to let the endianness
...@@ -2257,7 +2225,7 @@ static int perf_header__adds_write(struct perf_header *header, ...@@ -2257,7 +2225,7 @@ static int perf_header__adds_write(struct perf_header *header,
sec_size = sizeof(*feat_sec) * nr_sections; sec_size = sizeof(*feat_sec) * nr_sections;
sec_start = header->data_offset + header->data_size; sec_start = header->feat_offset;
lseek(fd, sec_start + sec_size, SEEK_SET); lseek(fd, sec_start + sec_size, SEEK_SET);
for_each_set_bit(feat, header->adds_features, HEADER_FEAT_BITS) { for_each_set_bit(feat, header->adds_features, HEADER_FEAT_BITS) {
...@@ -2304,6 +2272,7 @@ int perf_session__write_header(struct perf_session *session, ...@@ -2304,6 +2272,7 @@ int perf_session__write_header(struct perf_session *session,
struct perf_file_attr f_attr; struct perf_file_attr f_attr;
struct perf_header *header = &session->header; struct perf_header *header = &session->header;
struct perf_evsel *evsel; struct perf_evsel *evsel;
u64 attr_offset;
int err; int err;
lseek(fd, sizeof(f_header), SEEK_SET); lseek(fd, sizeof(f_header), SEEK_SET);
...@@ -2317,7 +2286,7 @@ int perf_session__write_header(struct perf_session *session, ...@@ -2317,7 +2286,7 @@ int perf_session__write_header(struct perf_session *session,
} }
} }
header->attr_offset = lseek(fd, 0, SEEK_CUR); attr_offset = lseek(fd, 0, SEEK_CUR);
list_for_each_entry(evsel, &evlist->entries, node) { list_for_each_entry(evsel, &evlist->entries, node) {
f_attr = (struct perf_file_attr){ f_attr = (struct perf_file_attr){
...@@ -2334,17 +2303,8 @@ int perf_session__write_header(struct perf_session *session, ...@@ -2334,17 +2303,8 @@ int perf_session__write_header(struct perf_session *session,
} }
} }
header->event_offset = lseek(fd, 0, SEEK_CUR);
header->event_size = trace_event_count * sizeof(struct perf_trace_event_type);
if (trace_events) {
err = do_write(fd, trace_events, header->event_size);
if (err < 0) {
pr_debug("failed to write perf header events\n");
return err;
}
}
header->data_offset = lseek(fd, 0, SEEK_CUR); header->data_offset = lseek(fd, 0, SEEK_CUR);
header->feat_offset = header->data_offset + header->data_size;
if (at_exit) { if (at_exit) {
err = perf_header__adds_write(header, evlist, fd); err = perf_header__adds_write(header, evlist, fd);
...@@ -2357,17 +2317,14 @@ int perf_session__write_header(struct perf_session *session, ...@@ -2357,17 +2317,14 @@ int perf_session__write_header(struct perf_session *session,
.size = sizeof(f_header), .size = sizeof(f_header),
.attr_size = sizeof(f_attr), .attr_size = sizeof(f_attr),
.attrs = { .attrs = {
.offset = header->attr_offset, .offset = attr_offset,
.size = evlist->nr_entries * sizeof(f_attr), .size = evlist->nr_entries * sizeof(f_attr),
}, },
.data = { .data = {
.offset = header->data_offset, .offset = header->data_offset,
.size = header->data_size, .size = header->data_size,
}, },
.event_types = { /* event_types is ignored, store zeros */
.offset = header->event_offset,
.size = header->event_size,
},
}; };
memcpy(&f_header.adds_features, &header->adds_features, sizeof(header->adds_features)); memcpy(&f_header.adds_features, &header->adds_features, sizeof(header->adds_features));
...@@ -2417,7 +2374,7 @@ int perf_header__process_sections(struct perf_header *header, int fd, ...@@ -2417,7 +2374,7 @@ int perf_header__process_sections(struct perf_header *header, int fd,
sec_size = sizeof(*feat_sec) * nr_sections; sec_size = sizeof(*feat_sec) * nr_sections;
lseek(fd, header->data_offset + header->data_size, SEEK_SET); lseek(fd, header->feat_offset, SEEK_SET);
err = perf_header__getbuffer64(header, fd, feat_sec, sec_size); err = perf_header__getbuffer64(header, fd, feat_sec, sec_size);
if (err < 0) if (err < 0)
...@@ -2523,6 +2480,7 @@ static int check_magic_endian(u64 magic, uint64_t hdr_sz, ...@@ -2523,6 +2480,7 @@ static int check_magic_endian(u64 magic, uint64_t hdr_sz,
/* check for legacy format */ /* check for legacy format */
ret = memcmp(&magic, __perf_magic1, sizeof(magic)); ret = memcmp(&magic, __perf_magic1, sizeof(magic));
if (ret == 0) { if (ret == 0) {
ph->version = PERF_HEADER_VERSION_1;
pr_debug("legacy perf.data format\n"); pr_debug("legacy perf.data format\n");
if (is_pipe) if (is_pipe)
return try_all_pipe_abis(hdr_sz, ph); return try_all_pipe_abis(hdr_sz, ph);
...@@ -2544,6 +2502,7 @@ static int check_magic_endian(u64 magic, uint64_t hdr_sz, ...@@ -2544,6 +2502,7 @@ static int check_magic_endian(u64 magic, uint64_t hdr_sz,
return -1; return -1;
ph->needs_swap = true; ph->needs_swap = true;
ph->version = PERF_HEADER_VERSION_2;
return 0; return 0;
} }
...@@ -2614,10 +2573,9 @@ int perf_file_header__read(struct perf_file_header *header, ...@@ -2614,10 +2573,9 @@ int perf_file_header__read(struct perf_file_header *header,
memcpy(&ph->adds_features, &header->adds_features, memcpy(&ph->adds_features, &header->adds_features,
sizeof(ph->adds_features)); sizeof(ph->adds_features));
ph->event_offset = header->event_types.offset;
ph->event_size = header->event_types.size;
ph->data_offset = header->data.offset; ph->data_offset = header->data.offset;
ph->data_size = header->data.size; ph->data_size = header->data.size;
ph->feat_offset = header->data.offset + header->data.size;
return 0; return 0;
} }
...@@ -2666,19 +2624,17 @@ static int perf_file_header__read_pipe(struct perf_pipe_file_header *header, ...@@ -2666,19 +2624,17 @@ static int perf_file_header__read_pipe(struct perf_pipe_file_header *header,
return 0; return 0;
} }
static int perf_header__read_pipe(struct perf_session *session, int fd) static int perf_header__read_pipe(struct perf_session *session)
{ {
struct perf_header *header = &session->header; struct perf_header *header = &session->header;
struct perf_pipe_file_header f_header; struct perf_pipe_file_header f_header;
if (perf_file_header__read_pipe(&f_header, header, fd, if (perf_file_header__read_pipe(&f_header, header, session->fd,
session->repipe) < 0) { session->repipe) < 0) {
pr_debug("incompatible file format\n"); pr_debug("incompatible file format\n");
return -EINVAL; return -EINVAL;
} }
session->fd = fd;
return 0; return 0;
} }
...@@ -2772,20 +2728,21 @@ static int perf_evlist__prepare_tracepoint_events(struct perf_evlist *evlist, ...@@ -2772,20 +2728,21 @@ static int perf_evlist__prepare_tracepoint_events(struct perf_evlist *evlist,
return 0; return 0;
} }
int perf_session__read_header(struct perf_session *session, int fd) int perf_session__read_header(struct perf_session *session)
{ {
struct perf_header *header = &session->header; struct perf_header *header = &session->header;
struct perf_file_header f_header; struct perf_file_header f_header;
struct perf_file_attr f_attr; struct perf_file_attr f_attr;
u64 f_id; u64 f_id;
int nr_attrs, nr_ids, i, j; int nr_attrs, nr_ids, i, j;
int fd = session->fd;
session->evlist = perf_evlist__new(); session->evlist = perf_evlist__new();
if (session->evlist == NULL) if (session->evlist == NULL)
return -ENOMEM; return -ENOMEM;
if (session->fd_pipe) if (session->fd_pipe)
return perf_header__read_pipe(session, fd); return perf_header__read_pipe(session);
if (perf_file_header__read(&f_header, header, fd) < 0) if (perf_file_header__read(&f_header, header, fd) < 0)
return -EINVAL; return -EINVAL;
...@@ -2839,22 +2796,9 @@ int perf_session__read_header(struct perf_session *session, int fd) ...@@ -2839,22 +2796,9 @@ int perf_session__read_header(struct perf_session *session, int fd)
symbol_conf.nr_events = nr_attrs; symbol_conf.nr_events = nr_attrs;
if (f_header.event_types.size) {
lseek(fd, f_header.event_types.offset, SEEK_SET);
trace_events = malloc(f_header.event_types.size);
if (trace_events == NULL)
return -ENOMEM;
if (perf_header__getbuffer64(header, fd, trace_events,
f_header.event_types.size))
goto out_errno;
trace_event_count = f_header.event_types.size / sizeof(struct perf_trace_event_type);
}
perf_header__process_sections(header, fd, &session->pevent, perf_header__process_sections(header, fd, &session->pevent,
perf_file_section__process); perf_file_section__process);
lseek(fd, header->data_offset, SEEK_SET);
if (perf_evlist__prepare_tracepoint_events(session->evlist, if (perf_evlist__prepare_tracepoint_events(session->evlist,
session->pevent)) session->pevent))
goto out_delete_evlist; goto out_delete_evlist;
...@@ -2922,7 +2866,8 @@ int perf_event__synthesize_attrs(struct perf_tool *tool, ...@@ -2922,7 +2866,8 @@ int perf_event__synthesize_attrs(struct perf_tool *tool,
return err; return err;
} }
int perf_event__process_attr(union perf_event *event, int perf_event__process_attr(struct perf_tool *tool __maybe_unused,
union perf_event *event,
struct perf_evlist **pevlist) struct perf_evlist **pevlist)
{ {
u32 i, ids, n_ids; u32 i, ids, n_ids;
...@@ -2961,64 +2906,6 @@ int perf_event__process_attr(union perf_event *event, ...@@ -2961,64 +2906,6 @@ int perf_event__process_attr(union perf_event *event,
return 0; return 0;
} }
int perf_event__synthesize_event_type(struct perf_tool *tool,
u64 event_id, char *name,
perf_event__handler_t process,
struct machine *machine)
{
union perf_event ev;
size_t size = 0;
int err = 0;
memset(&ev, 0, sizeof(ev));
ev.event_type.event_type.event_id = event_id;
memset(ev.event_type.event_type.name, 0, MAX_EVENT_NAME);
strncpy(ev.event_type.event_type.name, name, MAX_EVENT_NAME - 1);
ev.event_type.header.type = PERF_RECORD_HEADER_EVENT_TYPE;
size = strlen(ev.event_type.event_type.name);
size = PERF_ALIGN(size, sizeof(u64));
ev.event_type.header.size = sizeof(ev.event_type) -
(sizeof(ev.event_type.event_type.name) - size);
err = process(tool, &ev, NULL, machine);
return err;
}
int perf_event__synthesize_event_types(struct perf_tool *tool,
perf_event__handler_t process,
struct machine *machine)
{
struct perf_trace_event_type *type;
int i, err = 0;
for (i = 0; i < trace_event_count; i++) {
type = &trace_events[i];
err = perf_event__synthesize_event_type(tool, type->event_id,
type->name, process,
machine);
if (err) {
pr_debug("failed to create perf header event type\n");
return err;
}
}
return err;
}
int perf_event__process_event_type(struct perf_tool *tool __maybe_unused,
union perf_event *event)
{
if (perf_header__push_event(event->event_type.event_type.event_id,
event->event_type.event_type.name) < 0)
return -ENOMEM;
return 0;
}
int perf_event__synthesize_tracing_data(struct perf_tool *tool, int fd, int perf_event__synthesize_tracing_data(struct perf_tool *tool, int fd,
struct perf_evlist *evlist, struct perf_evlist *evlist,
perf_event__handler_t process) perf_event__handler_t process)
...@@ -3065,7 +2952,8 @@ int perf_event__synthesize_tracing_data(struct perf_tool *tool, int fd, ...@@ -3065,7 +2952,8 @@ int perf_event__synthesize_tracing_data(struct perf_tool *tool, int fd,
return aligned_size; return aligned_size;
} }
int perf_event__process_tracing_data(union perf_event *event, int perf_event__process_tracing_data(struct perf_tool *tool __maybe_unused,
union perf_event *event,
struct perf_session *session) struct perf_session *session)
{ {
ssize_t size_read, padding, size = event->tracing_data.size; ssize_t size_read, padding, size = event->tracing_data.size;
......
...@@ -34,6 +34,11 @@ enum { ...@@ -34,6 +34,11 @@ enum {
HEADER_FEAT_BITS = 256, HEADER_FEAT_BITS = 256,
}; };
enum perf_header_version {
PERF_HEADER_VERSION_1,
PERF_HEADER_VERSION_2,
};
struct perf_file_section { struct perf_file_section {
u64 offset; u64 offset;
u64 size; u64 size;
...@@ -45,6 +50,7 @@ struct perf_file_header { ...@@ -45,6 +50,7 @@ struct perf_file_header {
u64 attr_size; u64 attr_size;
struct perf_file_section attrs; struct perf_file_section attrs;
struct perf_file_section data; struct perf_file_section data;
/* event_types is ignored */
struct perf_file_section event_types; struct perf_file_section event_types;
DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS); DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS);
}; };
...@@ -84,28 +90,24 @@ struct perf_session_env { ...@@ -84,28 +90,24 @@ struct perf_session_env {
}; };
struct perf_header { struct perf_header {
bool needs_swap; enum perf_header_version version;
s64 attr_offset; bool needs_swap;
u64 data_offset; u64 data_offset;
u64 data_size; u64 data_size;
u64 event_offset; u64 feat_offset;
u64 event_size;
DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS); DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS);
struct perf_session_env env; struct perf_session_env env;
}; };
struct perf_evlist; struct perf_evlist;
struct perf_session; struct perf_session;
int perf_session__read_header(struct perf_session *session, int fd); int perf_session__read_header(struct perf_session *session);
int perf_session__write_header(struct perf_session *session, int perf_session__write_header(struct perf_session *session,
struct perf_evlist *evlist, struct perf_evlist *evlist,
int fd, bool at_exit); int fd, bool at_exit);
int perf_header__write_pipe(int fd); int perf_header__write_pipe(int fd);
int perf_header__push_event(u64 id, const char *name);
char *perf_header__find_event(u64 id);
void perf_header__set_feat(struct perf_header *header, int feat); void perf_header__set_feat(struct perf_header *header, int feat);
void perf_header__clear_feat(struct perf_header *header, int feat); void perf_header__clear_feat(struct perf_header *header, int feat);
bool perf_header__has_feat(const struct perf_header *header, int feat); bool perf_header__has_feat(const struct perf_header *header, int feat);
...@@ -130,22 +132,14 @@ int perf_event__synthesize_attr(struct perf_tool *tool, ...@@ -130,22 +132,14 @@ int perf_event__synthesize_attr(struct perf_tool *tool,
int perf_event__synthesize_attrs(struct perf_tool *tool, int perf_event__synthesize_attrs(struct perf_tool *tool,
struct perf_session *session, struct perf_session *session,
perf_event__handler_t process); perf_event__handler_t process);
int perf_event__process_attr(union perf_event *event, struct perf_evlist **pevlist); int perf_event__process_attr(struct perf_tool *tool, union perf_event *event,
struct perf_evlist **pevlist);
int perf_event__synthesize_event_type(struct perf_tool *tool,
u64 event_id, char *name,
perf_event__handler_t process,
struct machine *machine);
int perf_event__synthesize_event_types(struct perf_tool *tool,
perf_event__handler_t process,
struct machine *machine);
int perf_event__process_event_type(struct perf_tool *tool,
union perf_event *event);
int perf_event__synthesize_tracing_data(struct perf_tool *tool, int perf_event__synthesize_tracing_data(struct perf_tool *tool,
int fd, struct perf_evlist *evlist, int fd, struct perf_evlist *evlist,
perf_event__handler_t process); perf_event__handler_t process);
int perf_event__process_tracing_data(union perf_event *event, int perf_event__process_tracing_data(struct perf_tool *tool,
union perf_event *event,
struct perf_session *session); struct perf_session *session);
int perf_event__synthesize_build_id(struct perf_tool *tool, int perf_event__synthesize_build_id(struct perf_tool *tool,
......
...@@ -912,6 +912,7 @@ static struct hist_entry *hists__add_dummy_entry(struct hists *hists, ...@@ -912,6 +912,7 @@ static struct hist_entry *hists__add_dummy_entry(struct hists *hists,
rb_link_node(&he->rb_node_in, parent, p); rb_link_node(&he->rb_node_in, parent, p);
rb_insert_color(&he->rb_node_in, root); rb_insert_color(&he->rb_node_in, root);
hists__inc_nr_entries(hists, he); hists__inc_nr_entries(hists, he);
he->dummy = true;
} }
out: out:
return he; return he;
......
...@@ -141,10 +141,12 @@ struct perf_hpp { ...@@ -141,10 +141,12 @@ struct perf_hpp {
}; };
struct perf_hpp_fmt { struct perf_hpp_fmt {
int (*header)(struct perf_hpp *hpp); int (*header)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp);
int (*width)(struct perf_hpp *hpp); int (*width)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp);
int (*color)(struct perf_hpp *hpp, struct hist_entry *he); int (*color)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
int (*entry)(struct perf_hpp *hpp, struct hist_entry *he); struct hist_entry *he);
int (*entry)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
struct hist_entry *he);
struct list_head list; struct list_head list;
}; };
...@@ -157,7 +159,7 @@ extern struct list_head perf_hpp__list; ...@@ -157,7 +159,7 @@ extern struct list_head perf_hpp__list;
extern struct perf_hpp_fmt perf_hpp__format[]; extern struct perf_hpp_fmt perf_hpp__format[];
enum { enum {
PERF_HPP__BASELINE, /* Matches perf_hpp__format array. */
PERF_HPP__OVERHEAD, PERF_HPP__OVERHEAD,
PERF_HPP__OVERHEAD_SYS, PERF_HPP__OVERHEAD_SYS,
PERF_HPP__OVERHEAD_US, PERF_HPP__OVERHEAD_US,
...@@ -165,11 +167,6 @@ enum { ...@@ -165,11 +167,6 @@ enum {
PERF_HPP__OVERHEAD_GUEST_US, PERF_HPP__OVERHEAD_GUEST_US,
PERF_HPP__SAMPLES, PERF_HPP__SAMPLES,
PERF_HPP__PERIOD, PERF_HPP__PERIOD,
PERF_HPP__PERIOD_BASELINE,
PERF_HPP__DELTA,
PERF_HPP__RATIO,
PERF_HPP__WEIGHTED_DIFF,
PERF_HPP__FORMULA,
PERF_HPP__MAX_INDEX PERF_HPP__MAX_INDEX
}; };
...@@ -177,8 +174,6 @@ enum { ...@@ -177,8 +174,6 @@ enum {
void perf_hpp__init(void); void perf_hpp__init(void);
void perf_hpp__column_register(struct perf_hpp_fmt *format); void perf_hpp__column_register(struct perf_hpp_fmt *format);
void perf_hpp__column_enable(unsigned col); void perf_hpp__column_enable(unsigned col);
int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he,
bool color);
struct perf_evlist; struct perf_evlist;
...@@ -245,11 +240,4 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist __maybe_unused, ...@@ -245,11 +240,4 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist __maybe_unused,
#endif #endif
unsigned int hists__sort_list_width(struct hists *self); unsigned int hists__sort_list_width(struct hists *self);
double perf_diff__compute_delta(struct hist_entry *he, struct hist_entry *pair);
double perf_diff__compute_ratio(struct hist_entry *he, struct hist_entry *pair);
s64 perf_diff__compute_wdiff(struct hist_entry *he, struct hist_entry *pair);
int perf_diff__formula(struct hist_entry *he, struct hist_entry *pair,
char *buf, size_t size);
double perf_diff__period_percent(struct hist_entry *he, u64 period);
#endif /* __PERF_HIST_H */ #endif /* __PERF_HIST_H */
#include <string.h> #include <string.h>
void *memdup(const void *src, size_t len); void *memdup(const void *src, size_t len);
int str_append(char **s, int *len, const char *a);
...@@ -233,7 +233,7 @@ void machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size) ...@@ -233,7 +233,7 @@ void machines__set_id_hdr_size(struct machines *machines, u16 id_hdr_size)
return; return;
} }
static struct thread *__machine__findnew_thread(struct machine *machine, pid_t pid, static struct thread *__machine__findnew_thread(struct machine *machine, pid_t tid,
bool create) bool create)
{ {
struct rb_node **p = &machine->threads.rb_node; struct rb_node **p = &machine->threads.rb_node;
...@@ -241,23 +241,23 @@ static struct thread *__machine__findnew_thread(struct machine *machine, pid_t p ...@@ -241,23 +241,23 @@ static struct thread *__machine__findnew_thread(struct machine *machine, pid_t p
struct thread *th; struct thread *th;
/* /*
* Font-end cache - PID lookups come in blocks, * Front-end cache - TID lookups come in blocks,
* so most of the time we dont have to look up * so most of the time we dont have to look up
* the full rbtree: * the full rbtree:
*/ */
if (machine->last_match && machine->last_match->pid == pid) if (machine->last_match && machine->last_match->tid == tid)
return machine->last_match; return machine->last_match;
while (*p != NULL) { while (*p != NULL) {
parent = *p; parent = *p;
th = rb_entry(parent, struct thread, rb_node); th = rb_entry(parent, struct thread, rb_node);
if (th->pid == pid) { if (th->tid == tid) {
machine->last_match = th; machine->last_match = th;
return th; return th;
} }
if (pid < th->pid) if (tid < th->tid)
p = &(*p)->rb_left; p = &(*p)->rb_left;
else else
p = &(*p)->rb_right; p = &(*p)->rb_right;
...@@ -266,7 +266,7 @@ static struct thread *__machine__findnew_thread(struct machine *machine, pid_t p ...@@ -266,7 +266,7 @@ static struct thread *__machine__findnew_thread(struct machine *machine, pid_t p
if (!create) if (!create)
return NULL; return NULL;
th = thread__new(pid); th = thread__new(tid);
if (th != NULL) { if (th != NULL) {
rb_link_node(&th->rb_node, parent, p); rb_link_node(&th->rb_node, parent, p);
rb_insert_color(&th->rb_node, &machine->threads); rb_insert_color(&th->rb_node, &machine->threads);
...@@ -276,14 +276,14 @@ static struct thread *__machine__findnew_thread(struct machine *machine, pid_t p ...@@ -276,14 +276,14 @@ static struct thread *__machine__findnew_thread(struct machine *machine, pid_t p
return th; return th;
} }
struct thread *machine__findnew_thread(struct machine *machine, pid_t pid) struct thread *machine__findnew_thread(struct machine *machine, pid_t tid)
{ {
return __machine__findnew_thread(machine, pid, true); return __machine__findnew_thread(machine, tid, true);
} }
struct thread *machine__find_thread(struct machine *machine, pid_t pid) struct thread *machine__find_thread(struct machine *machine, pid_t tid)
{ {
return __machine__findnew_thread(machine, pid, false); return __machine__findnew_thread(machine, tid, false);
} }
int machine__process_comm_event(struct machine *machine, union perf_event *event) int machine__process_comm_event(struct machine *machine, union perf_event *event)
...@@ -1058,11 +1058,10 @@ int machine__process_event(struct machine *machine, union perf_event *event) ...@@ -1058,11 +1058,10 @@ int machine__process_event(struct machine *machine, union perf_event *event)
return ret; return ret;
} }
static bool symbol__match_parent_regex(struct symbol *sym) static bool symbol__match_regex(struct symbol *sym, regex_t *regex)
{ {
if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0)) if (sym->name && !regexec(regex, sym->name, 0, NULL, 0))
return 1; return 1;
return 0; return 0;
} }
...@@ -1159,8 +1158,8 @@ struct branch_info *machine__resolve_bstack(struct machine *machine, ...@@ -1159,8 +1158,8 @@ struct branch_info *machine__resolve_bstack(struct machine *machine,
static int machine__resolve_callchain_sample(struct machine *machine, static int machine__resolve_callchain_sample(struct machine *machine,
struct thread *thread, struct thread *thread,
struct ip_callchain *chain, struct ip_callchain *chain,
struct symbol **parent) struct symbol **parent,
struct addr_location *root_al)
{ {
u8 cpumode = PERF_RECORD_MISC_USER; u8 cpumode = PERF_RECORD_MISC_USER;
unsigned int i; unsigned int i;
...@@ -1211,8 +1210,15 @@ static int machine__resolve_callchain_sample(struct machine *machine, ...@@ -1211,8 +1210,15 @@ static int machine__resolve_callchain_sample(struct machine *machine,
MAP__FUNCTION, ip, &al, NULL); MAP__FUNCTION, ip, &al, NULL);
if (al.sym != NULL) { if (al.sym != NULL) {
if (sort__has_parent && !*parent && if (sort__has_parent && !*parent &&
symbol__match_parent_regex(al.sym)) symbol__match_regex(al.sym, &parent_regex))
*parent = al.sym; *parent = al.sym;
else if (have_ignore_callees && root_al &&
symbol__match_regex(al.sym, &ignore_callees_regex)) {
/* Treat this symbol as the root,
forgetting its callees. */
*root_al = al;
callchain_cursor_reset(&callchain_cursor);
}
if (!symbol_conf.use_callchain) if (!symbol_conf.use_callchain)
break; break;
} }
...@@ -1237,15 +1243,13 @@ int machine__resolve_callchain(struct machine *machine, ...@@ -1237,15 +1243,13 @@ int machine__resolve_callchain(struct machine *machine,
struct perf_evsel *evsel, struct perf_evsel *evsel,
struct thread *thread, struct thread *thread,
struct perf_sample *sample, struct perf_sample *sample,
struct symbol **parent) struct symbol **parent,
struct addr_location *root_al)
{ {
int ret; int ret;
callchain_cursor_reset(&callchain_cursor);
ret = machine__resolve_callchain_sample(machine, thread, ret = machine__resolve_callchain_sample(machine, thread,
sample->callchain, parent); sample->callchain, parent, root_al);
if (ret) if (ret)
return ret; return ret;
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include <linux/rbtree.h> #include <linux/rbtree.h>
#include "map.h" #include "map.h"
struct addr_location;
struct branch_stack; struct branch_stack;
struct perf_evsel; struct perf_evsel;
struct perf_sample; struct perf_sample;
...@@ -36,7 +37,7 @@ struct map *machine__kernel_map(struct machine *machine, enum map_type type) ...@@ -36,7 +37,7 @@ struct map *machine__kernel_map(struct machine *machine, enum map_type type)
return machine->vmlinux_maps[type]; return machine->vmlinux_maps[type];
} }
struct thread *machine__find_thread(struct machine *machine, pid_t pid); struct thread *machine__find_thread(struct machine *machine, pid_t tid);
int machine__process_comm_event(struct machine *machine, union perf_event *event); int machine__process_comm_event(struct machine *machine, union perf_event *event);
int machine__process_exit_event(struct machine *machine, union perf_event *event); int machine__process_exit_event(struct machine *machine, union perf_event *event);
...@@ -83,7 +84,8 @@ int machine__resolve_callchain(struct machine *machine, ...@@ -83,7 +84,8 @@ int machine__resolve_callchain(struct machine *machine,
struct perf_evsel *evsel, struct perf_evsel *evsel,
struct thread *thread, struct thread *thread,
struct perf_sample *sample, struct perf_sample *sample,
struct symbol **parent); struct symbol **parent,
struct addr_location *root_al);
/* /*
* Default guest kernel is defined by parameter --guestkallsyms * Default guest kernel is defined by parameter --guestkallsyms
...@@ -99,7 +101,7 @@ static inline bool machine__is_host(struct machine *machine) ...@@ -99,7 +101,7 @@ static inline bool machine__is_host(struct machine *machine)
return machine ? machine->pid == HOST_KERNEL_ID : false; return machine ? machine->pid == HOST_KERNEL_ID : false;
} }
struct thread *machine__findnew_thread(struct machine *machine, pid_t pid); struct thread *machine__findnew_thread(struct machine *machine, pid_t tid);
size_t machine__fprintf(struct machine *machine, FILE *fp); size_t machine__fprintf(struct machine *machine, FILE *fp);
......
This diff is collapsed.
...@@ -23,6 +23,7 @@ struct tracepoint_path { ...@@ -23,6 +23,7 @@ struct tracepoint_path {
}; };
extern struct tracepoint_path *tracepoint_id_to_path(u64 config); extern struct tracepoint_path *tracepoint_id_to_path(u64 config);
extern struct tracepoint_path *tracepoint_name_to_path(const char *name);
extern bool have_tracepoints(struct list_head *evlist); extern bool have_tracepoints(struct list_head *evlist);
const char *event_type(int type); const char *event_type(int type);
...@@ -84,16 +85,16 @@ void parse_events__free_terms(struct list_head *terms); ...@@ -84,16 +85,16 @@ void parse_events__free_terms(struct list_head *terms);
int parse_events__modifier_event(struct list_head *list, char *str, bool add); int parse_events__modifier_event(struct list_head *list, char *str, bool add);
int parse_events__modifier_group(struct list_head *list, char *event_mod); int parse_events__modifier_group(struct list_head *list, char *event_mod);
int parse_events_name(struct list_head *list, char *name); int parse_events_name(struct list_head *list, char *name);
int parse_events_add_tracepoint(struct list_head **list, int *idx, int parse_events_add_tracepoint(struct list_head *list, int *idx,
char *sys, char *event); char *sys, char *event);
int parse_events_add_numeric(struct list_head **list, int *idx, int parse_events_add_numeric(struct list_head *list, int *idx,
u32 type, u64 config, u32 type, u64 config,
struct list_head *head_config); struct list_head *head_config);
int parse_events_add_cache(struct list_head **list, int *idx, int parse_events_add_cache(struct list_head *list, int *idx,
char *type, char *op_result1, char *op_result2); char *type, char *op_result1, char *op_result2);
int parse_events_add_breakpoint(struct list_head **list, int *idx, int parse_events_add_breakpoint(struct list_head *list, int *idx,
void *ptr, char *type); void *ptr, char *type);
int parse_events_add_pmu(struct list_head **list, int *idx, int parse_events_add_pmu(struct list_head *list, int *idx,
char *pmu , struct list_head *head_config); char *pmu , struct list_head *head_config);
void parse_events__set_leader(char *name, struct list_head *list); void parse_events__set_leader(char *name, struct list_head *list);
void parse_events_update_lists(struct list_head *list_event, void parse_events_update_lists(struct list_head *list_event,
......
...@@ -22,6 +22,13 @@ do { \ ...@@ -22,6 +22,13 @@ do { \
YYABORT; \ YYABORT; \
} while (0) } while (0)
#define ALLOC_LIST(list) \
do { \
list = malloc(sizeof(*list)); \
ABORT_ON(!list); \
INIT_LIST_HEAD(list); \
} while (0)
static inc_group_count(struct list_head *list, static inc_group_count(struct list_head *list,
struct parse_events_evlist *data) struct parse_events_evlist *data)
{ {
...@@ -196,9 +203,10 @@ event_pmu: ...@@ -196,9 +203,10 @@ event_pmu:
PE_NAME '/' event_config '/' PE_NAME '/' event_config '/'
{ {
struct parse_events_evlist *data = _data; struct parse_events_evlist *data = _data;
struct list_head *list = NULL; struct list_head *list;
ABORT_ON(parse_events_add_pmu(&list, &data->idx, $1, $3)); ALLOC_LIST(list);
ABORT_ON(parse_events_add_pmu(list, &data->idx, $1, $3));
parse_events__free_terms($3); parse_events__free_terms($3);
$$ = list; $$ = list;
} }
...@@ -212,11 +220,12 @@ event_legacy_symbol: ...@@ -212,11 +220,12 @@ event_legacy_symbol:
value_sym '/' event_config '/' value_sym '/' event_config '/'
{ {
struct parse_events_evlist *data = _data; struct parse_events_evlist *data = _data;
struct list_head *list = NULL; struct list_head *list;
int type = $1 >> 16; int type = $1 >> 16;
int config = $1 & 255; int config = $1 & 255;
ABORT_ON(parse_events_add_numeric(&list, &data->idx, ALLOC_LIST(list);
ABORT_ON(parse_events_add_numeric(list, &data->idx,
type, config, $3)); type, config, $3));
parse_events__free_terms($3); parse_events__free_terms($3);
$$ = list; $$ = list;
...@@ -225,11 +234,12 @@ value_sym '/' event_config '/' ...@@ -225,11 +234,12 @@ value_sym '/' event_config '/'
value_sym sep_slash_dc value_sym sep_slash_dc
{ {
struct parse_events_evlist *data = _data; struct parse_events_evlist *data = _data;
struct list_head *list = NULL; struct list_head *list;
int type = $1 >> 16; int type = $1 >> 16;
int config = $1 & 255; int config = $1 & 255;
ABORT_ON(parse_events_add_numeric(&list, &data->idx, ALLOC_LIST(list);
ABORT_ON(parse_events_add_numeric(list, &data->idx,
type, config, NULL)); type, config, NULL));
$$ = list; $$ = list;
} }
...@@ -238,27 +248,30 @@ event_legacy_cache: ...@@ -238,27 +248,30 @@ event_legacy_cache:
PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT
{ {
struct parse_events_evlist *data = _data; struct parse_events_evlist *data = _data;
struct list_head *list = NULL; struct list_head *list;
ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, $3, $5)); ALLOC_LIST(list);
ABORT_ON(parse_events_add_cache(list, &data->idx, $1, $3, $5));
$$ = list; $$ = list;
} }
| |
PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT
{ {
struct parse_events_evlist *data = _data; struct parse_events_evlist *data = _data;
struct list_head *list = NULL; struct list_head *list;
ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, $3, NULL)); ALLOC_LIST(list);
ABORT_ON(parse_events_add_cache(list, &data->idx, $1, $3, NULL));
$$ = list; $$ = list;
} }
| |
PE_NAME_CACHE_TYPE PE_NAME_CACHE_TYPE
{ {
struct parse_events_evlist *data = _data; struct parse_events_evlist *data = _data;
struct list_head *list = NULL; struct list_head *list;
ABORT_ON(parse_events_add_cache(&list, &data->idx, $1, NULL, NULL)); ALLOC_LIST(list);
ABORT_ON(parse_events_add_cache(list, &data->idx, $1, NULL, NULL));
$$ = list; $$ = list;
} }
...@@ -266,9 +279,10 @@ event_legacy_mem: ...@@ -266,9 +279,10 @@ event_legacy_mem:
PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc
{ {
struct parse_events_evlist *data = _data; struct parse_events_evlist *data = _data;
struct list_head *list = NULL; struct list_head *list;
ABORT_ON(parse_events_add_breakpoint(&list, &data->idx, ALLOC_LIST(list);
ABORT_ON(parse_events_add_breakpoint(list, &data->idx,
(void *) $2, $4)); (void *) $2, $4));
$$ = list; $$ = list;
} }
...@@ -276,9 +290,10 @@ PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc ...@@ -276,9 +290,10 @@ PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc
PE_PREFIX_MEM PE_VALUE sep_dc PE_PREFIX_MEM PE_VALUE sep_dc
{ {
struct parse_events_evlist *data = _data; struct parse_events_evlist *data = _data;
struct list_head *list = NULL; struct list_head *list;
ABORT_ON(parse_events_add_breakpoint(&list, &data->idx, ALLOC_LIST(list);
ABORT_ON(parse_events_add_breakpoint(list, &data->idx,
(void *) $2, NULL)); (void *) $2, NULL));
$$ = list; $$ = list;
} }
...@@ -287,9 +302,10 @@ event_legacy_tracepoint: ...@@ -287,9 +302,10 @@ event_legacy_tracepoint:
PE_NAME ':' PE_NAME PE_NAME ':' PE_NAME
{ {
struct parse_events_evlist *data = _data; struct parse_events_evlist *data = _data;
struct list_head *list = NULL; struct list_head *list;
ABORT_ON(parse_events_add_tracepoint(&list, &data->idx, $1, $3)); ALLOC_LIST(list);
ABORT_ON(parse_events_add_tracepoint(list, &data->idx, $1, $3));
$$ = list; $$ = list;
} }
...@@ -297,9 +313,10 @@ event_legacy_numeric: ...@@ -297,9 +313,10 @@ event_legacy_numeric:
PE_VALUE ':' PE_VALUE PE_VALUE ':' PE_VALUE
{ {
struct parse_events_evlist *data = _data; struct parse_events_evlist *data = _data;
struct list_head *list = NULL; struct list_head *list;
ABORT_ON(parse_events_add_numeric(&list, &data->idx, (u32)$1, $3, NULL)); ALLOC_LIST(list);
ABORT_ON(parse_events_add_numeric(list, &data->idx, (u32)$1, $3, NULL));
$$ = list; $$ = list;
} }
...@@ -307,9 +324,10 @@ event_legacy_raw: ...@@ -307,9 +324,10 @@ event_legacy_raw:
PE_RAW PE_RAW
{ {
struct parse_events_evlist *data = _data; struct parse_events_evlist *data = _data;
struct list_head *list = NULL; struct list_head *list;
ABORT_ON(parse_events_add_numeric(&list, &data->idx, ALLOC_LIST(list);
ABORT_ON(parse_events_add_numeric(list, &data->idx,
PERF_TYPE_RAW, $1, NULL)); PERF_TYPE_RAW, $1, NULL));
$$ = list; $$ = list;
} }
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment