Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 03d85a63 authored by Ingo Molnar's avatar Ingo Molnar
Browse files

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

Merge tag 'perf-core-for-mingo-20160429' 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:

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: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parents 3521ba1c ca7ce82a
Loading
Loading
Loading
Loading
+1 −2
Original line number Original line Diff line number Diff line
@@ -27,10 +27,9 @@ int main(void)
	attr.log_level = 0;
	attr.log_level = 0;
	attr.kern_version = 0;
	attr.kern_version = 0;


	attr = attr;
	/*
	/*
	 * Test existence of __NR_bpf and BPF_PROG_LOAD.
	 * Test existence of __NR_bpf and BPF_PROG_LOAD.
	 * This call should fail if we run the testcase.
	 * 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 −0
Original line number Original line Diff line number Diff line
@@ -347,6 +347,19 @@ Configure all used events to run in kernel space.
--all-user::
--all-user::
Configure all used events to run in user space.
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
SEE ALSO
--------
--------
linkperf:perf-stat[1], linkperf:perf-list[1]
linkperf:perf-stat[1], linkperf:perf-list[1]
+118 −55
Original line number Original line Diff line number Diff line
@@ -34,6 +34,7 @@
#include "util/parse-regs-options.h"
#include "util/parse-regs-options.h"
#include "util/llvm-utils.h"
#include "util/llvm-utils.h"
#include "util/bpf-loader.h"
#include "util/bpf-loader.h"
#include "util/trigger.h"
#include "asm/bug.h"
#include "asm/bug.h"


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


@@ -127,44 +129,9 @@ static volatile int done;
static volatile int signr = -1;
static volatile int signr = -1;
static volatile int child_finished;
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 volatile int auxtrace_record__snapshot_started;
static DEFINE_TRIGGER(auxtrace_snapshot_trigger);
static DEFINE_TRIGGER(switch_output_trigger);


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


@@ -532,6 +500,25 @@ record__finish_output(struct record *rec)
	return;
	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
static int
record__switch_output(struct record *rec, bool at_exit)
record__switch_output(struct record *rec, bool at_exit)
{
{
@@ -560,6 +547,23 @@ record__switch_output(struct record *rec, bool at_exit)
	if (!quiet)
	if (!quiet)
		fprintf(stderr, "[ perf record: Dump %s.%s ]\n",
		fprintf(stderr, "[ perf record: Dump %s.%s ]\n",
			file->path, timestamp);
			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;
	return fd;
}
}


@@ -684,9 +688,12 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
	signal(SIGINT, sig_handler);
	signal(SIGINT, sig_handler);
	signal(SIGTERM, 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);
		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 {
	} else {
		signal(SIGUSR2, SIG_IGN);
		signal(SIGUSR2, SIG_IGN);
	}
	}
@@ -815,27 +822,45 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
		perf_evlist__enable(rec->evlist);
		perf_evlist__enable(rec->evlist);
	}
	}


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


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


		if (auxtrace_record__snapshot_started) {
		if (auxtrace_record__snapshot_started) {
			auxtrace_record__snapshot_started = 0;
			auxtrace_record__snapshot_started = 0;
			if (!auxtrace_snapshot_err)
			if (!trigger_is_error(&auxtrace_snapshot_trigger))
				record__read_auxtrace_snapshot(rec);
				record__read_auxtrace_snapshot(rec);
			if (auxtrace_snapshot_err) {
			if (trigger_is_error(&auxtrace_snapshot_trigger)) {
				pr_err("AUX area tracing snapshot failed\n");
				pr_err("AUX area tracing snapshot failed\n");
				err = -1;
				err = -1;
				goto out_child;
				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 (hits == rec->samples) {
			if (done || draining)
			if (done || draining)
				break;
				break;
@@ -858,12 +883,13 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
		 * disable events in this case.
		 * disable events in this case.
		 */
		 */
		if (done && !disabled && !target__none(&opts->target)) {
		if (done && !disabled && !target__none(&opts->target)) {
			auxtrace_snapshot_disable();
			trigger_off(&auxtrace_snapshot_trigger);
			perf_evlist__disable(rec->evlist);
			perf_evlist__disable(rec->evlist);
			disabled = true;
			disabled = true;
		}
		}
	}
	}
	auxtrace_snapshot_disable();
	trigger_off(&auxtrace_snapshot_trigger);
	trigger_off(&switch_output_trigger);


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


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


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

	if (!rec->itr) {
	if (!rec->itr) {
		rec->itr = auxtrace_record__init(rec->evlist, &err);
		rec->itr = auxtrace_record__init(rec->evlist, &err);
		if (err)
		if (err)
@@ -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"
"If some relocation was applied (e.g. kexec) symbols may be misresolved\n"
"even with a suitable vmlinux or kallsyms file.\n\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();
			disable_buildid_cache();
		}
	}


	if (rec->evlist->nr_entries == 0 &&
	if (rec->evlist->nr_entries == 0 &&
	    perf_evlist__add_default(rec->evlist) < 0) {
	    perf_evlist__add_default(rec->evlist) < 0) {
@@ -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)
static void snapshot_sig_handler(int sig __maybe_unused)
{
{
	if (!auxtrace_snapshot_is_enabled())
	if (trigger_is_ready(&auxtrace_snapshot_trigger)) {
		return;
		trigger_hit(&auxtrace_snapshot_trigger);
	auxtrace_snapshot_disable();
	auxtrace_snapshot_err = auxtrace_record__snapshot_start(record.itr);
		auxtrace_record__snapshot_started = 1;
		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);
}
}
+1 −61
Original line number Original line Diff line number Diff line
@@ -52,10 +52,6 @@
# define O_CLOEXEC		02000000
# define O_CLOEXEC		02000000
#endif
#endif


#ifndef MSG_CMSG_CLOEXEC
# define MSG_CMSG_CLOEXEC	0x40000000
#endif

struct trace {
struct trace {
	struct perf_tool	tool;
	struct perf_tool	tool;
	struct syscalltbl	*sctbl;
	struct syscalltbl	*sctbl;
@@ -513,63 +509,6 @@ static const char *socket_families[] = {
};
};
static DEFINE_STRARRAY(socket_families);
static DEFINE_STRARRAY(socket_families);


#ifndef MSG_PROBE
#define MSG_PROBE	     0x10
#endif
#ifndef MSG_WAITFORONE
#define MSG_WAITFORONE	0x10000
#endif
#ifndef MSG_SENDPAGE_NOTLAST
#define MSG_SENDPAGE_NOTLAST 0x20000
#endif
#ifndef MSG_FASTOPEN
#define MSG_FASTOPEN	     0x20000000
#endif

static size_t syscall_arg__scnprintf_msg_flags(char *bf, size_t size,
					       struct syscall_arg *arg)
{
	int printed = 0, flags = arg->val;

	if (flags == 0)
		return scnprintf(bf, size, "NONE");
#define	P_MSG_FLAG(n) \
	if (flags & MSG_##n) { \
		printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \
		flags &= ~MSG_##n; \
	}

	P_MSG_FLAG(OOB);
	P_MSG_FLAG(PEEK);
	P_MSG_FLAG(DONTROUTE);
	P_MSG_FLAG(TRYHARD);
	P_MSG_FLAG(CTRUNC);
	P_MSG_FLAG(PROBE);
	P_MSG_FLAG(TRUNC);
	P_MSG_FLAG(DONTWAIT);
	P_MSG_FLAG(EOR);
	P_MSG_FLAG(WAITALL);
	P_MSG_FLAG(FIN);
	P_MSG_FLAG(SYN);
	P_MSG_FLAG(CONFIRM);
	P_MSG_FLAG(RST);
	P_MSG_FLAG(ERRQUEUE);
	P_MSG_FLAG(NOSIGNAL);
	P_MSG_FLAG(MORE);
	P_MSG_FLAG(WAITFORONE);
	P_MSG_FLAG(SENDPAGE_NOTLAST);
	P_MSG_FLAG(FASTOPEN);
	P_MSG_FLAG(CMSG_CLOEXEC);
#undef P_MSG_FLAG

	if (flags)
		printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags);

	return printed;
}

#define SCA_MSG_FLAGS syscall_arg__scnprintf_msg_flags

static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size,
						 struct syscall_arg *arg)
						 struct syscall_arg *arg)
{
{
@@ -850,6 +789,7 @@ static size_t syscall_arg__scnprintf_getrandom_flags(char *bf, size_t size,
#include "trace/beauty/pid.c"
#include "trace/beauty/pid.c"
#include "trace/beauty/mmap.c"
#include "trace/beauty/mmap.c"
#include "trace/beauty/mode_t.c"
#include "trace/beauty/mode_t.c"
#include "trace/beauty/msg_flags.c"
#include "trace/beauty/perf_event_open.c"
#include "trace/beauty/perf_event_open.c"
#include "trace/beauty/sched_policy.c"
#include "trace/beauty/sched_policy.c"
#include "trace/beauty/socket_type.c"
#include "trace/beauty/socket_type.c"
+1 −1
Original line number Original line Diff line number Diff line
@@ -202,7 +202,7 @@ static int dsos__create(int cnt, int size)
{
{
	int i;
	int i;


	dsos = malloc(sizeof(dsos) * cnt);
	dsos = malloc(sizeof(*dsos) * cnt);
	TEST_ASSERT_VAL("failed to alloc dsos array", dsos);
	TEST_ASSERT_VAL("failed to alloc dsos array", dsos);


	for (i = 0; i < cnt; i++) {
	for (i = 0; i < cnt; i++) {
Loading