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

Commit 9db55064 authored by Ingo Molnar's avatar Ingo Molnar
Browse files

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

Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux

 into perf/core

Pull perf/core improvements from Arnaldo Carvalho de Melo:

 * perf inject changes to allow showing where a task sleeps, from Andrew Vagin.

 * Makefile improvements from Namhyung Kim.

 * Add --pre and --post command hooks in 'stat', from Peter Zijlstra.

Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parents 8f7c1d07 1f16c575
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -253,7 +253,7 @@ all_deps := $(all_objs:%.o=.%.d)
# let .d file also depends on the source and header files
define check_deps
		@set -e; $(RM) $@; \
		$(CC) -M $(CFLAGS) $< > $@.$$$$; \
		$(CC) -MM $(CFLAGS) $< > $@.$$$$; \
		sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
		$(RM) $@.$$$$
endef
+11 −0
Original line number Diff line number Diff line
@@ -29,6 +29,17 @@ OPTIONS
-v::
--verbose::
	Be more verbose.
-i::
--input=::
	Input file name. (default: stdin)
-o::
--output=::
	Output file name. (default: stdout)
-s::
--sched-stat::
	Merge sched_stat and sched_switch for getting events where and how long
	tasks slept. sched_switch contains a callchain where a task slept and
	sched_stat contains a timeslice how long a task slept.

SEE ALSO
--------
+5 −0
Original line number Diff line number Diff line
@@ -108,6 +108,11 @@ with it. --append may be used here. Examples:
     3>results  perf stat --log-fd 3          -- $cmd
     3>>results perf stat --log-fd 3 --append -- $cmd

--pre::
--post::
	Pre and post measurement hooks, e.g.:

perf stat --repeat 10 --null --sync --pre 'make -s O=defconfig-build/clean' -- make -s -j64 O=defconfig-build/ bzImage


EXAMPLES
+12 −39
Original line number Diff line number Diff line
@@ -541,7 +541,8 @@ LIB_OBJS += $(OUTPUT)util/symbol-minimal.o
else # NO_LIBELF
BASIC_CFLAGS += -DLIBELF_SUPPORT

ifeq ($(call try-cc,$(SOURCE_ELF_MMAP),$(FLAGS_COMMON),-DLIBELF_MMAP),y)
FLAGS_LIBELF=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS)
ifeq ($(call try-cc,$(SOURCE_ELF_MMAP),$(FLAGS_LIBELF),-DLIBELF_MMAP),y)
	BASIC_CFLAGS += -DLIBELF_MMAP
endif

@@ -977,20 +978,15 @@ help:
	@echo 'Perf maintainer targets:'
	@echo '  clean			- clean all binary objects and build output'

doc:
	$(MAKE) -C Documentation all

man:
	$(MAKE) -C Documentation man

html:
	$(MAKE) -C Documentation html
DOC_TARGETS := doc man html info pdf

info:
	$(MAKE) -C Documentation info
INSTALL_DOC_TARGETS := $(patsubst %,install-%,$(DOC_TARGETS)) try-install-man
INSTALL_DOC_TARGETS += quick-install-doc quick-install-man quick-install-html

pdf:
	$(MAKE) -C Documentation pdf
# 'make doc' should call 'make -C Documentation all'
$(DOC_TARGETS):
	$(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) $(@:doc=all)

TAGS:
	$(RM) TAGS
@@ -1061,32 +1057,9 @@ install: all try-install-man
install-python_ext:
	$(PYTHON_WORD) util/setup.py --quiet install --root='/$(DESTDIR_SQ)'

install-doc:
	$(MAKE) -C Documentation install

install-man:
	$(MAKE) -C Documentation install-man

try-install-man:
	$(MAKE) -C Documentation try-install-man

install-html:
	$(MAKE) -C Documentation install-html

install-info:
	$(MAKE) -C Documentation install-info

install-pdf:
	$(MAKE) -C Documentation install-pdf

quick-install-doc:
	$(MAKE) -C Documentation quick-install

quick-install-man:
	$(MAKE) -C Documentation quick-install-man

quick-install-html:
	$(MAKE) -C Documentation quick-install-html
# 'make install-doc' should call 'make -C Documentation install'
$(INSTALL_DOC_TARGETS):
	$(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) $(@:-doc=)

### Cleaning rules

@@ -1094,7 +1067,7 @@ clean: $(LIBTRACEEVENT)-clean
	$(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf.o $(LANG_BINDINGS)
	$(RM) $(ALL_PROGRAMS) perf
	$(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope*
	$(MAKE) -C Documentation/ clean
	$(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean
	$(RM) $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS
	$(RM) $(OUTPUT)util/*-bison*
	$(RM) $(OUTPUT)util/*-flex*
+181 −8
Original line number Diff line number Diff line
@@ -8,33 +8,53 @@
#include "builtin.h"

#include "perf.h"
#include "util/color.h"
#include "util/evlist.h"
#include "util/evsel.h"
#include "util/session.h"
#include "util/tool.h"
#include "util/debug.h"
#include "util/build-id.h"

#include "util/parse-options.h"

#include <linux/list.h>

struct perf_inject {
	struct perf_tool tool;
	bool		 build_ids;
	bool		 sched_stat;
	const char	 *input_name;
	int		 pipe_output,
			 output;
	u64		 bytes_written;
	struct list_head samples;
};

struct event_entry {
	struct list_head node;
	u32		 tid;
	union perf_event event[0];
};

static int perf_event__repipe_synth(struct perf_tool *tool __maybe_unused,
static int perf_event__repipe_synth(struct perf_tool *tool,
				    union perf_event *event,
				    struct machine *machine __maybe_unused)
{
	struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
	uint32_t size;
	void *buf = event;

	size = event->header.size;

	while (size) {
		int ret = write(STDOUT_FILENO, buf, size);
		int ret = write(inject->output, buf, size);
		if (ret < 0)
			return -errno;

		size -= ret;
		buf += ret;
		inject->bytes_written += ret;
	}

	return 0;
@@ -80,12 +100,25 @@ static int perf_event__repipe(struct perf_tool *tool,
	return perf_event__repipe_synth(tool, event, machine);
}

typedef int (*inject_handler)(struct perf_tool *tool,
			      union perf_event *event,
			      struct perf_sample *sample,
			      struct perf_evsel *evsel,
			      struct machine *machine);

static int perf_event__repipe_sample(struct perf_tool *tool,
				     union perf_event *event,
			      struct perf_sample *sample __maybe_unused,
			      struct perf_evsel *evsel __maybe_unused,
				     struct perf_sample *sample,
				     struct perf_evsel *evsel,
				     struct machine *machine)
{
	if (evsel->handler.func) {
		inject_handler f = evsel->handler.func;
		return f(tool, event, sample, evsel, machine);
	}

	build_id__mark_dso_hit(tool, event, sample, evsel, machine);

	return perf_event__repipe_synth(tool, event, machine);
}

@@ -210,6 +243,80 @@ static int perf_event__inject_buildid(struct perf_tool *tool,
	return 0;
}

static int perf_inject__sched_process_exit(struct perf_tool *tool,
					   union perf_event *event __maybe_unused,
					   struct perf_sample *sample,
					   struct perf_evsel *evsel __maybe_unused,
					   struct machine *machine __maybe_unused)
{
	struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
	struct event_entry *ent;

	list_for_each_entry(ent, &inject->samples, node) {
		if (sample->tid == ent->tid) {
			list_del_init(&ent->node);
			free(ent);
			break;
		}
	}

	return 0;
}

static int perf_inject__sched_switch(struct perf_tool *tool,
				     union perf_event *event,
				     struct perf_sample *sample,
				     struct perf_evsel *evsel,
				     struct machine *machine)
{
	struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
	struct event_entry *ent;

	perf_inject__sched_process_exit(tool, event, sample, evsel, machine);

	ent = malloc(event->header.size + sizeof(struct event_entry));
	if (ent == NULL) {
		color_fprintf(stderr, PERF_COLOR_RED,
			     "Not enough memory to process sched switch event!");
		return -1;
	}

	ent->tid = sample->tid;
	memcpy(&ent->event, event, event->header.size);
	list_add(&ent->node, &inject->samples);
	return 0;
}

static int perf_inject__sched_stat(struct perf_tool *tool,
				   union perf_event *event __maybe_unused,
				   struct perf_sample *sample,
				   struct perf_evsel *evsel,
				   struct machine *machine)
{
	struct event_entry *ent;
	union perf_event *event_sw;
	struct perf_sample sample_sw;
	struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
	u32 pid = perf_evsel__intval(evsel, sample, "pid");

	list_for_each_entry(ent, &inject->samples, node) {
		if (pid == ent->tid)
			goto found;
	}

	return 0;
found:
	event_sw = &ent->event[0];
	perf_evsel__parse_sample(evsel, event_sw, &sample_sw);

	sample_sw.period = sample->period;
	sample_sw.time	 = sample->time;
	perf_event__synthesize_sample(event_sw, evsel->attr.sample_type,
				      &sample_sw, false);
	build_id__mark_dso_hit(tool, event_sw, &sample_sw, evsel, machine);
	return perf_event__repipe(tool, event_sw, &sample_sw, machine);
}

extern volatile int session_done;

static void sig_handler(int sig __maybe_unused)
@@ -217,6 +324,21 @@ static void sig_handler(int sig __maybe_unused)
	session_done = 1;
}

static int perf_evsel__check_stype(struct perf_evsel *evsel,
				   u64 sample_type, const char *sample_msg)
{
	struct perf_event_attr *attr = &evsel->attr;
	const char *name = perf_evsel__name(evsel);

	if (!(attr->sample_type & sample_type)) {
		pr_err("Samples for %s event do not have %s attribute set.",
			name, sample_msg);
		return -EINVAL;
	}

	return 0;
}

static int __cmd_inject(struct perf_inject *inject)
{
	struct perf_session *session;
@@ -224,19 +346,48 @@ static int __cmd_inject(struct perf_inject *inject)

	signal(SIGINT, sig_handler);

	if (inject->build_ids) {
		inject->tool.sample	  = perf_event__inject_buildid;
	if (inject->build_ids || inject->sched_stat) {
		inject->tool.mmap	  = perf_event__repipe_mmap;
		inject->tool.fork	  = perf_event__repipe_fork;
		inject->tool.tracing_data = perf_event__repipe_tracing_data;
	}

	session = perf_session__new("-", O_RDONLY, false, true, &inject->tool);
	session = perf_session__new(inject->input_name, O_RDONLY, false, true, &inject->tool);
	if (session == NULL)
		return -ENOMEM;

	if (inject->build_ids) {
		inject->tool.sample = perf_event__inject_buildid;
	} else if (inject->sched_stat) {
		struct perf_evsel *evsel;

		inject->tool.ordered_samples = true;

		list_for_each_entry(evsel, &session->evlist->entries, node) {
			const char *name = perf_evsel__name(evsel);

			if (!strcmp(name, "sched:sched_switch")) {
				if (perf_evsel__check_stype(evsel, PERF_SAMPLE_TID, "TID"))
					return -EINVAL;

				evsel->handler.func = perf_inject__sched_switch;
			} else if (!strcmp(name, "sched:sched_process_exit"))
				evsel->handler.func = perf_inject__sched_process_exit;
			else if (!strncmp(name, "sched:sched_stat_", 17))
				evsel->handler.func = perf_inject__sched_stat;
		}
	}

	if (!inject->pipe_output)
		lseek(inject->output, session->header.data_offset, SEEK_SET);

	ret = perf_session__process_events(session, &inject->tool);

	if (!inject->pipe_output) {
		session->header.data_size = inject->bytes_written;
		perf_session__write_header(session, session->evlist, inject->output, true);
	}

	perf_session__delete(session);

	return ret;
@@ -260,10 +411,20 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
			.tracing_data	= perf_event__repipe_tracing_data_synth,
			.build_id	= perf_event__repipe_op2_synth,
		},
		.input_name  = "-",
		.samples = LIST_HEAD_INIT(inject.samples),
	};
	const char *output_name = "-";
	const struct option options[] = {
		OPT_BOOLEAN('b', "build-ids", &inject.build_ids,
			    "Inject build-ids into the output stream"),
		OPT_STRING('i', "input", &inject.input_name, "file",
			   "input file name"),
		OPT_STRING('o', "output", &output_name, "file",
			   "output file name"),
		OPT_BOOLEAN('s', "sched-stat", &inject.sched_stat,
			    "Merge sched-stat and sched-switch for getting events "
			    "where and how long tasks slept"),
		OPT_INCR('v', "verbose", &verbose,
			 "be more verbose (show build ids, etc)"),
		OPT_END()
@@ -281,6 +442,18 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
	if (argc)
		usage_with_options(inject_usage, options);

	if (!strcmp(output_name, "-")) {
		inject.pipe_output = 1;
		inject.output = STDOUT_FILENO;
	} else {
		inject.output = open(output_name, O_CREAT | O_WRONLY | O_TRUNC,
						  S_IRUSR | S_IWUSR);
		if (inject.output < 0) {
			perror("failed to create output file");
			return -1;
		}
	}

	if (symbol__init() < 0)
		return -1;

Loading