Skip to content

Commit

Permalink
Merge branch 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/…
Browse files Browse the repository at this point in the history
…linux/kernel/git/tip/tip

Pull perf tooling fixes from Ingo Molnar:
 "This contains five tooling fixes:

   - fix a remaining mmap2 assumption which resulted in perf top output
     breakage
   - fix mmap ring-buffer processing bug that corrupts data
   - fix for a severe python scripting memory leak
   - fix broken (and user-visible) -g option handling
   - fix stdio output

  The diffstat size is larger than what we'd like to see this late :-/"

* 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  perf tools: Fixup mmap event consumption
  perf top: Split -G and --call-graph
  perf record: Split -g and --call-graph
  perf hists: Add color overhead for stdio output buffer
  perf tools: Fix up /proc/PID/maps parsing
  perf script python: Fix mem leak due to missing Py_DECREFs on dict entries
  • Loading branch information
Linus Torvalds committed Oct 29, 2013
2 parents 2a999aa + cd65718 commit f9ec2e6
Show file tree
Hide file tree
Showing 22 changed files with 176 additions and 81 deletions.
14 changes: 13 additions & 1 deletion tools/perf/Documentation/perf-record.txt
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,20 @@ OPTIONS
Number of mmap data pages. Must be a power of two.

-g::
Enables call-graph (stack chain/backtrace) recording.

--call-graph::
Do call-graph (stack chain/backtrace) recording.
Setup and enable call-graph (stack chain/backtrace) recording,
implies -g.

Allows specifying "fp" (frame pointer) or "dwarf"
(DWARF's CFI - Call Frame Information) as the method to collect
the information used to show the call graphs.

In some systems, where binaries are build with gcc
--fomit-frame-pointer, using the "fp" method will produce bogus
call graphs, using "dwarf", if available (perf tools linked to
the libunwind library) should be used instead.

-q::
--quiet::
Expand Down
18 changes: 5 additions & 13 deletions tools/perf/Documentation/perf-top.txt
Original file line number Diff line number Diff line change
Expand Up @@ -140,20 +140,12 @@ Default is to monitor all CPUS.
--asm-raw::
Show raw instruction encoding of assembly instructions.

-G [type,min,order]::
-G::
Enables call-graph (stack chain/backtrace) recording.

--call-graph::
Display call chains using type, min percent threshold and order.
type can be either:
- flat: single column, linear exposure of call chains.
- graph: use a graph tree, displaying absolute overhead rates.
- fractal: like graph, but displays relative rates. Each branch of
the tree is considered as a new profiled object.

order can be either:
- callee: callee based call graph.
- caller: inverted caller based call graph.

Default: fractal,0.5,callee.
Setup and enable call-graph (stack chain/backtrace) recording,
implies -G.

--ignore-callees=<regex>::
Ignore callees of the function(s) matching the given regex.
Expand Down
7 changes: 7 additions & 0 deletions tools/perf/builtin-kvm.c
Original file line number Diff line number Diff line change
Expand Up @@ -888,11 +888,18 @@ static s64 perf_kvm__mmap_read_idx(struct perf_kvm_stat *kvm, int idx,
while ((event = perf_evlist__mmap_read(kvm->evlist, idx)) != NULL) {
err = perf_evlist__parse_sample(kvm->evlist, event, &sample);
if (err) {
perf_evlist__mmap_consume(kvm->evlist, idx);
pr_err("Failed to parse sample\n");
return -1;
}

err = perf_session_queue_event(kvm->session, event, &sample, 0);
/*
* FIXME: Here we can't consume the event, as perf_session_queue_event will
* point to it, and it'll get possibly overwritten by the kernel.
*/
perf_evlist__mmap_consume(kvm->evlist, idx);

if (err) {
pr_err("Failed to enqueue sample: %d\n", err);
return -1;
Expand Down
73 changes: 51 additions & 22 deletions tools/perf/builtin-record.c
Original file line number Diff line number Diff line change
Expand Up @@ -712,21 +712,12 @@ static int get_stack_size(char *str, unsigned long *_size)
}
#endif /* LIBUNWIND_SUPPORT */

int record_parse_callchain_opt(const struct option *opt,
const char *arg, int unset)
int record_parse_callchain(const char *arg, struct perf_record_opts *opts)
{
struct perf_record_opts *opts = opt->value;
char *tok, *name, *saveptr = NULL;
char *buf;
int ret = -1;

/* --no-call-graph */
if (unset)
return 0;

/* We specified default option if none is provided. */
BUG_ON(!arg);

/* We need buffer that we know we can write to. */
buf = malloc(strlen(arg) + 1);
if (!buf)
Expand Down Expand Up @@ -764,27 +755,62 @@ int record_parse_callchain_opt(const struct option *opt,
ret = get_stack_size(tok, &size);
opts->stack_dump_size = size;
}

if (!ret)
pr_debug("callchain: stack dump size %d\n",
opts->stack_dump_size);
#endif /* LIBUNWIND_SUPPORT */
} else {
pr_err("callchain: Unknown -g option "
pr_err("callchain: Unknown --call-graph option "
"value: %s\n", arg);
break;
}

} while (0);

free(buf);
return ret;
}

static void callchain_debug(struct perf_record_opts *opts)
{
pr_debug("callchain: type %d\n", opts->call_graph);

if (opts->call_graph == CALLCHAIN_DWARF)
pr_debug("callchain: stack dump size %d\n",
opts->stack_dump_size);
}

int record_parse_callchain_opt(const struct option *opt,
const char *arg,
int unset)
{
struct perf_record_opts *opts = opt->value;
int ret;

/* --no-call-graph */
if (unset) {
opts->call_graph = CALLCHAIN_NONE;
pr_debug("callchain: disabled\n");
return 0;
}

ret = record_parse_callchain(arg, opts);
if (!ret)
pr_debug("callchain: type %d\n", opts->call_graph);
callchain_debug(opts);

return ret;
}

int record_callchain_opt(const struct option *opt,
const char *arg __maybe_unused,
int unset __maybe_unused)
{
struct perf_record_opts *opts = opt->value;

if (opts->call_graph == CALLCHAIN_NONE)
opts->call_graph = CALLCHAIN_FP;

callchain_debug(opts);
return 0;
}

static const char * const record_usage[] = {
"perf record [<options>] [<command>]",
"perf record [<options>] -- <command> [<options>]",
Expand Down Expand Up @@ -813,12 +839,12 @@ static struct perf_record record = {
},
};

#define CALLCHAIN_HELP "do call-graph (stack chain/backtrace) recording: "
#define CALLCHAIN_HELP "setup and enables call-graph (stack chain/backtrace) recording: "

#ifdef LIBUNWIND_SUPPORT
const char record_callchain_help[] = CALLCHAIN_HELP "[fp] dwarf";
const char record_callchain_help[] = CALLCHAIN_HELP "fp dwarf";
#else
const char record_callchain_help[] = CALLCHAIN_HELP "[fp]";
const char record_callchain_help[] = CALLCHAIN_HELP "fp";
#endif

/*
Expand Down Expand Up @@ -858,9 +884,12 @@ const struct option record_options[] = {
"number of mmap data pages"),
OPT_BOOLEAN(0, "group", &record.opts.group,
"put the counters into a counter group"),
OPT_CALLBACK_DEFAULT('g', "call-graph", &record.opts,
"mode[,dump_size]", record_callchain_help,
&record_parse_callchain_opt, "fp"),
OPT_CALLBACK_NOOPT('g', NULL, &record.opts,
NULL, "enables call-graph recording" ,
&record_callchain_opt),
OPT_CALLBACK(0, "call-graph", &record.opts,
"mode[,dump_size]", record_callchain_help,
&record_parse_callchain_opt),
OPT_INCR('v', "verbose", &verbose,
"be more verbose (show counter open errors, etc)"),
OPT_BOOLEAN('q', "quiet", &quiet, "don't print any message"),
Expand Down
33 changes: 19 additions & 14 deletions tools/perf/builtin-top.c
Original file line number Diff line number Diff line change
Expand Up @@ -810,7 +810,7 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx)
ret = perf_evlist__parse_sample(top->evlist, event, &sample);
if (ret) {
pr_err("Can't parse sample, err = %d\n", ret);
continue;
goto next_event;
}

evsel = perf_evlist__id2evsel(session->evlist, sample.id);
Expand All @@ -825,13 +825,13 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx)
case PERF_RECORD_MISC_USER:
++top->us_samples;
if (top->hide_user_symbols)
continue;
goto next_event;
machine = &session->machines.host;
break;
case PERF_RECORD_MISC_KERNEL:
++top->kernel_samples;
if (top->hide_kernel_symbols)
continue;
goto next_event;
machine = &session->machines.host;
break;
case PERF_RECORD_MISC_GUEST_KERNEL:
Expand All @@ -847,7 +847,7 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx)
*/
/* Fall thru */
default:
continue;
goto next_event;
}


Expand All @@ -859,6 +859,8 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx)
machine__process_event(machine, event);
} else
++session->stats.nr_unknown_events;
next_event:
perf_evlist__mmap_consume(top->evlist, idx);
}
}

Expand Down Expand Up @@ -1016,16 +1018,16 @@ static int __cmd_top(struct perf_top *top)
}

static int
parse_callchain_opt(const struct option *opt, const char *arg, int unset)
callchain_opt(const struct option *opt, const char *arg, int unset)
{
/*
* --no-call-graph
*/
if (unset)
return 0;

symbol_conf.use_callchain = true;
return record_callchain_opt(opt, arg, unset);
}

static int
parse_callchain_opt(const struct option *opt, const char *arg, int unset)
{
symbol_conf.use_callchain = true;
return record_parse_callchain_opt(opt, arg, unset);
}

Expand Down Expand Up @@ -1106,9 +1108,12 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
"sort by key(s): pid, comm, dso, symbol, parent, weight, local_weight"),
OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples,
"Show a column with the number of samples"),
OPT_CALLBACK_DEFAULT('G', "call-graph", &top.record_opts,
"mode[,dump_size]", record_callchain_help,
&parse_callchain_opt, "fp"),
OPT_CALLBACK_NOOPT('G', NULL, &top.record_opts,
NULL, "enables call-graph recording",
&callchain_opt),
OPT_CALLBACK(0, "call-graph", &top.record_opts,
"mode[,dump_size]", record_callchain_help,
&parse_callchain_opt),
OPT_CALLBACK(0, "ignore-callees", NULL, "regex",
"ignore callees of these functions in call graphs",
report_parse_ignore_callees_opt),
Expand Down
8 changes: 5 additions & 3 deletions tools/perf/builtin-trace.c
Original file line number Diff line number Diff line change
Expand Up @@ -987,7 +987,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
err = perf_evlist__parse_sample(evlist, event, &sample);
if (err) {
fprintf(trace->output, "Can't parse sample, err = %d, skipping...\n", err);
continue;
goto next_event;
}

if (trace->base_time == 0)
Expand All @@ -1001,18 +1001,20 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
evsel = perf_evlist__id2evsel(evlist, sample.id);
if (evsel == NULL) {
fprintf(trace->output, "Unknown tp ID %" PRIu64 ", skipping...\n", sample.id);
continue;
goto next_event;
}

if (sample.raw_data == NULL) {
fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n",
perf_evsel__name(evsel), sample.tid,
sample.cpu, sample.raw_size);
continue;
goto next_event;
}

handler = evsel->handler.func;
handler(trace, evsel, &sample);
next_event:
perf_evlist__mmap_consume(evlist, i);

if (done)
goto out_unmap_evlist;
Expand Down
1 change: 1 addition & 0 deletions tools/perf/tests/code-reading.c
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,7 @@ static int process_events(struct machine *machine, struct perf_evlist *evlist,
for (i = 0; i < evlist->nr_mmaps; i++) {
while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
ret = process_event(machine, evlist, event, state);
perf_evlist__mmap_consume(evlist, i);
if (ret < 0)
return ret;
}
Expand Down
1 change: 1 addition & 0 deletions tools/perf/tests/keep-tracking.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ static int find_comm(struct perf_evlist *evlist, const char *comm)
(pid_t)event->comm.tid == getpid() &&
strcmp(event->comm.comm, comm) == 0)
found += 1;
perf_evlist__mmap_consume(evlist, i);
}
}
return found;
Expand Down
1 change: 1 addition & 0 deletions tools/perf/tests/mmap-basic.c
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ int test__basic_mmap(void)
goto out_munmap;
}
nr_events[evsel->idx]++;
perf_evlist__mmap_consume(evlist, 0);
}

err = 0;
Expand Down
4 changes: 3 additions & 1 deletion tools/perf/tests/open-syscall-tp-fields.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,10 @@ int test__syscall_open_tp_fields(void)

++nr_events;

if (type != PERF_RECORD_SAMPLE)
if (type != PERF_RECORD_SAMPLE) {
perf_evlist__mmap_consume(evlist, i);
continue;
}

err = perf_evsel__parse_sample(evsel, event, &sample);
if (err) {
Expand Down
2 changes: 2 additions & 0 deletions tools/perf/tests/perf-record.c
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,8 @@ int test__PERF_RECORD(void)
type);
++errs;
}

perf_evlist__mmap_consume(evlist, i);
}
}

Expand Down
4 changes: 3 additions & 1 deletion tools/perf/tests/perf-time-to-tsc.c
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ int test__perf_time_to_tsc(void)
if (event->header.type != PERF_RECORD_COMM ||
(pid_t)event->comm.pid != getpid() ||
(pid_t)event->comm.tid != getpid())
continue;
goto next_event;

if (strcmp(event->comm.comm, comm1) == 0) {
CHECK__(perf_evsel__parse_sample(evsel, event,
Expand All @@ -134,6 +134,8 @@ int test__perf_time_to_tsc(void)
&sample));
comm2_time = sample.time;
}
next_event:
perf_evlist__mmap_consume(evlist, i);
}
}

Expand Down
4 changes: 3 additions & 1 deletion tools/perf/tests/sw-clock.c
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id)
struct perf_sample sample;

if (event->header.type != PERF_RECORD_SAMPLE)
continue;
goto next_event;

err = perf_evlist__parse_sample(evlist, event, &sample);
if (err < 0) {
Expand All @@ -88,6 +88,8 @@ static int __test__sw_clock_freq(enum perf_sw_ids clock_id)

total_periods += sample.period;
nr_samples++;
next_event:
perf_evlist__mmap_consume(evlist, 0);
}

if ((u64) nr_samples == total_periods) {
Expand Down
Loading

0 comments on commit f9ec2e6

Please sign in to comment.