You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge branch 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip
* 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip: (184 commits) perf probe: Clean up probe_point_lazy_walker() return value tracing: Fix irqoff selftest expanding max buffer tracing: Align 4 byte ints together in struct tracer tracing: Export trace_set_clr_event() tracing: Explain about unstable clock on resume with ring buffer warning ftrace/graph: Trace function entry before updating index ftrace: Add .ref.text as one of the safe areas to trace tracing: Adjust conditional expression latency formatting. tracing: Fix event alignment: skb:kfree_skb tracing: Fix event alignment: mce:mce_record tracing: Fix event alignment: kvm:kvm_hv_hypercall tracing: Fix event alignment: module:module_request tracing: Fix event alignment: ftrace:context_switch and ftrace:wakeup tracing: Remove lock_depth from event entry perf header: Stop using 'self' perf session: Use evlist/evsel for managing perf.data attributes perf top: Don't let events to eat up whole header line perf top: Fix events overflow in top command ring-buffer: Remove unused #include <linux/trace_irq.h> tracing: Add an 'overwrite' trace_option. ...
This commit is contained in:
@@ -1,4 +1,3 @@
|
||||
PERF-BUILD-OPTIONS
|
||||
PERF-CFLAGS
|
||||
PERF-GUI-VARS
|
||||
PERF-VERSION-FILE
|
||||
|
||||
@@ -178,8 +178,8 @@ install-pdf: pdf
|
||||
$(INSTALL) -d -m 755 $(DESTDIR)$(pdfdir)
|
||||
$(INSTALL) -m 644 user-manual.pdf $(DESTDIR)$(pdfdir)
|
||||
|
||||
install-html: html
|
||||
'$(SHELL_PATH_SQ)' ./install-webdoc.sh $(DESTDIR)$(htmldir)
|
||||
#install-html: html
|
||||
# '$(SHELL_PATH_SQ)' ./install-webdoc.sh $(DESTDIR)$(htmldir)
|
||||
|
||||
../PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE
|
||||
$(QUIET_SUBDIR0)../ $(QUIET_SUBDIR1) PERF-VERSION-FILE
|
||||
@@ -288,15 +288,16 @@ $(patsubst %.txt,%.html,$(wildcard howto/*.txt)): %.html : %.txt
|
||||
sed -e '1,/^$$/d' $< | $(ASCIIDOC) -b xhtml11 - >$@+ && \
|
||||
mv $@+ $@
|
||||
|
||||
install-webdoc : html
|
||||
'$(SHELL_PATH_SQ)' ./install-webdoc.sh $(WEBDOC_DEST)
|
||||
# UNIMPLEMENTED
|
||||
#install-webdoc : html
|
||||
# '$(SHELL_PATH_SQ)' ./install-webdoc.sh $(WEBDOC_DEST)
|
||||
|
||||
quick-install: quick-install-man
|
||||
# quick-install: quick-install-man
|
||||
|
||||
quick-install-man:
|
||||
'$(SHELL_PATH_SQ)' ./install-doc-quick.sh $(DOC_REF) $(DESTDIR)$(mandir)
|
||||
# quick-install-man:
|
||||
# '$(SHELL_PATH_SQ)' ./install-doc-quick.sh $(DOC_REF) $(DESTDIR)$(mandir)
|
||||
|
||||
quick-install-html:
|
||||
'$(SHELL_PATH_SQ)' ./install-doc-quick.sh $(HTML_REF) $(DESTDIR)$(htmldir)
|
||||
#quick-install-html:
|
||||
# '$(SHELL_PATH_SQ)' ./install-doc-quick.sh $(HTML_REF) $(DESTDIR)$(htmldir)
|
||||
|
||||
.PHONY: .FORCE-PERF-VERSION-FILE
|
||||
|
||||
@@ -8,7 +8,7 @@ perf-list - List all symbolic event types
|
||||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
'perf list'
|
||||
'perf list' [hw|sw|cache|tracepoint|event_glob]
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
@@ -63,7 +63,26 @@ details. Some of them are referenced in the SEE ALSO section below.
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
None
|
||||
|
||||
Without options all known events will be listed.
|
||||
|
||||
To limit the list use:
|
||||
|
||||
. 'hw' or 'hardware' to list hardware events such as cache-misses, etc.
|
||||
|
||||
. 'sw' or 'software' to list software events such as context switches, etc.
|
||||
|
||||
. 'cache' or 'hwcache' to list hardware cache events such as L1-dcache-loads, etc.
|
||||
|
||||
. 'tracepoint' to list all tracepoint events, alternatively use
|
||||
'subsys_glob:event_glob' to filter by tracepoint subsystems such as sched,
|
||||
block, etc.
|
||||
|
||||
. If none of the above is matched, it will apply the supplied glob to all
|
||||
events, printing the ones that match.
|
||||
|
||||
One or more types can be used at the same time, listing the events for the
|
||||
types specified.
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
|
||||
@@ -24,8 +24,8 @@ and statistics with this 'perf lock' command.
|
||||
|
||||
'perf lock report' reports statistical data.
|
||||
|
||||
OPTIONS
|
||||
-------
|
||||
COMMON OPTIONS
|
||||
--------------
|
||||
|
||||
-i::
|
||||
--input=<file>::
|
||||
@@ -39,6 +39,14 @@ OPTIONS
|
||||
--dump-raw-trace::
|
||||
Dump raw trace in ASCII.
|
||||
|
||||
REPORT OPTIONS
|
||||
--------------
|
||||
|
||||
-k::
|
||||
--key=<value>::
|
||||
Sorting key. Possible values: acquired (default), contended,
|
||||
wait_total, wait_max, wait_min.
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
linkperf:perf[1]
|
||||
|
||||
@@ -16,7 +16,7 @@ or
|
||||
or
|
||||
'perf probe' --list
|
||||
or
|
||||
'perf probe' [options] --line='FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]'
|
||||
'perf probe' [options] --line='LINE'
|
||||
or
|
||||
'perf probe' [options] --vars='PROBEPOINT'
|
||||
|
||||
@@ -73,6 +73,17 @@ OPTIONS
|
||||
(Only for --vars) Show external defined variables in addition to local
|
||||
variables.
|
||||
|
||||
-F::
|
||||
--funcs::
|
||||
Show available functions in given module or kernel.
|
||||
|
||||
--filter=FILTER::
|
||||
(Only for --vars and --funcs) Set filter. FILTER is a combination of glob
|
||||
pattern, see FILTER PATTERN for detail.
|
||||
Default FILTER is "!__k???tab_* & !__crc_*" for --vars, and "!_*"
|
||||
for --funcs.
|
||||
If several filters are specified, only the last filter is used.
|
||||
|
||||
-f::
|
||||
--force::
|
||||
Forcibly add events with existing name.
|
||||
@@ -117,13 +128,14 @@ LINE SYNTAX
|
||||
-----------
|
||||
Line range is described by following syntax.
|
||||
|
||||
"FUNC[:RLN[+NUM|-RLN2]]|SRC[:ALN[+NUM|-ALN2]]"
|
||||
"FUNC[@SRC][:RLN[+NUM|-RLN2]]|SRC[:ALN[+NUM|-ALN2]]"
|
||||
|
||||
FUNC specifies the function name of showing lines. 'RLN' is the start line
|
||||
number from function entry line, and 'RLN2' is the end line number. As same as
|
||||
probe syntax, 'SRC' means the source file path, 'ALN' is start line number,
|
||||
and 'ALN2' is end line number in the file. It is also possible to specify how
|
||||
many lines to show by using 'NUM'.
|
||||
many lines to show by using 'NUM'. Moreover, 'FUNC@SRC' combination is good
|
||||
for searching a specific function when several functions share same name.
|
||||
So, "source.c:100-120" shows lines between 100th to l20th in source.c file. And "func:10+20" shows 20 lines from 10th line of func function.
|
||||
|
||||
LAZY MATCHING
|
||||
@@ -135,6 +147,14 @@ e.g.
|
||||
|
||||
This provides some sort of flexibility and robustness to probe point definitions against minor code changes. For example, actual 10th line of schedule() can be moved easily by modifying schedule(), but the same line matching 'rq=cpu_rq*' may still exist in the function.)
|
||||
|
||||
FILTER PATTERN
|
||||
--------------
|
||||
The filter pattern is a glob matching pattern(s) to filter variables.
|
||||
In addition, you can use "!" for specifying filter-out rule. You also can give several rules combined with "&" or "|", and fold those rules as one rule by using "(" ")".
|
||||
|
||||
e.g.
|
||||
With --filter "foo* | bar*", perf probe -V shows variables which start with "foo" or "bar".
|
||||
With --filter "!foo* & *bar", perf probe -V shows variables which don't start with "foo" and end with "bar", like "fizzbar". But "foobar" is filtered out.
|
||||
|
||||
EXAMPLES
|
||||
--------
|
||||
|
||||
@@ -137,6 +137,17 @@ Do not update the builid cache. This saves some overhead in situations
|
||||
where the information in the perf.data file (which includes buildids)
|
||||
is sufficient.
|
||||
|
||||
-G name,...::
|
||||
--cgroup name,...::
|
||||
monitor only in the container (cgroup) called "name". This option is available only
|
||||
in per-cpu mode. The cgroup filesystem must be mounted. All threads belonging to
|
||||
container "name" are monitored when they run on the monitored CPUs. Multiple cgroups
|
||||
can be provided. Each cgroup is applied to the corresponding event, i.e., first cgroup
|
||||
to first event, second cgroup to second event and so on. It is possible to provide
|
||||
an empty cgroup (monitor all the time) using, e.g., -G foo,,bar. Cgroups must have
|
||||
corresponding events, i.e., they always refer to events defined earlier on the command
|
||||
line.
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
linkperf:perf-stat[1], linkperf:perf-list[1]
|
||||
|
||||
@@ -83,6 +83,17 @@ This option is only valid in system-wide mode.
|
||||
print counts using a CSV-style output to make it easy to import directly into
|
||||
spreadsheets. Columns are separated by the string specified in SEP.
|
||||
|
||||
-G name::
|
||||
--cgroup name::
|
||||
monitor only in the container (cgroup) called "name". This option is available only
|
||||
in per-cpu mode. The cgroup filesystem must be mounted. All threads belonging to
|
||||
container "name" are monitored when they run on the monitored CPUs. Multiple cgroups
|
||||
can be provided. Each cgroup is applied to the corresponding event, i.e., first cgroup
|
||||
to first event, second cgroup to second event and so on. It is possible to provide
|
||||
an empty cgroup (monitor all the time) using, e.g., -G foo,,bar. Cgroups must have
|
||||
corresponding events, i.e., they always refer to events defined earlier on the command
|
||||
line.
|
||||
|
||||
EXAMPLES
|
||||
--------
|
||||
|
||||
|
||||
+89
-560
File diff suppressed because it is too large
Load Diff
@@ -55,7 +55,7 @@ int bench_sched_pipe(int argc, const char **argv,
|
||||
* discarding returned value of read(), write()
|
||||
* causes error in building environment for perf
|
||||
*/
|
||||
int ret, wait_stat;
|
||||
int __used ret, wait_stat;
|
||||
pid_t pid, retpid;
|
||||
|
||||
argc = parse_options(argc, argv, options,
|
||||
|
||||
+88
-263
@@ -9,6 +9,7 @@
|
||||
|
||||
#include "util/util.h"
|
||||
|
||||
#include "util/util.h"
|
||||
#include "util/color.h"
|
||||
#include <linux/list.h>
|
||||
#include "util/cache.h"
|
||||
@@ -18,6 +19,9 @@
|
||||
#include "perf.h"
|
||||
#include "util/debug.h"
|
||||
|
||||
#include "util/evlist.h"
|
||||
#include "util/evsel.h"
|
||||
#include "util/annotate.h"
|
||||
#include "util/event.h"
|
||||
#include "util/parse-options.h"
|
||||
#include "util/parse-events.h"
|
||||
@@ -36,9 +40,13 @@ static bool print_line;
|
||||
|
||||
static const char *sym_hist_filter;
|
||||
|
||||
static int hists__add_entry(struct hists *self, struct addr_location *al)
|
||||
static int perf_evlist__add_sample(struct perf_evlist *evlist,
|
||||
struct perf_sample *sample,
|
||||
struct addr_location *al)
|
||||
{
|
||||
struct perf_evsel *evsel;
|
||||
struct hist_entry *he;
|
||||
int ret;
|
||||
|
||||
if (sym_hist_filter != NULL &&
|
||||
(al->sym == NULL || strcmp(sym_hist_filter, al->sym->name) != 0)) {
|
||||
@@ -51,25 +59,51 @@ static int hists__add_entry(struct hists *self, struct addr_location *al)
|
||||
return 0;
|
||||
}
|
||||
|
||||
he = __hists__add_entry(self, al, NULL, 1);
|
||||
evsel = perf_evlist__id2evsel(evlist, sample->id);
|
||||
if (evsel == NULL) {
|
||||
/*
|
||||
* FIXME: Propagate this back, but at least we're in a builtin,
|
||||
* where exit() is allowed. ;-)
|
||||
*/
|
||||
ui__warning("Invalid %s file, contains samples with id not in "
|
||||
"its header!\n", input_name);
|
||||
exit_browser(0);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
he = __hists__add_entry(&evsel->hists, al, NULL, 1);
|
||||
if (he == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
return hist_entry__inc_addr_samples(he, al->addr);
|
||||
ret = 0;
|
||||
if (he->ms.sym != NULL) {
|
||||
struct annotation *notes = symbol__annotation(he->ms.sym);
|
||||
if (notes->src == NULL &&
|
||||
symbol__alloc_hist(he->ms.sym, evlist->nr_entries) < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
|
||||
}
|
||||
|
||||
evsel->hists.stats.total_period += sample->period;
|
||||
hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int process_sample_event(event_t *event, struct sample_data *sample,
|
||||
static int process_sample_event(union perf_event *event,
|
||||
struct perf_sample *sample,
|
||||
struct perf_session *session)
|
||||
{
|
||||
struct addr_location al;
|
||||
|
||||
if (event__preprocess_sample(event, session, &al, sample, NULL) < 0) {
|
||||
if (perf_event__preprocess_sample(event, session, &al, sample,
|
||||
symbol__annotate_init) < 0) {
|
||||
pr_warning("problem processing %d event, skipping it.\n",
|
||||
event->header.type);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!al.filtered && hists__add_entry(&session->hists, &al)) {
|
||||
if (!al.filtered && perf_evlist__add_sample(session->evlist, sample, &al)) {
|
||||
pr_warning("problem incrementing symbol count, "
|
||||
"skipping event\n");
|
||||
return -1;
|
||||
@@ -78,261 +112,26 @@ static int process_sample_event(event_t *event, struct sample_data *sample,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int objdump_line__print(struct objdump_line *self,
|
||||
struct list_head *head,
|
||||
struct hist_entry *he, u64 len)
|
||||
static int hist_entry__tty_annotate(struct hist_entry *he, int evidx)
|
||||
{
|
||||
struct symbol *sym = he->ms.sym;
|
||||
static const char *prev_line;
|
||||
static const char *prev_color;
|
||||
|
||||
if (self->offset != -1) {
|
||||
const char *path = NULL;
|
||||
unsigned int hits = 0;
|
||||
double percent = 0.0;
|
||||
const char *color;
|
||||
struct sym_priv *priv = symbol__priv(sym);
|
||||
struct sym_ext *sym_ext = priv->ext;
|
||||
struct sym_hist *h = priv->hist;
|
||||
s64 offset = self->offset;
|
||||
struct objdump_line *next = objdump__get_next_ip_line(head, self);
|
||||
|
||||
while (offset < (s64)len &&
|
||||
(next == NULL || offset < next->offset)) {
|
||||
if (sym_ext) {
|
||||
if (path == NULL)
|
||||
path = sym_ext[offset].path;
|
||||
percent += sym_ext[offset].percent;
|
||||
} else
|
||||
hits += h->ip[offset];
|
||||
|
||||
++offset;
|
||||
}
|
||||
|
||||
if (sym_ext == NULL && h->sum)
|
||||
percent = 100.0 * hits / h->sum;
|
||||
|
||||
color = get_percent_color(percent);
|
||||
|
||||
/*
|
||||
* Also color the filename and line if needed, with
|
||||
* the same color than the percentage. Don't print it
|
||||
* twice for close colored ip with the same filename:line
|
||||
*/
|
||||
if (path) {
|
||||
if (!prev_line || strcmp(prev_line, path)
|
||||
|| color != prev_color) {
|
||||
color_fprintf(stdout, color, " %s", path);
|
||||
prev_line = path;
|
||||
prev_color = color;
|
||||
}
|
||||
}
|
||||
|
||||
color_fprintf(stdout, color, " %7.2f", percent);
|
||||
printf(" : ");
|
||||
color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", self->line);
|
||||
} else {
|
||||
if (!*self->line)
|
||||
printf(" :\n");
|
||||
else
|
||||
printf(" : %s\n", self->line);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return symbol__tty_annotate(he->ms.sym, he->ms.map, evidx,
|
||||
print_line, full_paths, 0, 0);
|
||||
}
|
||||
|
||||
static struct rb_root root_sym_ext;
|
||||
|
||||
static void insert_source_line(struct sym_ext *sym_ext)
|
||||
{
|
||||
struct sym_ext *iter;
|
||||
struct rb_node **p = &root_sym_ext.rb_node;
|
||||
struct rb_node *parent = NULL;
|
||||
|
||||
while (*p != NULL) {
|
||||
parent = *p;
|
||||
iter = rb_entry(parent, struct sym_ext, node);
|
||||
|
||||
if (sym_ext->percent > iter->percent)
|
||||
p = &(*p)->rb_left;
|
||||
else
|
||||
p = &(*p)->rb_right;
|
||||
}
|
||||
|
||||
rb_link_node(&sym_ext->node, parent, p);
|
||||
rb_insert_color(&sym_ext->node, &root_sym_ext);
|
||||
}
|
||||
|
||||
static void free_source_line(struct hist_entry *he, int len)
|
||||
{
|
||||
struct sym_priv *priv = symbol__priv(he->ms.sym);
|
||||
struct sym_ext *sym_ext = priv->ext;
|
||||
int i;
|
||||
|
||||
if (!sym_ext)
|
||||
return;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
free(sym_ext[i].path);
|
||||
free(sym_ext);
|
||||
|
||||
priv->ext = NULL;
|
||||
root_sym_ext = RB_ROOT;
|
||||
}
|
||||
|
||||
/* Get the filename:line for the colored entries */
|
||||
static void
|
||||
get_source_line(struct hist_entry *he, int len, const char *filename)
|
||||
{
|
||||
struct symbol *sym = he->ms.sym;
|
||||
u64 start;
|
||||
int i;
|
||||
char cmd[PATH_MAX * 2];
|
||||
struct sym_ext *sym_ext;
|
||||
struct sym_priv *priv = symbol__priv(sym);
|
||||
struct sym_hist *h = priv->hist;
|
||||
|
||||
if (!h->sum)
|
||||
return;
|
||||
|
||||
sym_ext = priv->ext = calloc(len, sizeof(struct sym_ext));
|
||||
if (!priv->ext)
|
||||
return;
|
||||
|
||||
start = he->ms.map->unmap_ip(he->ms.map, sym->start);
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
char *path = NULL;
|
||||
size_t line_len;
|
||||
u64 offset;
|
||||
FILE *fp;
|
||||
|
||||
sym_ext[i].percent = 100.0 * h->ip[i] / h->sum;
|
||||
if (sym_ext[i].percent <= 0.5)
|
||||
continue;
|
||||
|
||||
offset = start + i;
|
||||
sprintf(cmd, "addr2line -e %s %016" PRIx64, filename, offset);
|
||||
fp = popen(cmd, "r");
|
||||
if (!fp)
|
||||
continue;
|
||||
|
||||
if (getline(&path, &line_len, fp) < 0 || !line_len)
|
||||
goto next;
|
||||
|
||||
sym_ext[i].path = malloc(sizeof(char) * line_len + 1);
|
||||
if (!sym_ext[i].path)
|
||||
goto next;
|
||||
|
||||
strcpy(sym_ext[i].path, path);
|
||||
insert_source_line(&sym_ext[i]);
|
||||
|
||||
next:
|
||||
pclose(fp);
|
||||
}
|
||||
}
|
||||
|
||||
static void print_summary(const char *filename)
|
||||
{
|
||||
struct sym_ext *sym_ext;
|
||||
struct rb_node *node;
|
||||
|
||||
printf("\nSorted summary for file %s\n", filename);
|
||||
printf("----------------------------------------------\n\n");
|
||||
|
||||
if (RB_EMPTY_ROOT(&root_sym_ext)) {
|
||||
printf(" Nothing higher than %1.1f%%\n", MIN_GREEN);
|
||||
return;
|
||||
}
|
||||
|
||||
node = rb_first(&root_sym_ext);
|
||||
while (node) {
|
||||
double percent;
|
||||
const char *color;
|
||||
char *path;
|
||||
|
||||
sym_ext = rb_entry(node, struct sym_ext, node);
|
||||
percent = sym_ext->percent;
|
||||
color = get_percent_color(percent);
|
||||
path = sym_ext->path;
|
||||
|
||||
color_fprintf(stdout, color, " %7.2f %s", percent, path);
|
||||
node = rb_next(node);
|
||||
}
|
||||
}
|
||||
|
||||
static void hist_entry__print_hits(struct hist_entry *self)
|
||||
{
|
||||
struct symbol *sym = self->ms.sym;
|
||||
struct sym_priv *priv = symbol__priv(sym);
|
||||
struct sym_hist *h = priv->hist;
|
||||
u64 len = sym->end - sym->start, offset;
|
||||
|
||||
for (offset = 0; offset < len; ++offset)
|
||||
if (h->ip[offset] != 0)
|
||||
printf("%*" PRIx64 ": %" PRIu64 "\n", BITS_PER_LONG / 2,
|
||||
sym->start + offset, h->ip[offset]);
|
||||
printf("%*s: %" PRIu64 "\n", BITS_PER_LONG / 2, "h->sum", h->sum);
|
||||
}
|
||||
|
||||
static int hist_entry__tty_annotate(struct hist_entry *he)
|
||||
{
|
||||
struct map *map = he->ms.map;
|
||||
struct dso *dso = map->dso;
|
||||
struct symbol *sym = he->ms.sym;
|
||||
const char *filename = dso->long_name, *d_filename;
|
||||
u64 len;
|
||||
LIST_HEAD(head);
|
||||
struct objdump_line *pos, *n;
|
||||
|
||||
if (hist_entry__annotate(he, &head, 0) < 0)
|
||||
return -1;
|
||||
|
||||
if (full_paths)
|
||||
d_filename = filename;
|
||||
else
|
||||
d_filename = basename(filename);
|
||||
|
||||
len = sym->end - sym->start;
|
||||
|
||||
if (print_line) {
|
||||
get_source_line(he, len, filename);
|
||||
print_summary(filename);
|
||||
}
|
||||
|
||||
printf("\n\n------------------------------------------------\n");
|
||||
printf(" Percent | Source code & Disassembly of %s\n", d_filename);
|
||||
printf("------------------------------------------------\n");
|
||||
|
||||
if (verbose)
|
||||
hist_entry__print_hits(he);
|
||||
|
||||
list_for_each_entry_safe(pos, n, &head, node) {
|
||||
objdump_line__print(pos, &head, he, len);
|
||||
list_del(&pos->node);
|
||||
objdump_line__free(pos);
|
||||
}
|
||||
|
||||
if (print_line)
|
||||
free_source_line(he, len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void hists__find_annotations(struct hists *self)
|
||||
static void hists__find_annotations(struct hists *self, int evidx)
|
||||
{
|
||||
struct rb_node *nd = rb_first(&self->entries), *next;
|
||||
int key = KEY_RIGHT;
|
||||
|
||||
while (nd) {
|
||||
struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
|
||||
struct sym_priv *priv;
|
||||
struct annotation *notes;
|
||||
|
||||
if (he->ms.sym == NULL || he->ms.map->dso->annotate_warned)
|
||||
goto find_next;
|
||||
|
||||
priv = symbol__priv(he->ms.sym);
|
||||
if (priv->hist == NULL) {
|
||||
notes = symbol__annotation(he->ms.sym);
|
||||
if (notes->src == NULL) {
|
||||
find_next:
|
||||
if (key == KEY_LEFT)
|
||||
nd = rb_prev(nd);
|
||||
@@ -342,7 +141,7 @@ find_next:
|
||||
}
|
||||
|
||||
if (use_browser > 0) {
|
||||
key = hist_entry__tui_annotate(he);
|
||||
key = hist_entry__tui_annotate(he, evidx);
|
||||
switch (key) {
|
||||
case KEY_RIGHT:
|
||||
next = rb_next(nd);
|
||||
@@ -357,24 +156,24 @@ find_next:
|
||||
if (next != NULL)
|
||||
nd = next;
|
||||
} else {
|
||||
hist_entry__tty_annotate(he);
|
||||
hist_entry__tty_annotate(he, evidx);
|
||||
nd = rb_next(nd);
|
||||
/*
|
||||
* Since we have a hist_entry per IP for the same
|
||||
* symbol, free he->ms.sym->hist to signal we already
|
||||
* symbol, free he->ms.sym->src to signal we already
|
||||
* processed this symbol.
|
||||
*/
|
||||
free(priv->hist);
|
||||
priv->hist = NULL;
|
||||
free(notes->src);
|
||||
notes->src = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static struct perf_event_ops event_ops = {
|
||||
.sample = process_sample_event,
|
||||
.mmap = event__process_mmap,
|
||||
.comm = event__process_comm,
|
||||
.fork = event__process_task,
|
||||
.mmap = perf_event__process_mmap,
|
||||
.comm = perf_event__process_comm,
|
||||
.fork = perf_event__process_task,
|
||||
.ordered_samples = true,
|
||||
.ordering_requires_timestamps = true,
|
||||
};
|
||||
@@ -383,6 +182,8 @@ static int __cmd_annotate(void)
|
||||
{
|
||||
int ret;
|
||||
struct perf_session *session;
|
||||
struct perf_evsel *pos;
|
||||
u64 total_nr_samples;
|
||||
|
||||
session = perf_session__new(input_name, O_RDONLY, force, false, &event_ops);
|
||||
if (session == NULL)
|
||||
@@ -403,12 +204,36 @@ static int __cmd_annotate(void)
|
||||
if (verbose > 2)
|
||||
perf_session__fprintf_dsos(session, stdout);
|
||||
|
||||
hists__collapse_resort(&session->hists);
|
||||
hists__output_resort(&session->hists);
|
||||
hists__find_annotations(&session->hists);
|
||||
out_delete:
|
||||
perf_session__delete(session);
|
||||
total_nr_samples = 0;
|
||||
list_for_each_entry(pos, &session->evlist->entries, node) {
|
||||
struct hists *hists = &pos->hists;
|
||||
u32 nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
|
||||
|
||||
if (nr_samples > 0) {
|
||||
total_nr_samples += nr_samples;
|
||||
hists__collapse_resort(hists);
|
||||
hists__output_resort(hists);
|
||||
hists__find_annotations(hists, pos->idx);
|
||||
}
|
||||
}
|
||||
|
||||
if (total_nr_samples == 0) {
|
||||
ui__warning("The %s file has no samples!\n", input_name);
|
||||
goto out_delete;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -451,9 +276,9 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __used)
|
||||
else if (use_tui)
|
||||
use_browser = 1;
|
||||
|
||||
setup_browser();
|
||||
setup_browser(true);
|
||||
|
||||
symbol_conf.priv_size = sizeof(struct sym_priv);
|
||||
symbol_conf.priv_size = sizeof(struct annotation);
|
||||
symbol_conf.try_vmlinux_path = true;
|
||||
|
||||
if (symbol__init() < 0)
|
||||
|
||||
@@ -30,13 +30,13 @@ static int hists__add_entry(struct hists *self,
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static int diff__process_sample_event(event_t *event,
|
||||
struct sample_data *sample,
|
||||
static int diff__process_sample_event(union perf_event *event,
|
||||
struct perf_sample *sample,
|
||||
struct perf_session *session)
|
||||
{
|
||||
struct addr_location al;
|
||||
|
||||
if (event__preprocess_sample(event, session, &al, sample, NULL) < 0) {
|
||||
if (perf_event__preprocess_sample(event, session, &al, sample, NULL) < 0) {
|
||||
pr_warning("problem processing %d event, skipping it.\n",
|
||||
event->header.type);
|
||||
return -1;
|
||||
@@ -56,11 +56,11 @@ static int diff__process_sample_event(event_t *event,
|
||||
|
||||
static struct perf_event_ops event_ops = {
|
||||
.sample = diff__process_sample_event,
|
||||
.mmap = event__process_mmap,
|
||||
.comm = event__process_comm,
|
||||
.exit = event__process_task,
|
||||
.fork = event__process_task,
|
||||
.lost = event__process_lost,
|
||||
.mmap = perf_event__process_mmap,
|
||||
.comm = perf_event__process_comm,
|
||||
.exit = perf_event__process_task,
|
||||
.fork = perf_event__process_task,
|
||||
.lost = perf_event__process_lost,
|
||||
.ordered_samples = true,
|
||||
.ordering_requires_timestamps = true,
|
||||
};
|
||||
|
||||
+43
-39
@@ -16,8 +16,8 @@
|
||||
static char const *input_name = "-";
|
||||
static bool inject_build_ids;
|
||||
|
||||
static int event__repipe_synth(event_t *event,
|
||||
struct perf_session *session __used)
|
||||
static int perf_event__repipe_synth(union perf_event *event,
|
||||
struct perf_session *session __used)
|
||||
{
|
||||
uint32_t size;
|
||||
void *buf = event;
|
||||
@@ -36,41 +36,44 @@ static int event__repipe_synth(event_t *event,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int event__repipe(event_t *event, struct sample_data *sample __used,
|
||||
struct perf_session *session)
|
||||
static int perf_event__repipe(union perf_event *event,
|
||||
struct perf_sample *sample __used,
|
||||
struct perf_session *session)
|
||||
{
|
||||
return event__repipe_synth(event, session);
|
||||
return perf_event__repipe_synth(event, session);
|
||||
}
|
||||
|
||||
static int event__repipe_mmap(event_t *self, struct sample_data *sample,
|
||||
struct perf_session *session)
|
||||
static int perf_event__repipe_mmap(union perf_event *event,
|
||||
struct perf_sample *sample,
|
||||
struct perf_session *session)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = event__process_mmap(self, sample, session);
|
||||
event__repipe(self, sample, session);
|
||||
err = perf_event__process_mmap(event, sample, session);
|
||||
perf_event__repipe(event, sample, session);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int event__repipe_task(event_t *self, struct sample_data *sample,
|
||||
struct perf_session *session)
|
||||
static int perf_event__repipe_task(union perf_event *event,
|
||||
struct perf_sample *sample,
|
||||
struct perf_session *session)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = event__process_task(self, sample, session);
|
||||
event__repipe(self, sample, session);
|
||||
err = perf_event__process_task(event, sample, session);
|
||||
perf_event__repipe(event, sample, session);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int event__repipe_tracing_data(event_t *self,
|
||||
struct perf_session *session)
|
||||
static int perf_event__repipe_tracing_data(union perf_event *event,
|
||||
struct perf_session *session)
|
||||
{
|
||||
int err;
|
||||
|
||||
event__repipe_synth(self, session);
|
||||
err = event__process_tracing_data(self, session);
|
||||
perf_event__repipe_synth(event, session);
|
||||
err = perf_event__process_tracing_data(event, session);
|
||||
|
||||
return err;
|
||||
}
|
||||
@@ -109,8 +112,8 @@ static int dso__inject_build_id(struct dso *self, struct perf_session *session)
|
||||
if (self->kernel)
|
||||
misc = PERF_RECORD_MISC_KERNEL;
|
||||
|
||||
err = event__synthesize_build_id(self, misc, event__repipe,
|
||||
machine, session);
|
||||
err = perf_event__synthesize_build_id(self, misc, perf_event__repipe,
|
||||
machine, session);
|
||||
if (err) {
|
||||
pr_err("Can't synthesize build_id event for %s\n", self->long_name);
|
||||
return -1;
|
||||
@@ -119,8 +122,9 @@ static int dso__inject_build_id(struct dso *self, struct perf_session *session)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int event__inject_buildid(event_t *event, struct sample_data *sample,
|
||||
struct perf_session *session)
|
||||
static int perf_event__inject_buildid(union perf_event *event,
|
||||
struct perf_sample *sample,
|
||||
struct perf_session *session)
|
||||
{
|
||||
struct addr_location al;
|
||||
struct thread *thread;
|
||||
@@ -155,24 +159,24 @@ static int event__inject_buildid(event_t *event, struct sample_data *sample,
|
||||
}
|
||||
|
||||
repipe:
|
||||
event__repipe(event, sample, session);
|
||||
perf_event__repipe(event, sample, session);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct perf_event_ops inject_ops = {
|
||||
.sample = event__repipe,
|
||||
.mmap = event__repipe,
|
||||
.comm = event__repipe,
|
||||
.fork = event__repipe,
|
||||
.exit = event__repipe,
|
||||
.lost = event__repipe,
|
||||
.read = event__repipe,
|
||||
.throttle = event__repipe,
|
||||
.unthrottle = event__repipe,
|
||||
.attr = event__repipe_synth,
|
||||
.event_type = event__repipe_synth,
|
||||
.tracing_data = event__repipe_synth,
|
||||
.build_id = event__repipe_synth,
|
||||
.sample = perf_event__repipe,
|
||||
.mmap = perf_event__repipe,
|
||||
.comm = perf_event__repipe,
|
||||
.fork = perf_event__repipe,
|
||||
.exit = perf_event__repipe,
|
||||
.lost = perf_event__repipe,
|
||||
.read = perf_event__repipe,
|
||||
.throttle = perf_event__repipe,
|
||||
.unthrottle = perf_event__repipe,
|
||||
.attr = perf_event__repipe_synth,
|
||||
.event_type = perf_event__repipe_synth,
|
||||
.tracing_data = perf_event__repipe_synth,
|
||||
.build_id = perf_event__repipe_synth,
|
||||
};
|
||||
|
||||
extern volatile int session_done;
|
||||
@@ -190,10 +194,10 @@ static int __cmd_inject(void)
|
||||
signal(SIGINT, sig_handler);
|
||||
|
||||
if (inject_build_ids) {
|
||||
inject_ops.sample = event__inject_buildid;
|
||||
inject_ops.mmap = event__repipe_mmap;
|
||||
inject_ops.fork = event__repipe_task;
|
||||
inject_ops.tracing_data = event__repipe_tracing_data;
|
||||
inject_ops.sample = perf_event__inject_buildid;
|
||||
inject_ops.mmap = perf_event__repipe_mmap;
|
||||
inject_ops.fork = perf_event__repipe_task;
|
||||
inject_ops.tracing_data = perf_event__repipe_tracing_data;
|
||||
}
|
||||
|
||||
session = perf_session__new(input_name, O_RDONLY, false, true, &inject_ops);
|
||||
|
||||
@@ -275,9 +275,8 @@ static void process_free_event(void *data,
|
||||
s_alloc->alloc_cpu = -1;
|
||||
}
|
||||
|
||||
static void
|
||||
process_raw_event(event_t *raw_event __used, void *data,
|
||||
int cpu, u64 timestamp, struct thread *thread)
|
||||
static void process_raw_event(union perf_event *raw_event __used, void *data,
|
||||
int cpu, u64 timestamp, struct thread *thread)
|
||||
{
|
||||
struct event *event;
|
||||
int type;
|
||||
@@ -304,7 +303,8 @@ process_raw_event(event_t *raw_event __used, void *data,
|
||||
}
|
||||
}
|
||||
|
||||
static int process_sample_event(event_t *event, struct sample_data *sample,
|
||||
static int process_sample_event(union perf_event *event,
|
||||
struct perf_sample *sample,
|
||||
struct perf_session *session)
|
||||
{
|
||||
struct thread *thread = perf_session__findnew(session, event->ip.pid);
|
||||
@@ -325,7 +325,7 @@ static int process_sample_event(event_t *event, struct sample_data *sample,
|
||||
|
||||
static struct perf_event_ops event_ops = {
|
||||
.sample = process_sample_event,
|
||||
.comm = event__process_comm,
|
||||
.comm = perf_event__process_comm,
|
||||
.ordered_samples = true,
|
||||
};
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
*
|
||||
* Copyright (C) 2009, Thomas Gleixner <tglx@linutronix.de>
|
||||
* Copyright (C) 2008-2009, Red Hat Inc, Ingo Molnar <mingo@redhat.com>
|
||||
* Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
|
||||
*/
|
||||
#include "builtin.h"
|
||||
|
||||
@@ -13,9 +14,47 @@
|
||||
#include "util/parse-events.h"
|
||||
#include "util/cache.h"
|
||||
|
||||
int cmd_list(int argc __used, const char **argv __used, const char *prefix __used)
|
||||
int cmd_list(int argc, const char **argv, const char *prefix __used)
|
||||
{
|
||||
setup_pager();
|
||||
print_events();
|
||||
|
||||
if (argc == 1)
|
||||
print_events(NULL);
|
||||
else {
|
||||
int i;
|
||||
|
||||
for (i = 1; i < argc; ++i) {
|
||||
if (i > 1)
|
||||
putchar('\n');
|
||||
if (strncmp(argv[i], "tracepoint", 10) == 0)
|
||||
print_tracepoint_events(NULL, NULL);
|
||||
else if (strcmp(argv[i], "hw") == 0 ||
|
||||
strcmp(argv[i], "hardware") == 0)
|
||||
print_events_type(PERF_TYPE_HARDWARE);
|
||||
else if (strcmp(argv[i], "sw") == 0 ||
|
||||
strcmp(argv[i], "software") == 0)
|
||||
print_events_type(PERF_TYPE_SOFTWARE);
|
||||
else if (strcmp(argv[i], "cache") == 0 ||
|
||||
strcmp(argv[i], "hwcache") == 0)
|
||||
print_hwcache_events(NULL);
|
||||
else {
|
||||
char *sep = strchr(argv[i], ':'), *s;
|
||||
int sep_idx;
|
||||
|
||||
if (sep == NULL) {
|
||||
print_events(argv[i]);
|
||||
continue;
|
||||
}
|
||||
sep_idx = sep - argv[i];
|
||||
s = strdup(argv[i]);
|
||||
if (s == NULL)
|
||||
return -1;
|
||||
|
||||
s[sep_idx] = '\0';
|
||||
print_tracepoint_events(s, s + sep_idx + 1);
|
||||
free(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -834,14 +834,14 @@ static void dump_info(void)
|
||||
die("Unknown type of information\n");
|
||||
}
|
||||
|
||||
static int process_sample_event(event_t *self, struct sample_data *sample,
|
||||
static int process_sample_event(union perf_event *event, struct perf_sample *sample,
|
||||
struct perf_session *s)
|
||||
{
|
||||
struct thread *thread = perf_session__findnew(s, sample->tid);
|
||||
|
||||
if (thread == NULL) {
|
||||
pr_debug("problem processing %d event, skipping it.\n",
|
||||
self->header.type);
|
||||
event->header.type);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -852,7 +852,7 @@ static int process_sample_event(event_t *self, struct sample_data *sample,
|
||||
|
||||
static struct perf_event_ops eops = {
|
||||
.sample = process_sample_event,
|
||||
.comm = event__process_comm,
|
||||
.comm = perf_event__process_comm,
|
||||
.ordered_samples = true,
|
||||
};
|
||||
|
||||
@@ -893,7 +893,7 @@ static const char * const report_usage[] = {
|
||||
|
||||
static const struct option report_options[] = {
|
||||
OPT_STRING('k', "key", &sort_key, "acquired",
|
||||
"key for sorting"),
|
||||
"key for sorting (acquired / contended / wait_total / wait_max / wait_min)"),
|
||||
/* TODO: type */
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include "builtin.h"
|
||||
#include "util/util.h"
|
||||
#include "util/strlist.h"
|
||||
#include "util/strfilter.h"
|
||||
#include "util/symbol.h"
|
||||
#include "util/debug.h"
|
||||
#include "util/debugfs.h"
|
||||
@@ -43,6 +44,8 @@
|
||||
#include "util/probe-finder.h"
|
||||
#include "util/probe-event.h"
|
||||
|
||||
#define DEFAULT_VAR_FILTER "!__k???tab_* & !__crc_*"
|
||||
#define DEFAULT_FUNC_FILTER "!_*"
|
||||
#define MAX_PATH_LEN 256
|
||||
|
||||
/* Session management structure */
|
||||
@@ -52,6 +55,7 @@ static struct {
|
||||
bool show_lines;
|
||||
bool show_vars;
|
||||
bool show_ext_vars;
|
||||
bool show_funcs;
|
||||
bool mod_events;
|
||||
int nevents;
|
||||
struct perf_probe_event events[MAX_PROBES];
|
||||
@@ -59,6 +63,7 @@ static struct {
|
||||
struct line_range line_range;
|
||||
const char *target_module;
|
||||
int max_probe_points;
|
||||
struct strfilter *filter;
|
||||
} params;
|
||||
|
||||
/* Parse an event definition. Note that any error must die. */
|
||||
@@ -157,6 +162,27 @@ static int opt_show_vars(const struct option *opt __used,
|
||||
}
|
||||
#endif
|
||||
|
||||
static int opt_set_filter(const struct option *opt __used,
|
||||
const char *str, int unset __used)
|
||||
{
|
||||
const char *err;
|
||||
|
||||
if (str) {
|
||||
pr_debug2("Set filter: %s\n", str);
|
||||
if (params.filter)
|
||||
strfilter__delete(params.filter);
|
||||
params.filter = strfilter__new(str, &err);
|
||||
if (!params.filter) {
|
||||
pr_err("Filter parse error at %td.\n", err - str + 1);
|
||||
pr_err("Source: \"%s\"\n", str);
|
||||
pr_err(" %*c\n", (int)(err - str + 1), '^');
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char * const probe_usage[] = {
|
||||
"perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]",
|
||||
"perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]",
|
||||
@@ -221,6 +247,13 @@ static const struct option options[] = {
|
||||
OPT__DRY_RUN(&probe_event_dry_run),
|
||||
OPT_INTEGER('\0', "max-probes", ¶ms.max_probe_points,
|
||||
"Set how many probe points can be found for a probe."),
|
||||
OPT_BOOLEAN('F', "funcs", ¶ms.show_funcs,
|
||||
"Show potential probe-able functions."),
|
||||
OPT_CALLBACK('\0', "filter", NULL,
|
||||
"[!]FILTER", "Set a filter (with --vars/funcs only)\n"
|
||||
"\t\t\t(default: \"" DEFAULT_VAR_FILTER "\" for --vars,\n"
|
||||
"\t\t\t \"" DEFAULT_FUNC_FILTER "\" for --funcs)",
|
||||
opt_set_filter),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
@@ -246,7 +279,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
|
||||
params.max_probe_points = MAX_PROBES;
|
||||
|
||||
if ((!params.nevents && !params.dellist && !params.list_events &&
|
||||
!params.show_lines))
|
||||
!params.show_lines && !params.show_funcs))
|
||||
usage_with_options(probe_usage, options);
|
||||
|
||||
/*
|
||||
@@ -267,12 +300,41 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
|
||||
pr_err(" Error: Don't use --list with --vars.\n");
|
||||
usage_with_options(probe_usage, options);
|
||||
}
|
||||
if (params.show_funcs) {
|
||||
pr_err(" Error: Don't use --list with --funcs.\n");
|
||||
usage_with_options(probe_usage, options);
|
||||
}
|
||||
ret = show_perf_probe_events();
|
||||
if (ret < 0)
|
||||
pr_err(" Error: Failed to show event list. (%d)\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
if (params.show_funcs) {
|
||||
if (params.nevents != 0 || params.dellist) {
|
||||
pr_err(" Error: Don't use --funcs with"
|
||||
" --add/--del.\n");
|
||||
usage_with_options(probe_usage, options);
|
||||
}
|
||||
if (params.show_lines) {
|
||||
pr_err(" Error: Don't use --funcs with --line.\n");
|
||||
usage_with_options(probe_usage, options);
|
||||
}
|
||||
if (params.show_vars) {
|
||||
pr_err(" Error: Don't use --funcs with --vars.\n");
|
||||
usage_with_options(probe_usage, options);
|
||||
}
|
||||
if (!params.filter)
|
||||
params.filter = strfilter__new(DEFAULT_FUNC_FILTER,
|
||||
NULL);
|
||||
ret = show_available_funcs(params.target_module,
|
||||
params.filter);
|
||||
strfilter__delete(params.filter);
|
||||
if (ret < 0)
|
||||
pr_err(" Error: Failed to show functions."
|
||||
" (%d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef DWARF_SUPPORT
|
||||
if (params.show_lines) {
|
||||
@@ -297,10 +359,16 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
|
||||
" --add/--del.\n");
|
||||
usage_with_options(probe_usage, options);
|
||||
}
|
||||
if (!params.filter)
|
||||
params.filter = strfilter__new(DEFAULT_VAR_FILTER,
|
||||
NULL);
|
||||
|
||||
ret = show_available_vars(params.events, params.nevents,
|
||||
params.max_probe_points,
|
||||
params.target_module,
|
||||
params.filter,
|
||||
params.show_ext_vars);
|
||||
strfilter__delete(params.filter);
|
||||
if (ret < 0)
|
||||
pr_err(" Error: Failed to show vars. (%d)\n", ret);
|
||||
return ret;
|
||||
|
||||
+170
-282
File diff suppressed because it is too large
Load Diff
+93
-134
@@ -9,6 +9,7 @@
|
||||
|
||||
#include "util/util.h"
|
||||
|
||||
#include "util/annotate.h"
|
||||
#include "util/color.h"
|
||||
#include <linux/list.h>
|
||||
#include "util/cache.h"
|
||||
@@ -20,6 +21,8 @@
|
||||
|
||||
#include "perf.h"
|
||||
#include "util/debug.h"
|
||||
#include "util/evlist.h"
|
||||
#include "util/evsel.h"
|
||||
#include "util/header.h"
|
||||
#include "util/session.h"
|
||||
|
||||
@@ -43,120 +46,79 @@ static const char default_pretty_printing_style[] = "normal";
|
||||
static const char *pretty_printing_style = default_pretty_printing_style;
|
||||
|
||||
static char callchain_default_opt[] = "fractal,0.5";
|
||||
static symbol_filter_t annotate_init;
|
||||
|
||||
static struct hists *perf_session__hists_findnew(struct perf_session *self,
|
||||
u64 event_stream, u32 type,
|
||||
u64 config)
|
||||
{
|
||||
struct rb_node **p = &self->hists_tree.rb_node;
|
||||
struct rb_node *parent = NULL;
|
||||
struct hists *iter, *new;
|
||||
|
||||
while (*p != NULL) {
|
||||
parent = *p;
|
||||
iter = rb_entry(parent, struct hists, rb_node);
|
||||
if (iter->config == config)
|
||||
return iter;
|
||||
|
||||
|
||||
if (config > iter->config)
|
||||
p = &(*p)->rb_right;
|
||||
else
|
||||
p = &(*p)->rb_left;
|
||||
}
|
||||
|
||||
new = malloc(sizeof(struct hists));
|
||||
if (new == NULL)
|
||||
return NULL;
|
||||
memset(new, 0, sizeof(struct hists));
|
||||
new->event_stream = event_stream;
|
||||
new->config = config;
|
||||
new->type = type;
|
||||
rb_link_node(&new->rb_node, parent, p);
|
||||
rb_insert_color(&new->rb_node, &self->hists_tree);
|
||||
return new;
|
||||
}
|
||||
|
||||
static int perf_session__add_hist_entry(struct perf_session *self,
|
||||
static int perf_session__add_hist_entry(struct perf_session *session,
|
||||
struct addr_location *al,
|
||||
struct sample_data *data)
|
||||
struct perf_sample *sample)
|
||||
{
|
||||
struct map_symbol *syms = NULL;
|
||||
struct symbol *parent = NULL;
|
||||
int err = -ENOMEM;
|
||||
int err = 0;
|
||||
struct hist_entry *he;
|
||||
struct hists *hists;
|
||||
struct perf_event_attr *attr;
|
||||
struct perf_evsel *evsel;
|
||||
|
||||
if ((sort__has_parent || symbol_conf.use_callchain) && data->callchain) {
|
||||
syms = perf_session__resolve_callchain(self, al->thread,
|
||||
data->callchain, &parent);
|
||||
if (syms == NULL)
|
||||
return -ENOMEM;
|
||||
if ((sort__has_parent || symbol_conf.use_callchain) && sample->callchain) {
|
||||
err = perf_session__resolve_callchain(session, al->thread,
|
||||
sample->callchain, &parent);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
attr = perf_header__find_attr(data->id, &self->header);
|
||||
if (attr)
|
||||
hists = perf_session__hists_findnew(self, data->id, attr->type, attr->config);
|
||||
else
|
||||
hists = perf_session__hists_findnew(self, data->id, 0, 0);
|
||||
if (hists == NULL)
|
||||
goto out_free_syms;
|
||||
he = __hists__add_entry(hists, al, parent, data->period);
|
||||
evsel = perf_evlist__id2evsel(session->evlist, sample->id);
|
||||
if (evsel == NULL) {
|
||||
/*
|
||||
* FIXME: Propagate this back, but at least we're in a builtin,
|
||||
* where exit() is allowed. ;-)
|
||||
*/
|
||||
ui__warning("Invalid %s file, contains samples with id %" PRIu64 " not in "
|
||||
"its header!\n", input_name, sample->id);
|
||||
exit_browser(0);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
he = __hists__add_entry(&evsel->hists, al, parent, sample->period);
|
||||
if (he == NULL)
|
||||
goto out_free_syms;
|
||||
err = 0;
|
||||
return -ENOMEM;
|
||||
|
||||
if (symbol_conf.use_callchain) {
|
||||
err = callchain_append(he->callchain, data->callchain, syms,
|
||||
data->period);
|
||||
err = callchain_append(he->callchain, &session->callchain_cursor,
|
||||
sample->period);
|
||||
if (err)
|
||||
goto out_free_syms;
|
||||
return err;
|
||||
}
|
||||
/*
|
||||
* Only in the newt browser we are doing integrated annotation,
|
||||
* so we don't allocated the extra space needed because the stdio
|
||||
* code will not use it.
|
||||
*/
|
||||
if (use_browser > 0)
|
||||
err = hist_entry__inc_addr_samples(he, al->addr);
|
||||
out_free_syms:
|
||||
free(syms);
|
||||
if (al->sym != NULL && use_browser > 0) {
|
||||
struct annotation *notes = symbol__annotation(he->ms.sym);
|
||||
|
||||
assert(evsel != NULL);
|
||||
|
||||
err = -ENOMEM;
|
||||
if (notes->src == NULL &&
|
||||
symbol__alloc_hist(he->ms.sym, session->evlist->nr_entries) < 0)
|
||||
goto out;
|
||||
|
||||
err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
|
||||
}
|
||||
|
||||
evsel->hists.stats.total_period += sample->period;
|
||||
hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int add_event_total(struct perf_session *session,
|
||||
struct sample_data *data,
|
||||
struct perf_event_attr *attr)
|
||||
{
|
||||
struct hists *hists;
|
||||
|
||||
if (attr)
|
||||
hists = perf_session__hists_findnew(session, data->id,
|
||||
attr->type, attr->config);
|
||||
else
|
||||
hists = perf_session__hists_findnew(session, data->id, 0, 0);
|
||||
|
||||
if (!hists)
|
||||
return -ENOMEM;
|
||||
|
||||
hists->stats.total_period += data->period;
|
||||
/*
|
||||
* FIXME: add_event_total should be moved from here to
|
||||
* perf_session__process_event so that the proper hist is passed to
|
||||
* the event_op methods.
|
||||
*/
|
||||
hists__inc_nr_events(hists, PERF_RECORD_SAMPLE);
|
||||
session->hists.stats.total_period += data->period;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int process_sample_event(event_t *event, struct sample_data *sample,
|
||||
static int process_sample_event(union perf_event *event,
|
||||
struct perf_sample *sample,
|
||||
struct perf_session *session)
|
||||
{
|
||||
struct addr_location al;
|
||||
struct perf_event_attr *attr;
|
||||
|
||||
if (event__preprocess_sample(event, session, &al, sample, NULL) < 0) {
|
||||
if (perf_event__preprocess_sample(event, session, &al, sample,
|
||||
annotate_init) < 0) {
|
||||
fprintf(stderr, "problem processing %d event, skipping it.\n",
|
||||
event->header.type);
|
||||
return -1;
|
||||
@@ -170,26 +132,17 @@ static int process_sample_event(event_t *event, struct sample_data *sample,
|
||||
return -1;
|
||||
}
|
||||
|
||||
attr = perf_header__find_attr(sample->id, &session->header);
|
||||
|
||||
if (add_event_total(session, sample, attr)) {
|
||||
pr_debug("problem adding event period\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int process_read_event(event_t *event, struct sample_data *sample __used,
|
||||
struct perf_session *session __used)
|
||||
static int process_read_event(union perf_event *event,
|
||||
struct perf_sample *sample __used,
|
||||
struct perf_session *session)
|
||||
{
|
||||
struct perf_event_attr *attr;
|
||||
|
||||
attr = perf_header__find_attr(event->read.id, &session->header);
|
||||
|
||||
struct perf_evsel *evsel = perf_evlist__id2evsel(session->evlist,
|
||||
event->read.id);
|
||||
if (show_threads) {
|
||||
const char *name = attr ? __event_name(attr->type, attr->config)
|
||||
: "unknown";
|
||||
const char *name = evsel ? event_name(evsel) : "unknown";
|
||||
perf_read_values_add_value(&show_threads_values,
|
||||
event->read.pid, event->read.tid,
|
||||
event->read.id,
|
||||
@@ -198,7 +151,7 @@ static int process_read_event(event_t *event, struct sample_data *sample __used,
|
||||
}
|
||||
|
||||
dump_printf(": %d %d %s %" PRIu64 "\n", event->read.pid, event->read.tid,
|
||||
attr ? __event_name(attr->type, attr->config) : "FAIL",
|
||||
evsel ? event_name(evsel) : "FAIL",
|
||||
event->read.value);
|
||||
|
||||
return 0;
|
||||
@@ -222,7 +175,7 @@ static int perf_session__setup_sample_type(struct perf_session *self)
|
||||
} else if (!dont_use_callchains && callchain_param.mode != CHAIN_NONE &&
|
||||
!symbol_conf.use_callchain) {
|
||||
symbol_conf.use_callchain = true;
|
||||
if (register_callchain_param(&callchain_param) < 0) {
|
||||
if (callchain_register_param(&callchain_param) < 0) {
|
||||
fprintf(stderr, "Can't register callchain"
|
||||
" params\n");
|
||||
return -EINVAL;
|
||||
@@ -233,17 +186,17 @@ static int perf_session__setup_sample_type(struct perf_session *self)
|
||||
}
|
||||
|
||||
static struct perf_event_ops event_ops = {
|
||||
.sample = process_sample_event,
|
||||
.mmap = event__process_mmap,
|
||||
.comm = event__process_comm,
|
||||
.exit = event__process_task,
|
||||
.fork = event__process_task,
|
||||
.lost = event__process_lost,
|
||||
.read = process_read_event,
|
||||
.attr = event__process_attr,
|
||||
.event_type = event__process_event_type,
|
||||
.tracing_data = event__process_tracing_data,
|
||||
.build_id = event__process_build_id,
|
||||
.sample = process_sample_event,
|
||||
.mmap = perf_event__process_mmap,
|
||||
.comm = perf_event__process_comm,
|
||||
.exit = perf_event__process_task,
|
||||
.fork = perf_event__process_task,
|
||||
.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,
|
||||
.ordering_requires_timestamps = true,
|
||||
};
|
||||
@@ -269,21 +222,21 @@ static size_t hists__fprintf_nr_sample_events(struct hists *self,
|
||||
return ret + fprintf(fp, "\n#\n");
|
||||
}
|
||||
|
||||
static int hists__tty_browse_tree(struct rb_root *tree, const char *help)
|
||||
static int perf_evlist__tty_browse_hists(struct perf_evlist *evlist,
|
||||
const char *help)
|
||||
{
|
||||
struct rb_node *next = rb_first(tree);
|
||||
struct perf_evsel *pos;
|
||||
|
||||
while (next) {
|
||||
struct hists *hists = rb_entry(next, struct hists, rb_node);
|
||||
list_for_each_entry(pos, &evlist->entries, node) {
|
||||
struct hists *hists = &pos->hists;
|
||||
const char *evname = NULL;
|
||||
|
||||
if (rb_first(&hists->entries) != rb_last(&hists->entries))
|
||||
evname = __event_name(hists->type, hists->config);
|
||||
evname = event_name(pos);
|
||||
|
||||
hists__fprintf_nr_sample_events(hists, evname, stdout);
|
||||
hists__fprintf(hists, NULL, false, stdout);
|
||||
fprintf(stdout, "\n\n");
|
||||
next = rb_next(&hists->rb_node);
|
||||
}
|
||||
|
||||
if (sort_order == default_sort_order &&
|
||||
@@ -304,8 +257,9 @@ static int hists__tty_browse_tree(struct rb_root *tree, const char *help)
|
||||
static int __cmd_report(void)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
u64 nr_samples;
|
||||
struct perf_session *session;
|
||||
struct rb_node *next;
|
||||
struct perf_evsel *pos;
|
||||
const char *help = "For a higher level overview, try: perf report --sort comm,dso";
|
||||
|
||||
signal(SIGINT, sig_handler);
|
||||
@@ -336,20 +290,24 @@ static int __cmd_report(void)
|
||||
if (verbose > 2)
|
||||
perf_session__fprintf_dsos(session, stdout);
|
||||
|
||||
next = rb_first(&session->hists_tree);
|
||||
while (next) {
|
||||
struct hists *hists;
|
||||
nr_samples = 0;
|
||||
list_for_each_entry(pos, &session->evlist->entries, node) {
|
||||
struct hists *hists = &pos->hists;
|
||||
|
||||
hists = rb_entry(next, struct hists, rb_node);
|
||||
hists__collapse_resort(hists);
|
||||
hists__output_resort(hists);
|
||||
next = rb_next(&hists->rb_node);
|
||||
nr_samples += hists->stats.nr_events[PERF_RECORD_SAMPLE];
|
||||
}
|
||||
|
||||
if (nr_samples == 0) {
|
||||
ui__warning("The %s file has no samples!\n", input_name);
|
||||
goto out_delete;
|
||||
}
|
||||
|
||||
if (use_browser > 0)
|
||||
hists__tui_browse_tree(&session->hists_tree, help);
|
||||
perf_evlist__tui_browse_hists(session->evlist, help);
|
||||
else
|
||||
hists__tty_browse_tree(&session->hists_tree, help);
|
||||
perf_evlist__tty_browse_hists(session->evlist, help);
|
||||
|
||||
out_delete:
|
||||
/*
|
||||
@@ -424,7 +382,7 @@ parse_callchain_opt(const struct option *opt __used, const char *arg,
|
||||
if (tok2)
|
||||
callchain_param.print_limit = strtod(tok2, &endptr);
|
||||
setup:
|
||||
if (register_callchain_param(&callchain_param) < 0) {
|
||||
if (callchain_register_param(&callchain_param) < 0) {
|
||||
fprintf(stderr, "Can't register callchain params\n");
|
||||
return -1;
|
||||
}
|
||||
@@ -498,7 +456,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
|
||||
use_browser = 1;
|
||||
|
||||
if (strcmp(input_name, "-") != 0)
|
||||
setup_browser();
|
||||
setup_browser(true);
|
||||
else
|
||||
use_browser = 0;
|
||||
/*
|
||||
@@ -507,7 +465,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
|
||||
* implementation.
|
||||
*/
|
||||
if (use_browser > 0) {
|
||||
symbol_conf.priv_size = sizeof(struct sym_priv);
|
||||
symbol_conf.priv_size = sizeof(struct annotation);
|
||||
annotate_init = symbol__annotate_init;
|
||||
/*
|
||||
* For searching by name on the "Browse map details".
|
||||
* providing it only in verbose mode not to bloat too
|
||||
|
||||
+11
-16
@@ -369,11 +369,6 @@ static void
|
||||
process_sched_event(struct task_desc *this_task __used, struct sched_atom *atom)
|
||||
{
|
||||
int ret = 0;
|
||||
u64 now;
|
||||
long long delta;
|
||||
|
||||
now = get_nsecs();
|
||||
delta = start_time + atom->timestamp - now;
|
||||
|
||||
switch (atom->type) {
|
||||
case SCHED_EVENT_RUN:
|
||||
@@ -562,7 +557,7 @@ static void wait_for_tasks(void)
|
||||
|
||||
static void run_one_test(void)
|
||||
{
|
||||
u64 T0, T1, delta, avg_delta, fluct, std_dev;
|
||||
u64 T0, T1, delta, avg_delta, fluct;
|
||||
|
||||
T0 = get_nsecs();
|
||||
wait_for_tasks();
|
||||
@@ -578,7 +573,6 @@ static void run_one_test(void)
|
||||
else
|
||||
fluct = delta - avg_delta;
|
||||
sum_fluct += fluct;
|
||||
std_dev = sum_fluct / nr_runs / sqrt(nr_runs);
|
||||
if (!run_avg)
|
||||
run_avg = delta;
|
||||
run_avg = (run_avg*9 + delta)/10;
|
||||
@@ -799,7 +793,7 @@ replay_switch_event(struct trace_switch_event *switch_event,
|
||||
u64 timestamp,
|
||||
struct thread *thread __used)
|
||||
{
|
||||
struct task_desc *prev, *next;
|
||||
struct task_desc *prev, __used *next;
|
||||
u64 timestamp0;
|
||||
s64 delta;
|
||||
|
||||
@@ -1404,7 +1398,7 @@ map_switch_event(struct trace_switch_event *switch_event,
|
||||
u64 timestamp,
|
||||
struct thread *thread __used)
|
||||
{
|
||||
struct thread *sched_out, *sched_in;
|
||||
struct thread *sched_out __used, *sched_in;
|
||||
int new_shortname;
|
||||
u64 timestamp0;
|
||||
s64 delta;
|
||||
@@ -1580,9 +1574,9 @@ process_sched_migrate_task_event(void *data, struct perf_session *session,
|
||||
event, cpu, timestamp, thread);
|
||||
}
|
||||
|
||||
static void
|
||||
process_raw_event(event_t *raw_event __used, struct perf_session *session,
|
||||
void *data, int cpu, u64 timestamp, struct thread *thread)
|
||||
static void process_raw_event(union perf_event *raw_event __used,
|
||||
struct perf_session *session, void *data, int cpu,
|
||||
u64 timestamp, struct thread *thread)
|
||||
{
|
||||
struct event *event;
|
||||
int type;
|
||||
@@ -1607,7 +1601,8 @@ process_raw_event(event_t *raw_event __used, struct perf_session *session,
|
||||
process_sched_migrate_task_event(data, session, event, cpu, timestamp, thread);
|
||||
}
|
||||
|
||||
static int process_sample_event(event_t *event, struct sample_data *sample,
|
||||
static int process_sample_event(union perf_event *event,
|
||||
struct perf_sample *sample,
|
||||
struct perf_session *session)
|
||||
{
|
||||
struct thread *thread;
|
||||
@@ -1635,9 +1630,9 @@ static int process_sample_event(event_t *event, struct sample_data *sample,
|
||||
|
||||
static struct perf_event_ops event_ops = {
|
||||
.sample = process_sample_event,
|
||||
.comm = event__process_comm,
|
||||
.lost = event__process_lost,
|
||||
.fork = event__process_task,
|
||||
.comm = perf_event__process_comm,
|
||||
.lost = perf_event__process_lost,
|
||||
.fork = perf_event__process_task,
|
||||
.ordered_samples = true,
|
||||
};
|
||||
|
||||
|
||||
@@ -63,7 +63,8 @@ static int cleanup_scripting(void)
|
||||
|
||||
static char const *input_name = "perf.data";
|
||||
|
||||
static int process_sample_event(event_t *event, struct sample_data *sample,
|
||||
static int process_sample_event(union perf_event *event,
|
||||
struct perf_sample *sample,
|
||||
struct perf_session *session)
|
||||
{
|
||||
struct thread *thread = perf_session__findnew(session, event->ip.pid);
|
||||
@@ -100,14 +101,14 @@ static int process_sample_event(event_t *event, struct sample_data *sample,
|
||||
}
|
||||
|
||||
static struct perf_event_ops event_ops = {
|
||||
.sample = process_sample_event,
|
||||
.comm = event__process_comm,
|
||||
.attr = event__process_attr,
|
||||
.event_type = event__process_event_type,
|
||||
.tracing_data = event__process_tracing_data,
|
||||
.build_id = event__process_build_id,
|
||||
.ordering_requires_timestamps = true,
|
||||
.sample = process_sample_event,
|
||||
.comm = perf_event__process_comm,
|
||||
.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,
|
||||
.ordering_requires_timestamps = true,
|
||||
};
|
||||
|
||||
extern volatile int session_done;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user