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,
#define EVENT_PTR(_id, _suffix) &EVENT_VAR(_id, _suffix).attr.attr
#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)
#define GENERIC_EVENT_ATTR(_name, _id) EVENT_ATTR(_name, _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)
This diff is collapsed.
......@@ -53,37 +53,13 @@
/*
* Power7 event codes.
*/
#define PME_PM_CYC 0x1e
#define PME_PM_GCT_NOSLOT_CYC 0x100f8
#define PME_PM_CMPLU_STALL 0x4000a
#define PME_PM_INST_CMPL 0x2
#define PME_PM_LD_REF_L1 0xc880
#define PME_PM_LD_MISS_L1 0x400f0
#define PME_PM_BRU_FIN 0x10068
#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
#define EVENT(_name, _code) \
PME_##_name = _code,
enum {
#include "power7-events-list.h"
};
#undef EVENT
/*
* Layout of constraint bits:
......@@ -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(stalled-cycles-frontend, GCT_NOSLOT_CYC);
GENERIC_EVENT_ATTR(stalled-cycles-backend, CMPLU_STALL);
GENERIC_EVENT_ATTR(instructions, INST_CMPL);
GENERIC_EVENT_ATTR(cache-references, LD_REF_L1);
GENERIC_EVENT_ATTR(cache-misses, LD_MISS_L1);
GENERIC_EVENT_ATTR(branch-instructions, BRU_FIN);
GENERIC_EVENT_ATTR(branch-misses, BR_MPRED);
POWER_EVENT_ATTR(CYC, CYC);
POWER_EVENT_ATTR(GCT_NOSLOT_CYC, GCT_NOSLOT_CYC);
POWER_EVENT_ATTR(CMPLU_STALL, CMPLU_STALL);
POWER_EVENT_ATTR(INST_CMPL, INST_CMPL);
POWER_EVENT_ATTR(LD_REF_L1, LD_REF_L1);
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);
GENERIC_EVENT_ATTR(cpu-cycles, PM_CYC);
GENERIC_EVENT_ATTR(stalled-cycles-frontend, PM_GCT_NOSLOT_CYC);
GENERIC_EVENT_ATTR(stalled-cycles-backend, PM_CMPLU_STALL);
GENERIC_EVENT_ATTR(instructions, PM_INST_CMPL);
GENERIC_EVENT_ATTR(cache-references, PM_LD_REF_L1);
GENERIC_EVENT_ATTR(cache-misses, PM_LD_MISS_L1);
GENERIC_EVENT_ATTR(branch-instructions, PM_BRU_FIN);
GENERIC_EVENT_ATTR(branch-misses, PM_BR_MPRED);
#define EVENT(_name, _code) POWER_EVENT_ATTR(_name, _name);
#include "power7-events-list.h"
#undef EVENT
#define EVENT(_name, _code) POWER_EVENT_PTR(_name),
static struct attribute *power7_events_attr[] = {
GENERIC_EVENT_PTR(CYC),
GENERIC_EVENT_PTR(GCT_NOSLOT_CYC),
GENERIC_EVENT_PTR(CMPLU_STALL),
GENERIC_EVENT_PTR(INST_CMPL),
GENERIC_EVENT_PTR(LD_REF_L1),
GENERIC_EVENT_PTR(LD_MISS_L1),
GENERIC_EVENT_PTR(BRU_FIN),
GENERIC_EVENT_PTR(BR_MPRED),
POWER_EVENT_PTR(CYC),
POWER_EVENT_PTR(GCT_NOSLOT_CYC),
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),
GENERIC_EVENT_PTR(PM_CYC),
GENERIC_EVENT_PTR(PM_GCT_NOSLOT_CYC),
GENERIC_EVENT_PTR(PM_CMPLU_STALL),
GENERIC_EVENT_PTR(PM_INST_CMPL),
GENERIC_EVENT_PTR(PM_LD_REF_L1),
GENERIC_EVENT_PTR(PM_LD_MISS_L1),
GENERIC_EVENT_PTR(PM_BRU_FIN),
GENERIC_EVENT_PTR(PM_BR_MPRED),
#include "power7-events-list.h"
#undef EVENT
NULL
};
static struct attribute_group power7_pmu_events_group = {
.name = "events",
.attrs = power7_events_attr,
......
......@@ -39,13 +39,8 @@ bindir_relative = bin
bindir = $(prefix)/$(bindir_relative)
man_dir = $(prefix)/share/man
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 img_install img_install_SQ
export man_dir man_dir_SQ INSTALL
export DESTDIR DESTDIR_SQ
# copy a bit from Linux kbuild
......@@ -76,10 +71,7 @@ $(if $(BUILD_OUTPUT),, \
all: sub-make
gui: force
$(call build_output, all_cmd)
$(filter-out gui,$(MAKECMDGOALS)): sub-make
$(MAKECMDGOALS): sub-make
sub-make: force
$(call build_output, $(MAKECMDGOALS))
......@@ -189,6 +181,7 @@ $(obj)/%.o: $(src)/%.c
$(Q)$(call do_compile)
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)
......@@ -258,9 +251,6 @@ define check_deps
$(RM) $@.$$$$
endef
$(gui_deps): ks_version.h
$(non_gui_deps): tc_version.h
$(all_deps): .%.d: $(src)/%.c
$(Q)$(call check_deps)
......@@ -300,7 +290,7 @@ define do_install
$(INSTALL) $1 '$(DESTDIR_SQ)$2'
endef
install_lib: all_cmd install_plugins install_python
install_lib: all_cmd
$(Q)$(call do_install,$(LIB_FILE),$(bindir_SQ))
install: install_lib
......
......@@ -5450,10 +5450,9 @@ int pevent_register_print_function(struct pevent *pevent,
* If @id is >= 0, then it is used to find the event.
* else @sys_name and @event_name are used.
*/
int pevent_register_event_handler(struct pevent *pevent,
int id, char *sys_name, char *event_name,
pevent_event_handler_func func,
void *context)
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)
{
struct event_format *event;
struct event_handler *handle;
......
......@@ -69,6 +69,7 @@ struct trace_seq {
};
void trace_seq_init(struct trace_seq *s);
void trace_seq_reset(struct trace_seq *s);
void trace_seq_destroy(struct trace_seq *s);
extern int trace_seq_printf(struct trace_seq *s, const char *fmt, ...)
......@@ -399,6 +400,7 @@ struct pevent {
int cpus;
int long_size;
int page_size;
struct cmdline *cmdlines;
struct cmdline_list *cmdlist;
......@@ -561,7 +563,8 @@ int pevent_print_num_field(struct trace_seq *s, const char *fmt,
struct event_format *event, const char *name,
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);
int pevent_register_print_function(struct pevent *pevent,
pevent_func_handler func,
......@@ -619,6 +622,16 @@ static inline void pevent_set_long_size(struct pevent *pevent, int 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)
{
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)
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
* @s: a pointer to the trace_seq to free the buffer
......
......@@ -3,17 +3,17 @@ perf-diff(1)
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
--------
[verse]
'perf diff' [oldfile] [newfile]
'perf diff' [baseline file] [data file1] [[data file2] ... ]
DESCRIPTION
-----------
This command displays the performance difference amongst two perf.data files
captured via perf record.
This command displays the performance difference amongst two or more perf.data
files captured via perf record.
If no parameters are passed it will assume perf.data.old and perf.data.
......@@ -75,8 +75,6 @@ OPTIONS
-c::
--compute::
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.
-p::
......@@ -87,6 +85,63 @@ OPTIONS
--formula::
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
------------------
delta
......@@ -96,7 +151,7 @@ If specified the 'Delta' column is displayed with value 'd' computed as:
d = A->period_percent - B->period_percent
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.
- 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:
r = A->period / B->period
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.
- 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:
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.
- period being the hist entry period value
- WEIGHT-A/WEIGHT-B being user suplied weights in the the '-c' option
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
--------
......
......@@ -8,7 +8,7 @@ perf-list - List all symbolic event types
SYNOPSIS
--------
[verse]
'perf list' [hw|sw|cache|tracepoint|event_glob]
'perf list' [hw|sw|cache|tracepoint|pmu|event_glob]
DESCRIPTION
-----------
......@@ -104,6 +104,8 @@ To limit the list use:
'subsys_glob:event_glob' to filter by tracepoint subsystems such as sched,
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
events, printing the ones that match.
......
......@@ -135,6 +135,11 @@ OPTIONS
--inverted::
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 printing style. key: normal, raw
......
......@@ -155,6 +155,11 @@ Default is to monitor all CPUS.
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::
Do not show entries which have an overhead under that percent.
(Default: 0).
......
......@@ -124,7 +124,7 @@ strip-libs = $(filter-out -l%,$(1))
ifneq ($(OUTPUT),)
TE_PATH=$(OUTPUT)
ifneq ($(subdir),)
LK_PATH=$(objtree)/lib/lk/
LK_PATH=$(OUTPUT)/../lib/lk/
else
LK_PATH=$(OUTPUT)
endif
......@@ -281,7 +281,7 @@ LIB_H += util/cpumap.h
LIB_H += util/top.h
LIB_H += $(ARCH_INCLUDE)
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/rblist.h
LIB_H += util/intlist.h
......
This diff is collapsed.
......@@ -38,8 +38,7 @@ struct event_entry {
};
static int perf_event__repipe_synth(struct perf_tool *tool,
union perf_event *event,
struct machine *machine __maybe_unused)
union perf_event *event)
{
struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
uint32_t size;
......@@ -65,39 +64,28 @@ static int perf_event__repipe_op2_synth(struct perf_tool *tool,
struct perf_session *session
__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,
union perf_event *event)
{
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)
static int perf_event__repipe_attr(struct perf_tool *tool,
union perf_event *event,
struct perf_evlist **pevlist)
{
int ret;
ret = perf_event__process_attr(event, pevlist);
ret = perf_event__process_attr(tool, event, pevlist);
if (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,
union perf_event *event,
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,
......@@ -119,7 +107,7 @@ static int perf_event__repipe_sample(struct perf_tool *tool,
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,
......@@ -148,13 +136,14 @@ static int perf_event__repipe_fork(struct perf_tool *tool,
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)
{
int err;
perf_event__repipe_synth(NULL, event, NULL);
err = perf_event__process_tracing_data(event, session);
perf_event__repipe_synth(tool, event);
err = perf_event__process_tracing_data(tool, event, session);
return err;
}
......@@ -407,8 +396,8 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
.throttle = perf_event__repipe,
.unthrottle = perf_event__repipe,
.attr = perf_event__repipe_attr,
.event_type = perf_event__repipe_event_type_synth,
.tracing_data = perf_event__repipe_tracing_data_synth,
.tracing_data = perf_event__repipe_op2_synth,
.finished_round = perf_event__repipe_op2_synth,
.build_id = perf_event__repipe_op2_synth,
},
.input_name = "-",
......
......@@ -313,7 +313,7 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
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) {
tracepoint_handler f = evsel->handler.func;
......
......@@ -13,6 +13,7 @@
#include "util/parse-events.h"
#include "util/cache.h"
#include "util/pmu.h"
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 ||
strcmp(argv[i], "hwcache") == 0)
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)
print_events(NULL, true);
else {
......
......@@ -474,13 +474,6 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
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)) {
/*
* FIXME err <= 0 here actually means that
......@@ -904,7 +897,6 @@ const struct option record_options[] = {
int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
{
int err = -ENOMEM;
struct perf_evsel *pos;
struct perf_evlist *evsel_list;
struct perf_record *rec = &record;
char errbuf[BUFSIZ];
......@@ -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)
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)
rec->opts.default_interval = rec->opts.user_interval;
if (rec->opts.user_freq != UINT_MAX)
......
......@@ -89,7 +89,7 @@ static int perf_report__add_mem_hist_entry(struct perf_tool *tool,
if ((sort__has_parent || symbol_conf.use_callchain) &&
sample->callchain) {
err = machine__resolve_callchain(machine, evsel, al->thread,
sample, &parent);
sample, &parent, al);
if (err)
return err;
}
......@@ -180,7 +180,7 @@ static int perf_report__add_branch_hist_entry(struct perf_tool *tool,
if ((sort__has_parent || symbol_conf.use_callchain)
&& sample->callchain) {
err = machine__resolve_callchain(machine, evsel, al->thread,
sample, &parent);
sample, &parent, al);
if (err)
return err;
}
......@@ -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) {
err = machine__resolve_callchain(machine, evsel, al->thread,
sample, &parent);
sample, &parent, al);
if (err)
return err;
}
......@@ -497,7 +497,7 @@ static int __cmd_report(struct perf_report *rep)
ret = perf_session__cpu_bitmap(session, rep->cpu_list,
rep->cpu_bitmap);
if (ret)
goto out_delete;
return ret;
}
if (use_browser <= 0)
......@@ -508,11 +508,11 @@ static int __cmd_report(struct perf_report *rep)
ret = perf_report__setup_sample_type(rep);
if (ret)
goto out_delete;
return ret;
ret = perf_session__process_events(session, &rep->tool);
if (ret)
goto out_delete;
return ret;
kernel_map = session->machines.host.vmlinux_maps[MAP__FUNCTION];
kernel_kmap = map__kmap(kernel_map);
......@@ -547,7 +547,7 @@ static int __cmd_report(struct perf_report *rep)
if (dump_trace) {
perf_session__fprintf_nr_events(session, stdout);
goto out_delete;
return 0;
}
nr_samples = 0;
......@@ -572,7 +572,7 @@ static int __cmd_report(struct perf_report *rep)
if (nr_samples == 0) {
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)
......@@ -598,19 +598,6 @@ static int __cmd_report(struct perf_report *rep)
} else
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;
}
......@@ -694,6 +681,24 @@ parse_callchain_opt(const struct option *opt, const char *arg, int unset)
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
parse_branch_mode(const struct option *opt __maybe_unused,
const char *str __maybe_unused, int unset)
......@@ -736,7 +741,6 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
.lost = perf_event__process_lost,
.read = process_read_event,
.attr = perf_event__process_attr,
.event_type = perf_event__process_event_type,
.tracing_data = perf_event__process_tracing_data,
.build_id = perf_event__process_build_id,
.ordered_samples = true,
......@@ -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),
OPT_BOOLEAN('G', "inverted", &report.inverted_callchain,
"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...]",
"only consider symbols in these dsos"),
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)
setup_browser(true);
else {
use_browser = 0;
perf_hpp__column_enable(PERF_HPP__OVERHEAD);
perf_hpp__init();
}
......@@ -931,14 +937,6 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
if (parent_pattern != default_parent_pattern) {
if (sort_dimension__add("parent") < 0)
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) {
......
......@@ -1075,7 +1075,7 @@ static int latency_migrate_task_event(struct perf_sched *sched,
if (!atoms) {
if (thread_atoms_insert(sched, migrant))
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);
if (!atoms) {
pr_err("migration-event: Internal tree error");
......@@ -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_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++)
printf(" ");
......@@ -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)
{
if (l->thread->pid < r->thread->pid)
if (l->thread->tid < r->thread->tid)
return -1;
if (l->thread->pid > r->thread->pid)
if (l->thread->tid > r->thread->tid)
return 1;
return 0;
......@@ -1321,7 +1321,7 @@ static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel,
printf("*");
if (sched->curr_thread[cpu]) {
if (sched->curr_thread[cpu]->pid)
if (sched->curr_thread[cpu]->tid)
printf("%2s ", sched->curr_thread[cpu]->shortname);
else
printf(". ");
......@@ -1332,7 +1332,7 @@ static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel,
printf(" %12.6f secs ", (double)timestamp/1e9);
if (new_shortname) {
printf("%s => %s:%d\n",
sched_in->shortname, sched_in->comm, sched_in->pid);
sched_in->shortname, sched_in->comm, sched_in->tid);
} else {
printf("\n");
}
......@@ -1662,28 +1662,29 @@ static int __cmd_record(int argc, const char **argv)
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)
{
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[] = {
OPT_STRING('s', "sort", &sched.sort_order, "key[,key2...]",
"sort by key(s): runtime, switch, avg, max"),
......
......@@ -24,6 +24,7 @@ static u64 last_timestamp;
static u64 nr_unordered;
extern const struct option record_options[];
static bool no_callchain;
static bool latency_format;
static bool system_wide;
static const char *cpu_list;
static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
......@@ -523,7 +524,6 @@ static struct perf_tool perf_script = {
.exit = perf_event__process_exit,
.fork = perf_event__process_fork,
.attr = perf_event__process_attr,
.event_type = perf_event__process_event_type,
.tracing_data = perf_event__process_tracing_data,
.build_id = perf_event__process_build_id,
.ordered_samples = true,
......
......@@ -12,6 +12,8 @@
* of the License.
*/
#include <traceevent/event-parse.h>
#include "builtin.h"
#include "util/util.h"
......@@ -19,6 +21,7 @@
#include "util/color.h"
#include <linux/list.h>
#include "util/cache.h"
#include "util/evlist.h"
#include "util/evsel.h"
#include <linux/rbtree.h>
#include "util/symbol.h"
......@@ -328,25 +331,6 @@ struct wakeup_entry {
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 trace_entry te;
char prev_comm[TASK_COMM_LEN];
......@@ -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,
union perf_event *event __maybe_unused,
......@@ -486,8 +472,6 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
struct perf_evsel *evsel,
struct machine *machine __maybe_unused)
{
struct trace_entry *te;
if (evsel->attr.sample_type & PERF_SAMPLE_TIME) {
if (!first_time || first_time > sample->time)
first_time = sample->time;
......@@ -495,69 +479,90 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
last_time = sample->time;
}
te = (void *)sample->raw_data;
if ((evsel->attr.sample_type & PERF_SAMPLE_RAW) && sample->raw_size > 0) {
char *event_str;
#ifdef SUPPORT_OLD_POWER_EVENTS
struct power_entry_old *peo;
peo = (void *)te;
#endif
/*
* FIXME: use evsel, its already mapped from id to perf_evsel,
* 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.
*
* e.g.:
*
* if (evsel->attr.config == power_cpu_idle_id)
*/
event_str = perf_header__find_event(te->type);
if (!event_str)
return 0;
if (sample->cpu > numcpus)
numcpus = sample->cpu;
if (strcmp(event_str, "power:cpu_idle") == 0) {
struct power_processor_entry *ppe = (void *)te;
if (ppe->state == (u32)PWR_EVENT_EXIT)
c_state_end(ppe->cpu_id, sample->time);
else
c_state_start(ppe->cpu_id, sample->time,
ppe->state);
}
else if (strcmp(event_str, "power:cpu_frequency") == 0) {
struct power_processor_entry *ppe = (void *)te;
p_state_change(ppe->cpu_id, sample->time, ppe->state);
}
if (sample->cpu > numcpus)
numcpus = sample->cpu;
if (evsel->handler.func != NULL) {
tracepoint_handler f = evsel->handler.func;
return f(evsel, sample);
}
return 0;
}
static int
process_sample_cpu_idle(struct perf_evsel *evsel __maybe_unused,
struct perf_sample *sample)
{
struct power_processor_entry *ppe = sample->raw_data;
if (ppe->state == (u32) PWR_EVENT_EXIT)
c_state_end(ppe->cpu_id, sample->time);
else
c_state_start(ppe->cpu_id, sample->time, ppe->state);
return 0;
}
static int
process_sample_cpu_frequency(struct perf_evsel *evsel __maybe_unused,
struct perf_sample *sample)
{
struct power_processor_entry *ppe = sample->raw_data;
p_state_change(ppe->cpu_id, sample->time, ppe->state);
return 0;
}
static int
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)
sched_wakeup(sample->cpu, sample->time, sample->pid, te);
static int
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
if (use_old_power_events) {
if (strcmp(event_str, "power:power_start") == 0)
c_state_start(peo->cpu_id, sample->time,
peo->value);
else if (strcmp(event_str, "power:power_end") == 0)
c_state_end(sample->cpu, sample->time);
else if (strcmp(event_str,
"power:power_frequency") == 0)
p_state_change(peo->cpu_id, sample->time,
peo->value);
}
#endif
}
static int
process_sample_power_start(struct perf_evsel *evsel __maybe_unused,
struct perf_sample *sample)
{
struct power_entry_old *peo = sample->raw_data;
c_state_start(peo->cpu_id, sample->time, peo->value);
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
* and close out each CPU for these.
......@@ -974,6 +979,17 @@ static int __cmd_timechart(const char *output_name)
.sample = process_sample_event,
.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,
0, false, &perf_timechart);
int ret = -EINVAL;
......@@ -984,6 +1000,12 @@ static int __cmd_timechart(const char *output_name)
if (!perf_session__has_traces(session, "timechart record"))
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);
if (ret)
goto out_delete;
......
......@@ -40,6 +40,7 @@
#include "util/xyarray.h"
#include "util/sort.h"
#include "util/intlist.h"
#include "arch/common.h"
#include "util/debug.h"
......@@ -772,8 +773,7 @@ static void perf_event__process_sample(struct perf_tool *tool,
sample->callchain) {
err = machine__resolve_callchain(machine, evsel,
al.thread, sample,
&parent);
&parent, &al);
if (err)
return;
}
......@@ -939,6 +939,12 @@ static int __cmd_top(struct perf_top *top)
if (top->session == NULL)
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);
if (ret)
goto out_delete;
......@@ -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,
"mode[,dump_size]", record_callchain_help,
&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,
"Show a column with the sum of periods"),
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)
"Interleave source code with assembly code (default)"),
OPT_BOOLEAN(0, "asm-raw", &symbol_conf.annotate_asm_raw,
"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",
"Specify disassembler style (e.g. -M intel for intel syntax)"),
OPT_STRING('u', "uid", &target->uid_str, "user", "user to profile"),
......
#include <traceevent/event-parse.h>
#include "builtin.h"
#include "util/color.h"
#include "util/evlist.h"
......@@ -5,7 +6,6 @@
#include "util/thread.h"
#include "util/parse-options.h"
#include "util/thread_map.h"
#include "event-parse.h"
#include <libaudit.h>
#include <stdlib.h>
......@@ -142,7 +142,7 @@ static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thre
printed += fprintf_duration(duration, fp);
if (trace->multiple_threads)
printed += fprintf(fp, "%d ", thread->pid);
printed += fprintf(fp, "%d ", thread->tid);
return printed;
}
......@@ -593,7 +593,7 @@ static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp)
color = PERF_COLOR_YELLOW;
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 += fprintf(fp, " ] %10.3f ms\n", ttrace->runtime_ms);
}
......
......@@ -46,6 +46,8 @@ ifneq ($(obj-perf),)
obj-perf := $(abspath $(obj-perf))/
endif
LIB_INCLUDE := $(srctree)/tools/lib/
# include ARCH specific config
-include $(src-perf)/arch/$(ARCH)/Makefile
......@@ -121,8 +123,7 @@ endif
CFLAGS += -I$(src-perf)/util
CFLAGS += -I$(src-perf)
CFLAGS += -I$(TRACE_EVENT_DIR)
CFLAGS += -I$(srctree)/tools/lib/
CFLAGS += -I$(LIB_INCLUDE)
CFLAGS += -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
......
......@@ -10,14 +10,6 @@
#include "symbol.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 buf_templ[] = "/tmp/test-XXXXXX";
......
#include <traceevent/event-parse.h>
#include "evsel.h"
#include "tests.h"
#include "event-parse.h"
static int perf_evsel__test_field(struct perf_evsel *evsel, const char *name,
int size, bool should_be_signed)
......@@ -49,7 +49,7 @@ int test__perf_evsel__tp_sched_test(void)
if (perf_evsel__test_field(evsel, "prev_prio", 4, true))
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;
if (perf_evsel__test_field(evsel, "next_comm", 16, true))
......
......@@ -7,14 +7,6 @@
#include "tests.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 | \
PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD)
......@@ -1254,24 +1246,20 @@ static int test_events(struct evlist_test *events, unsigned cnt)
static int test_term(struct terms_test *t)
{
struct list_head *terms;
struct list_head terms;
int ret;
terms = malloc(sizeof(*terms));
if (!terms)
return -ENOMEM;
INIT_LIST_HEAD(terms);
INIT_LIST_HEAD(&terms);
ret = parse_events_terms(terms, t->str);
ret = parse_events_terms(&terms, t->str);
if (ret) {
pr_debug("failed to parse terms '%s', err %d\n",
t->str , ret);
return ret;
}
ret = t->check(terms);
parse_events__free_terms(terms);
ret = t->check(&terms);
parse_events__free_terms(&terms);
return ret;
}
......
#ifndef 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 {
TEST_OK = 0,
TEST_FAIL = -1,
......
......@@ -139,11 +139,18 @@ int test__vmlinux_matches_kallsyms(void)
* _really_ have a problem.
*/
s64 skew = sym->end - pair->end;
if (llabs(skew) < page_size)
continue;
if (llabs(skew) >= page_size)
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 {
struct rb_node *nnd;
detour:
......
......@@ -685,8 +685,10 @@ static u64 __hpp_get_##_field(struct hist_entry *he) \
return he->stat._field; \
} \
\
static int hist_browser__hpp_color_##_type(struct perf_hpp *hpp, \
struct hist_entry *he) \
static int \
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); \
}
......@@ -701,8 +703,6 @@ __HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us, NULL)
void hist_browser__init_hpp(void)
{
perf_hpp__column_enable(PERF_HPP__OVERHEAD);
perf_hpp__init();
perf_hpp__format[PERF_HPP__OVERHEAD].color =
......@@ -762,9 +762,9 @@ static int hist_browser__show_entry(struct hist_browser *browser,
first = false;
if (fmt->color) {
width -= fmt->color(&hpp, entry);
width -= fmt->color(fmt, &hpp, entry);
} else {
width -= fmt->entry(&hpp, entry);
width -= fmt->entry(fmt, &hpp, entry);
slsmg_printf("%s", s);
}
}
......@@ -1256,7 +1256,7 @@ static int hists__browser_title(struct hists *hists, char *bf, size_t size,
printed += scnprintf(bf + printed, size - printed,
", Thread: %s(%d)",
(thread->comm_set ? thread->comm : ""),
thread->pid);
thread->tid);
if (dso)
printed += scnprintf(bf + printed, size - printed,
", DSO: %s", dso->short_name);
......@@ -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",
(browser->hists->thread_filter ? "out of" : "into"),
(thread->comm_set ? thread->comm : ""),
thread->pid) > 0)
thread->tid) > 0)
zoom_thread = nr_options++;
if (dso != NULL &&
......@@ -1702,7 +1702,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
} else {
ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"",
thread->comm_set ? thread->comm : "",
thread->pid);
thread->tid);
browser->hists->thread_filter = thread;
sort_thread.elide = true;
pstack__push(fstack, &browser->hists->thread_filter);
......
......@@ -91,7 +91,8 @@ static u64 he_get_##_field(struct hist_entry *he) \
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) \
{ \
return __hpp__color_fmt(hpp, he, he_get_##_field); \
......@@ -124,6 +125,81 @@ void perf_gtk__init_hpp(void)
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,
float min_pcnt)
{
......@@ -131,10 +207,11 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
GType col_types[MAX_COLUMNS];
GtkCellRenderer *renderer;
struct sort_entry *se;
GtkListStore *store;
GtkTreeStore *store;
struct rb_node *nd;
GtkWidget *view;
int col_idx;
int sym_col = -1;
int nr_cols;
char s[512];
......@@ -153,10 +230,13 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
if (se->elide)
continue;
if (se == &sort_sym)
sym_col = nr_cols;
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();
......@@ -165,7 +245,7 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
col_idx = 0;
perf_hpp__for_each_format(fmt) {
fmt->header(&hpp);
fmt->header(fmt, &hpp);
gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
-1, ltrim(s),
......@@ -183,6 +263,18 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
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));
g_object_unref(GTK_TREE_MODEL(store));
......@@ -199,17 +291,17 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
if (percent < min_pcnt)
continue;
gtk_list_store_append(store, &iter);
gtk_tree_store_append(store, &iter, NULL);
col_idx = 0;
perf_hpp__for_each_format(fmt) {
if (fmt->color)
fmt->color(&hpp, h);
fmt->color(fmt, &hpp, h);
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) {
......@@ -219,10 +311,26 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
se->se_snprintf(h, s, ARRAY_SIZE(s),
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);
}
......
#include <math.h>
#include <linux/compiler.h>
#include "../util/hist.h"
#include "../util/util.h"
......@@ -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) \
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; \
\
......@@ -92,7 +94,8 @@ static int hpp__header_##_type(struct perf_hpp *hpp) \
}
#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; \
\
......@@ -110,14 +113,16 @@ static u64 he_get_##_field(struct hist_entry *he) \
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%%", \
(hpp_snprint_fn)percent_color_snprintf, true); \
}
#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%%"; \
return __hpp__fmt(hpp, he, he_get_##_field, fmt, \
......@@ -130,7 +135,8 @@ static u64 he_get_raw_##_field(struct hist_entry *he) \
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; \
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)
HPP_RAW_FNS(samples, "Samples", nr_events, 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) \
{ \
.header = hpp__header_ ## _name, \
......@@ -363,19 +179,13 @@ static int hpp__entry_formula(struct perf_hpp *hpp, struct hist_entry *he)
}
struct perf_hpp_fmt perf_hpp__format[] = {
HPP__COLOR_PRINT_FNS(baseline),
HPP__COLOR_PRINT_FNS(overhead),
HPP__COLOR_PRINT_FNS(overhead_sys),
HPP__COLOR_PRINT_FNS(overhead_us),
HPP__COLOR_PRINT_FNS(overhead_guest_sys),
HPP__COLOR_PRINT_FNS(overhead_guest_us),
HPP__PRINT_FNS(samples),
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)
HPP__PRINT_FNS(period)
};
LIST_HEAD(perf_hpp__list);
......@@ -396,6 +206,8 @@ LIST_HEAD(perf_hpp__list);
void perf_hpp__init(void)
{
perf_hpp__column_enable(PERF_HPP__OVERHEAD);
if (symbol_conf.show_cpu_utilization) {
perf_hpp__column_enable(PERF_HPP__OVERHEAD_SYS);
perf_hpp__column_enable(PERF_HPP__OVERHEAD_US);
......@@ -424,46 +236,6 @@ void perf_hpp__column_enable(unsigned 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,
struct hists *hists)
{
......@@ -499,7 +271,7 @@ unsigned int hists__sort_list_width(struct hists *hists)
if (i)
ret += 2;
ret += fmt->width(&dummy_hpp);
ret += fmt->width(fmt, &dummy_hpp);
}
list_for_each_entry(se, &hist_entry__sort_list, list)
......
......@@ -30,7 +30,6 @@ void setup_browser(bool fallback_to_pager)
if (fallback_to_pager)
setup_pager();
perf_hpp__column_enable(PERF_HPP__OVERHEAD);
perf_hpp__init();
break;
}
......
......@@ -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);
}
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,
struct hists *hists, FILE *fp)
{
......@@ -365,7 +406,7 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
else
first = false;
fmt->header(&dummy_hpp);
fmt->header(fmt, &dummy_hpp);
fprintf(fp, "%s", bf);
}
......@@ -410,7 +451,7 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
else
first = false;
width = fmt->width(&dummy_hpp);
width = fmt->width(fmt, &dummy_hpp);
for (i = 0; i < width; i++)
fprintf(fp, ".");
}
......
......@@ -41,7 +41,7 @@ static inline int cpu_map__nr(const struct cpu_map *map)
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;
}
......
......@@ -686,7 +686,7 @@ int perf_event__preprocess_sample(const union perf_event *event,
!strlist__has_entry(symbol_conf.comm_list, thread->comm))
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?
*
......
......@@ -116,7 +116,7 @@ struct build_id_event {
enum perf_user_event_type { /* above any possible kernel type */
PERF_RECORD_USER_TYPE_START = 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_BUILD_ID = 67,
PERF_RECORD_FINISHED_ROUND = 68,
......
......@@ -403,16 +403,20 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx)
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)
{
int i;
for (i = 0; i < evlist->nr_mmaps; i++) {
if (evlist->mmap[i].base != NULL) {
munmap(evlist->mmap[i].base, evlist->mmap_len);
evlist->mmap[i].base = NULL;
}
}
for (i = 0; i < evlist->nr_mmaps; i++)
__perf_evlist__munmap(evlist, i);
free(evlist->mmap);
evlist->mmap = NULL;
......@@ -421,7 +425,7 @@ void perf_evlist__munmap(struct perf_evlist *evlist)
static int perf_evlist__alloc_mmap(struct perf_evlist *evlist)
{
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->mmap = zalloc(evlist->nr_mmaps * sizeof(struct perf_mmap));
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
return 0;
out_unmap:
for (cpu = 0; cpu < nr_cpus; cpu++) {
if (evlist->mmap[cpu].base != NULL) {
munmap(evlist->mmap[cpu].base, evlist->mmap_len);
evlist->mmap[cpu].base = NULL;
}
}
for (cpu = 0; cpu < nr_cpus; cpu++)
__perf_evlist__munmap(evlist, cpu);
return -1;
}
......@@ -517,12 +517,8 @@ static int perf_evlist__mmap_per_thread(struct perf_evlist *evlist, int prot, in
return 0;
out_unmap:
for (thread = 0; thread < nr_threads; thread++) {
if (evlist->mmap[thread].base != NULL) {
munmap(evlist->mmap[thread].base, evlist->mmap_len);
evlist->mmap[thread].base = NULL;
}
}
for (thread = 0; thread < nr_threads; thread++)
__perf_evlist__munmap(evlist, thread);
return -1;
}
......@@ -573,7 +569,7 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
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_cpu(evlist, prot, mask);
......@@ -838,7 +834,7 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist,
int perf_evlist__start_workload(struct perf_evlist *evlist)
{
if (evlist->workload.cork_fd > 0) {
char bf;
char bf = 0;
int ret;
/*
* Remove the cork, let it rip!
......
......@@ -9,17 +9,17 @@
#include <byteswap.h>
#include <linux/bitops.h>
#include "asm/bug.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 "evlist.h"
#include "util.h"
#include "cpumap.h"
#include "thread_map.h"
#include "target.h"
#include <linux/hw_breakpoint.h>
#include <linux/perf_event.h>
#include "perf_regs.h"
static struct {
......
......@@ -25,41 +25,9 @@
static bool no_buildid_cache = false;
static int trace_event_count;
static struct perf_trace_event_type *trace_events;
static u32 header_argc;
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"
* must be a numerical value to let the endianness
......@@ -2257,7 +2225,7 @@ static int perf_header__adds_write(struct perf_header *header,
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);
for_each_set_bit(feat, header->adds_features, HEADER_FEAT_BITS) {
......@@ -2304,6 +2272,7 @@ int perf_session__write_header(struct perf_session *session,
struct perf_file_attr f_attr;
struct perf_header *header = &session->header;
struct perf_evsel *evsel;
u64 attr_offset;
int err;
lseek(fd, sizeof(f_header), SEEK_SET);
......@@ -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) {
f_attr = (struct perf_file_attr){
......@@ -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->feat_offset = header->data_offset + header->data_size;
if (at_exit) {
err = perf_header__adds_write(header, evlist, fd);
......@@ -2357,17 +2317,14 @@ int perf_session__write_header(struct perf_session *session,
.size = sizeof(f_header),
.attr_size = sizeof(f_attr),
.attrs = {
.offset = header->attr_offset,
.offset = attr_offset,
.size = evlist->nr_entries * sizeof(f_attr),
},
.data = {
.offset = header->data_offset,
.size = header->data_size,
},
.event_types = {
.offset = header->event_offset,
.size = header->event_size,
},
/* event_types is ignored, store zeros */
};
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,
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);
if (err < 0)
......@@ -2523,6 +2480,7 @@ static int check_magic_endian(u64 magic, uint64_t hdr_sz,
/* check for legacy format */
ret = memcmp(&magic, __perf_magic1, sizeof(magic));
if (ret == 0) {
ph->version = PERF_HEADER_VERSION_1;
pr_debug("legacy perf.data format\n");
if (is_pipe)
return try_all_pipe_abis(hdr_sz, ph);
......@@ -2544,6 +2502,7 @@ static int check_magic_endian(u64 magic, uint64_t hdr_sz,
return -1;
ph->needs_swap = true;
ph->version = PERF_HEADER_VERSION_2;
return 0;
}
......@@ -2614,10 +2573,9 @@ int perf_file_header__read(struct perf_file_header *header,
memcpy(&ph->adds_features, &header->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_size = header->data.size;
ph->feat_offset = header->data.offset + header->data.size;
return 0;
}
......@@ -2666,19 +2624,17 @@ static int perf_file_header__read_pipe(struct perf_pipe_file_header *header,
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_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) {
pr_debug("incompatible file format\n");
return -EINVAL;
}
session->fd = fd;
return 0;
}
......@@ -2772,20 +2728,21 @@ static int perf_evlist__prepare_tracepoint_events(struct perf_evlist *evlist,
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_file_header f_header;
struct perf_file_attr f_attr;
u64 f_id;
int nr_attrs, nr_ids, i, j;
int fd = session->fd;
session->evlist = perf_evlist__new();
if (session->evlist == NULL)
return -ENOMEM;
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)
return -EINVAL;
......@@ -2839,22 +2796,9 @@ int perf_session__read_header(struct perf_session *session, int fd)
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_file_section__process);
lseek(fd, header->data_offset, SEEK_SET);
if (perf_evlist__prepare_tracepoint_events(session->evlist,
session->pevent))
goto out_delete_evlist;
......@@ -2922,7 +2866,8 @@ int perf_event__synthesize_attrs(struct perf_tool *tool,
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)
{
u32 i, ids, n_ids;
......@@ -2961,64 +2906,6 @@ int perf_event__process_attr(union perf_event *event,
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,
struct perf_evlist *evlist,
perf_event__handler_t process)
......@@ -3065,7 +2952,8 @@ int perf_event__synthesize_tracing_data(struct perf_tool *tool, int fd,
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)
{
ssize_t size_read, padding, size = event->tracing_data.size;
......
......@@ -34,6 +34,11 @@ enum {
HEADER_FEAT_BITS = 256,
};
enum perf_header_version {
PERF_HEADER_VERSION_1,
PERF_HEADER_VERSION_2,
};
struct perf_file_section {
u64 offset;
u64 size;
......@@ -45,6 +50,7 @@ struct perf_file_header {
u64 attr_size;
struct perf_file_section attrs;
struct perf_file_section data;
/* event_types is ignored */
struct perf_file_section event_types;
DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS);
};
......@@ -84,28 +90,24 @@ struct perf_session_env {
};
struct perf_header {
bool needs_swap;
s64 attr_offset;
u64 data_offset;
u64 data_size;
u64 event_offset;
u64 event_size;
enum perf_header_version version;
bool needs_swap;
u64 data_offset;
u64 data_size;
u64 feat_offset;
DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS);
struct perf_session_env env;
struct perf_session_env env;
};
struct perf_evlist;
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,
struct perf_evlist *evlist,
int fd, bool at_exit);
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__clear_feat(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,
int perf_event__synthesize_attrs(struct perf_tool *tool,
struct perf_session *session,
perf_event__handler_t process);
int perf_event__process_attr(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__process_attr(struct perf_tool *tool, union perf_event *event,
struct perf_evlist **pevlist);
int perf_event__synthesize_tracing_data(struct perf_tool *tool,
int fd, struct perf_evlist *evlist,
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);
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,
rb_link_node(&he->rb_node_in, parent, p);
rb_insert_color(&he->rb_node_in, root);
hists__inc_nr_entries(hists, he);
he->dummy = true;
}
out:
return he;
......
......@@ -141,10 +141,12 @@ struct perf_hpp {
};
struct perf_hpp_fmt {
int (*header)(struct perf_hpp *hpp);
int (*width)(struct perf_hpp *hpp);
int (*color)(struct perf_hpp *hpp, struct hist_entry *he);
int (*entry)(struct perf_hpp *hpp, struct hist_entry *he);
int (*header)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp);
int (*width)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp);
int (*color)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
struct hist_entry *he);
int (*entry)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
struct hist_entry *he);
struct list_head list;
};
......@@ -157,7 +159,7 @@ extern struct list_head perf_hpp__list;
extern struct perf_hpp_fmt perf_hpp__format[];
enum {
PERF_HPP__BASELINE,
/* Matches perf_hpp__format array. */
PERF_HPP__OVERHEAD,
PERF_HPP__OVERHEAD_SYS,
PERF_HPP__OVERHEAD_US,
......@@ -165,11 +167,6 @@ enum {
PERF_HPP__OVERHEAD_GUEST_US,
PERF_HPP__SAMPLES,
PERF_HPP__PERIOD,
PERF_HPP__PERIOD_BASELINE,
PERF_HPP__DELTA,
PERF_HPP__RATIO,
PERF_HPP__WEIGHTED_DIFF,
PERF_HPP__FORMULA,
PERF_HPP__MAX_INDEX
};
......@@ -177,8 +174,6 @@ enum {
void perf_hpp__init(void);
void perf_hpp__column_register(struct perf_hpp_fmt *format);
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;
......@@ -245,11 +240,4 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist __maybe_unused,
#endif
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 */
#include <string.h>
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)
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)
{
struct rb_node **p = &machine->threads.rb_node;
......@@ -241,23 +241,23 @@ static struct thread *__machine__findnew_thread(struct machine *machine, pid_t p
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
* 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;
while (*p != NULL) {
parent = *p;
th = rb_entry(parent, struct thread, rb_node);
if (th->pid == pid) {
if (th->tid == tid) {
machine->last_match = th;
return th;
}
if (pid < th->pid)
if (tid < th->tid)
p = &(*p)->rb_left;
else
p = &(*p)->rb_right;
......@@ -266,7 +266,7 @@ static struct thread *__machine__findnew_thread(struct machine *machine, pid_t p
if (!create)
return NULL;
th = thread__new(pid);
th = thread__new(tid);
if (th != NULL) {
rb_link_node(&th->rb_node, parent, p);
rb_insert_color(&th->rb_node, &machine->threads);
......@@ -276,14 +276,14 @@ static struct thread *__machine__findnew_thread(struct machine *machine, pid_t p
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)
......@@ -1058,11 +1058,10 @@ int machine__process_event(struct machine *machine, union perf_event *event)
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 0;
}
......@@ -1159,8 +1158,8 @@ struct branch_info *machine__resolve_bstack(struct machine *machine,
static int machine__resolve_callchain_sample(struct machine *machine,
struct thread *thread,
struct ip_callchain *chain,
struct symbol **parent)
struct symbol **parent,
struct addr_location *root_al)
{
u8 cpumode = PERF_RECORD_MISC_USER;
unsigned int i;
......@@ -1211,8 +1210,15 @@ static int machine__resolve_callchain_sample(struct machine *machine,
MAP__FUNCTION, ip, &al, NULL);
if (al.sym != NULL) {
if (sort__has_parent && !*parent &&
symbol__match_parent_regex(al.sym))
symbol__match_regex(al.sym, &parent_regex))
*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)
break;
}
......@@ -1237,15 +1243,13 @@ int machine__resolve_callchain(struct machine *machine,
struct perf_evsel *evsel,
struct thread *thread,
struct perf_sample *sample,
struct symbol **parent)
struct symbol **parent,
struct addr_location *root_al)
{
int ret;
callchain_cursor_reset(&callchain_cursor);
ret = machine__resolve_callchain_sample(machine, thread,
sample->callchain, parent);
sample->callchain, parent, root_al);
if (ret)
return ret;
......
......@@ -5,6 +5,7 @@
#include <linux/rbtree.h>
#include "map.h"
struct addr_location;
struct branch_stack;
struct perf_evsel;
struct perf_sample;
......@@ -36,7 +37,7 @@ struct map *machine__kernel_map(struct machine *machine, enum map_type 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_exit_event(struct machine *machine, union perf_event *event);
......@@ -83,7 +84,8 @@ int machine__resolve_callchain(struct machine *machine,
struct perf_evsel *evsel,
struct thread *thread,
struct perf_sample *sample,
struct symbol **parent);
struct symbol **parent,
struct addr_location *root_al);
/*
* Default guest kernel is defined by parameter --guestkallsyms
......@@ -99,7 +101,7 @@ static inline bool machine__is_host(struct machine *machine)
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);
......
This diff is collapsed.
......@@ -23,6 +23,7 @@ struct tracepoint_path {
};
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);
const char *event_type(int type);
......@@ -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_group(struct list_head *list, char *event_mod);
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);
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,
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);
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);
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);
void parse_events__set_leader(char *name, struct list_head *list);
void parse_events_update_lists(struct list_head *list_event,
......
......@@ -22,6 +22,13 @@ do { \
YYABORT; \
} 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,
struct parse_events_evlist *data)
{
......@@ -196,9 +203,10 @@ event_pmu:
PE_NAME '/' event_config '/'
{
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);
$$ = list;
}
......@@ -212,11 +220,12 @@ event_legacy_symbol:
value_sym '/' event_config '/'
{
struct parse_events_evlist *data = _data;
struct list_head *list = NULL;
struct list_head *list;
int type = $1 >> 16;
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));
parse_events__free_terms($3);
$$ = list;
......@@ -225,11 +234,12 @@ value_sym '/' event_config '/'
value_sym sep_slash_dc
{
struct parse_events_evlist *data = _data;
struct list_head *list = NULL;
struct list_head *list;
int type = $1 >> 16;
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));
$$ = list;
}
......@@ -238,27 +248,30 @@ event_legacy_cache:
PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT '-' PE_NAME_CACHE_OP_RESULT
{
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;
}
|
PE_NAME_CACHE_TYPE '-' PE_NAME_CACHE_OP_RESULT
{
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;
}
|
PE_NAME_CACHE_TYPE
{
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;
}
......@@ -266,9 +279,10 @@ event_legacy_mem:
PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc
{
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));
$$ = list;
}
......@@ -276,9 +290,10 @@ PE_PREFIX_MEM PE_VALUE ':' PE_MODIFIER_BP sep_dc
PE_PREFIX_MEM PE_VALUE sep_dc
{
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));
$$ = list;
}
......@@ -287,9 +302,10 @@ event_legacy_tracepoint:
PE_NAME ':' PE_NAME
{
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;
}
......@@ -297,9 +313,10 @@ event_legacy_numeric:
PE_VALUE ':' PE_VALUE
{
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;
}
......@@ -307,9 +324,10 @@ event_legacy_raw:
PE_RAW
{
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));
$$ = 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