Skip to content

Commit

Permalink
Merge tag 'perf-core-for-mingo-20160429' of git://git.kernel.org/pub/…
Browse files Browse the repository at this point in the history
…scm/linux/kernel/git/acme/linux into perf/core

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

User visible changes:

 - Allow generate timestamped suffixed multiple perf.data files upon receiving
   SIGUSR2 in 'perf record', to slice a long running monitoring session, allowing
   to dump uninteresting sessions (Wang Nan)

 - Handle ENOMEM for perf_event_max_stack + PERF_SAMPLE_CALLCHAIN
   in perf_evsel__open_strerror(), showing a more informative
   message when the request call stack depth can't be allocated by
   the kernel (Arnaldo Carvalho de Melo)

Infrastructure changes:

 - Use strbuf for making strings in 'perf probe' (Masami Hiramatsu)

 - Do not use sizeof on pointer type, not a problem since its a pointer to
   pointer, fix none the less. Found by Coccinelle (Vaishali Thakkar)

Cleanups:

 - Fix for Coverity found issues in the bpf feature build test (Florian Fainelli)

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
  • Loading branch information
Ingo Molnar committed Apr 29, 2016
2 parents 3521ba1 + ca7ce82 commit 03d85a6
Show file tree
Hide file tree
Showing 11 changed files with 393 additions and 290 deletions.
3 changes: 1 addition & 2 deletions tools/build/feature/test-bpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,9 @@ int main(void)
attr.log_level = 0;
attr.kern_version = 0;

attr = attr;
/*
* Test existence of __NR_bpf and BPF_PROG_LOAD.
* This call should fail if we run the testcase.
*/
return syscall(__NR_bpf, BPF_PROG_LOAD, attr, sizeof(attr));
return syscall(__NR_bpf, BPF_PROG_LOAD, &attr, sizeof(attr));
}
13 changes: 13 additions & 0 deletions tools/perf/Documentation/perf-record.txt
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,19 @@ Configure all used events to run in kernel space.
--all-user::
Configure all used events to run in user space.

--timestamp-filename
Append timestamp to output file name.

--switch-output::
Generate multiple perf.data files, timestamp prefixed, switching to a new one
when receiving a SIGUSR2.

A possible use case is to, given an external event, slice the perf.data file
that gets then processed, possibly via a perf script, to decide if that
particular perf.data snapshot should be kept or not.

Implies --timestamp-filename, --no-buildid and --no-buildid-cache.

SEE ALSO
--------
linkperf:perf-stat[1], linkperf:perf-list[1]
173 changes: 118 additions & 55 deletions tools/perf/builtin-record.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include "util/parse-regs-options.h"
#include "util/llvm-utils.h"
#include "util/bpf-loader.h"
#include "util/trigger.h"
#include "asm/bug.h"

#include <unistd.h>
Expand All @@ -57,6 +58,7 @@ struct record {
bool no_buildid_cache_set;
bool buildid_all;
bool timestamp_filename;
bool switch_output;
unsigned long long samples;
};

Expand Down Expand Up @@ -127,44 +129,9 @@ static volatile int done;
static volatile int signr = -1;
static volatile int child_finished;

static volatile enum {
AUXTRACE_SNAPSHOT_OFF = -1,
AUXTRACE_SNAPSHOT_DISABLED = 0,
AUXTRACE_SNAPSHOT_ENABLED = 1,
} auxtrace_snapshot_state = AUXTRACE_SNAPSHOT_OFF;

static inline void
auxtrace_snapshot_on(void)
{
auxtrace_snapshot_state = AUXTRACE_SNAPSHOT_DISABLED;
}

static inline void
auxtrace_snapshot_enable(void)
{
if (auxtrace_snapshot_state == AUXTRACE_SNAPSHOT_OFF)
return;
auxtrace_snapshot_state = AUXTRACE_SNAPSHOT_ENABLED;
}

static inline void
auxtrace_snapshot_disable(void)
{
if (auxtrace_snapshot_state == AUXTRACE_SNAPSHOT_OFF)
return;
auxtrace_snapshot_state = AUXTRACE_SNAPSHOT_DISABLED;
}

static inline bool
auxtrace_snapshot_is_enabled(void)
{
if (auxtrace_snapshot_state == AUXTRACE_SNAPSHOT_OFF)
return false;
return auxtrace_snapshot_state == AUXTRACE_SNAPSHOT_ENABLED;
}

static volatile int auxtrace_snapshot_err;
static volatile int auxtrace_record__snapshot_started;
static DEFINE_TRIGGER(auxtrace_snapshot_trigger);
static DEFINE_TRIGGER(switch_output_trigger);

static void sig_handler(int sig)
{
Expand Down Expand Up @@ -282,11 +249,12 @@ static void record__read_auxtrace_snapshot(struct record *rec)
{
pr_debug("Recording AUX area tracing snapshot\n");
if (record__auxtrace_read_snapshot_all(rec) < 0) {
auxtrace_snapshot_err = -1;
trigger_error(&auxtrace_snapshot_trigger);
} else {
auxtrace_snapshot_err = auxtrace_record__snapshot_finish(rec->itr);
if (!auxtrace_snapshot_err)
auxtrace_snapshot_enable();
if (auxtrace_record__snapshot_finish(rec->itr))
trigger_error(&auxtrace_snapshot_trigger);
else
trigger_ready(&auxtrace_snapshot_trigger);
}
}

Expand Down Expand Up @@ -532,6 +500,25 @@ record__finish_output(struct record *rec)
return;
}

static int record__synthesize_workload(struct record *rec)
{
struct {
struct thread_map map;
struct thread_map_data map_data;
} thread_map;

thread_map.map.nr = 1;
thread_map.map.map[0].pid = rec->evlist->workload.pid;
thread_map.map.map[0].comm = NULL;
return perf_event__synthesize_thread_map(&rec->tool, &thread_map.map,
process_synthesized_event,
&rec->session->machines.host,
rec->opts.sample_address,
rec->opts.proc_map_timeout);
}

static int record__synthesize(struct record *rec);

static int
record__switch_output(struct record *rec, bool at_exit)
{
Expand Down Expand Up @@ -560,6 +547,23 @@ record__switch_output(struct record *rec, bool at_exit)
if (!quiet)
fprintf(stderr, "[ perf record: Dump %s.%s ]\n",
file->path, timestamp);

/* Output tracking events */
if (!at_exit) {
record__synthesize(rec);

/*
* In 'perf record --switch-output' without -a,
* record__synthesize() in record__switch_output() won't
* generate tracking events because there's no thread_map
* in evlist. Which causes newly created perf.data doesn't
* contain map and comm information.
* Create a fake thread_map and directly call
* perf_event__synthesize_thread_map() for those events.
*/
if (target__none(&rec->opts.target))
record__synthesize_workload(rec);
}
return fd;
}

Expand Down Expand Up @@ -684,9 +688,12 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
signal(SIGINT, sig_handler);
signal(SIGTERM, sig_handler);

if (rec->opts.auxtrace_snapshot_mode) {
if (rec->opts.auxtrace_snapshot_mode || rec->switch_output) {
signal(SIGUSR2, snapshot_sig_handler);
auxtrace_snapshot_on();
if (rec->opts.auxtrace_snapshot_mode)
trigger_on(&auxtrace_snapshot_trigger);
if (rec->switch_output)
trigger_on(&switch_output_trigger);
} else {
signal(SIGUSR2, SIG_IGN);
}
Expand Down Expand Up @@ -815,27 +822,45 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
perf_evlist__enable(rec->evlist);
}

auxtrace_snapshot_enable();
trigger_ready(&auxtrace_snapshot_trigger);
trigger_ready(&switch_output_trigger);
for (;;) {
unsigned long long hits = rec->samples;

if (record__mmap_read_all(rec) < 0) {
auxtrace_snapshot_disable();
trigger_error(&auxtrace_snapshot_trigger);
trigger_error(&switch_output_trigger);
err = -1;
goto out_child;
}

if (auxtrace_record__snapshot_started) {
auxtrace_record__snapshot_started = 0;
if (!auxtrace_snapshot_err)
if (!trigger_is_error(&auxtrace_snapshot_trigger))
record__read_auxtrace_snapshot(rec);
if (auxtrace_snapshot_err) {
if (trigger_is_error(&auxtrace_snapshot_trigger)) {
pr_err("AUX area tracing snapshot failed\n");
err = -1;
goto out_child;
}
}

if (trigger_is_hit(&switch_output_trigger)) {
trigger_ready(&switch_output_trigger);

if (!quiet)
fprintf(stderr, "[ perf record: dump data: Woken up %ld times ]\n",
waking);
waking = 0;
fd = record__switch_output(rec, false);
if (fd < 0) {
pr_err("Failed to switch to new file\n");
trigger_error(&switch_output_trigger);
err = fd;
goto out_child;
}
}

if (hits == rec->samples) {
if (done || draining)
break;
Expand All @@ -858,12 +883,13 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
* disable events in this case.
*/
if (done && !disabled && !target__none(&opts->target)) {
auxtrace_snapshot_disable();
trigger_off(&auxtrace_snapshot_trigger);
perf_evlist__disable(rec->evlist);
disabled = true;
}
}
auxtrace_snapshot_disable();
trigger_off(&auxtrace_snapshot_trigger);
trigger_off(&switch_output_trigger);

if (forks && workload_exec_errno) {
char msg[STRERR_BUFSIZE];
Expand Down Expand Up @@ -1297,6 +1323,8 @@ struct option __record_options[] = {
"Record build-id of all DSOs regardless of hits"),
OPT_BOOLEAN(0, "timestamp-filename", &record.timestamp_filename,
"append timestamp to output filename"),
OPT_BOOLEAN(0, "switch-output", &record.switch_output,
"Switch output when receive SIGUSR2"),
OPT_END()
};

Expand Down Expand Up @@ -1352,6 +1380,9 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
return -EINVAL;
}

if (rec->switch_output)
rec->timestamp_filename = true;

if (!rec->itr) {
rec->itr = auxtrace_record__init(rec->evlist, &err);
if (err)
Expand Down Expand Up @@ -1385,8 +1416,36 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
"If some relocation was applied (e.g. kexec) symbols may be misresolved\n"
"even with a suitable vmlinux or kallsyms file.\n\n");

if (rec->no_buildid_cache || rec->no_buildid)
if (rec->no_buildid_cache || rec->no_buildid) {
disable_buildid_cache();
} else if (rec->switch_output) {
/*
* In 'perf record --switch-output', disable buildid
* generation by default to reduce data file switching
* overhead. Still generate buildid if they are required
* explicitly using
*
* perf record --signal-trigger --no-no-buildid \
* --no-no-buildid-cache
*
* Following code equals to:
*
* if ((rec->no_buildid || !rec->no_buildid_set) &&
* (rec->no_buildid_cache || !rec->no_buildid_cache_set))
* disable_buildid_cache();
*/
bool disable = true;

if (rec->no_buildid_set && !rec->no_buildid)
disable = false;
if (rec->no_buildid_cache_set && !rec->no_buildid_cache)
disable = false;
if (disable) {
rec->no_buildid = true;
rec->no_buildid_cache = true;
disable_buildid_cache();
}
}

if (rec->evlist->nr_entries == 0 &&
perf_evlist__add_default(rec->evlist) < 0) {
Expand Down Expand Up @@ -1445,9 +1504,13 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)

static void snapshot_sig_handler(int sig __maybe_unused)
{
if (!auxtrace_snapshot_is_enabled())
return;
auxtrace_snapshot_disable();
auxtrace_snapshot_err = auxtrace_record__snapshot_start(record.itr);
auxtrace_record__snapshot_started = 1;
if (trigger_is_ready(&auxtrace_snapshot_trigger)) {
trigger_hit(&auxtrace_snapshot_trigger);
auxtrace_record__snapshot_started = 1;
if (auxtrace_record__snapshot_start(record.itr))
trigger_error(&auxtrace_snapshot_trigger);
}

if (trigger_is_ready(&switch_output_trigger))
trigger_hit(&switch_output_trigger);
}
Loading

0 comments on commit 03d85a6

Please sign in to comment.