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

Commit 86141027 authored by Ingo Molnar's avatar Ingo Molnar
Browse files

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

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

 into perf/core

Pull perf/core improvements from Arnaldo Carvalho de Melo:

- Create extra kernel maps to help in decoding samples in x86 PTI entry
  trampolines (Adrian Hunter)

- Copy x86 PTI entry trampoline sections in the kcore copy used for
  annotation and intel_pt CPU traces decoding (Adrian Hunter)

- Support 'perf annotate --group' for non-explicit recorded event
  "groups", showing multiple columns, one for each event, just like
  when dealing with explicit event groups (those enclosed with {}) (Jin Yao)

Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parents 2996123e 22916fdb
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -4,6 +4,8 @@ libperf-y += pmu.o
libperf-y += kvm-stat.o
libperf-y += perf_regs.o
libperf-y += group.o
libperf-y += machine.o
libperf-y += event.o

libperf-$(CONFIG_DWARF) += dwarf-regs.o
libperf-$(CONFIG_BPF_PROLOGUE) += dwarf-regs.o
+76 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
#include <linux/types.h>
#include <linux/string.h>

#include "../../util/machine.h"
#include "../../util/tool.h"
#include "../../util/map.h"
#include "../../util/util.h"
#include "../../util/debug.h"

#if defined(__x86_64__)

int perf_event__synthesize_extra_kmaps(struct perf_tool *tool,
				       perf_event__handler_t process,
				       struct machine *machine)
{
	int rc = 0;
	struct map *pos;
	struct map_groups *kmaps = &machine->kmaps;
	struct maps *maps = &kmaps->maps;
	union perf_event *event = zalloc(sizeof(event->mmap) +
					 machine->id_hdr_size);

	if (!event) {
		pr_debug("Not enough memory synthesizing mmap event "
			 "for extra kernel maps\n");
		return -1;
	}

	for (pos = maps__first(maps); pos; pos = map__next(pos)) {
		struct kmap *kmap;
		size_t size;

		if (!__map__is_extra_kernel_map(pos))
			continue;

		kmap = map__kmap(pos);

		size = sizeof(event->mmap) - sizeof(event->mmap.filename) +
		       PERF_ALIGN(strlen(kmap->name) + 1, sizeof(u64)) +
		       machine->id_hdr_size;

		memset(event, 0, size);

		event->mmap.header.type = PERF_RECORD_MMAP;

		/*
		 * kernel uses 0 for user space maps, see kernel/perf_event.c
		 * __perf_event_mmap
		 */
		if (machine__is_host(machine))
			event->header.misc = PERF_RECORD_MISC_KERNEL;
		else
			event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL;

		event->mmap.header.size = size;

		event->mmap.start = pos->start;
		event->mmap.len   = pos->end - pos->start;
		event->mmap.pgoff = pos->pgoff;
		event->mmap.pid   = machine->pid;

		strlcpy(event->mmap.filename, kmap->name, PATH_MAX);

		if (perf_tool__process_synth_event(tool, event, machine,
						   process) != 0) {
			rc = -1;
			break;
		}
	}

	free(event);
	return rc;
}

#endif
+103 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
#include <linux/types.h>
#include <linux/string.h>
#include <stdlib.h>

#include "../../util/machine.h"
#include "../../util/map.h"
#include "../../util/symbol.h"
#include "../../util/sane_ctype.h"

#include <symbol/kallsyms.h>

#if defined(__x86_64__)

struct extra_kernel_map_info {
	int cnt;
	int max_cnt;
	struct extra_kernel_map *maps;
	bool get_entry_trampolines;
	u64 entry_trampoline;
};

static int add_extra_kernel_map(struct extra_kernel_map_info *mi, u64 start,
				u64 end, u64 pgoff, const char *name)
{
	if (mi->cnt >= mi->max_cnt) {
		void *buf;
		size_t sz;

		mi->max_cnt = mi->max_cnt ? mi->max_cnt * 2 : 32;
		sz = sizeof(struct extra_kernel_map) * mi->max_cnt;
		buf = realloc(mi->maps, sz);
		if (!buf)
			return -1;
		mi->maps = buf;
	}

	mi->maps[mi->cnt].start = start;
	mi->maps[mi->cnt].end   = end;
	mi->maps[mi->cnt].pgoff = pgoff;
	strlcpy(mi->maps[mi->cnt].name, name, KMAP_NAME_LEN);

	mi->cnt += 1;

	return 0;
}

static int find_extra_kernel_maps(void *arg, const char *name, char type,
				  u64 start)
{
	struct extra_kernel_map_info *mi = arg;

	if (!mi->entry_trampoline && kallsyms2elf_binding(type) == STB_GLOBAL &&
	    !strcmp(name, "_entry_trampoline")) {
		mi->entry_trampoline = start;
		return 0;
	}

	if (is_entry_trampoline(name)) {
		u64 end = start + page_size;

		return add_extra_kernel_map(mi, start, end, 0, name);
	}

	return 0;
}

int machine__create_extra_kernel_maps(struct machine *machine,
				      struct dso *kernel)
{
	struct extra_kernel_map_info mi = { .cnt = 0, };
	char filename[PATH_MAX];
	int ret;
	int i;

	machine__get_kallsyms_filename(machine, filename, PATH_MAX);

	if (symbol__restricted_filename(filename, "/proc/kallsyms"))
		return 0;

	ret = kallsyms__parse(filename, &mi, find_extra_kernel_maps);
	if (ret)
		goto out_free;

	if (!mi.entry_trampoline)
		goto out_free;

	for (i = 0; i < mi.cnt; i++) {
		struct extra_kernel_map *xm = &mi.maps[i];

		xm->pgoff = mi.entry_trampoline;
		ret = machine__create_extra_kernel_map(machine, kernel, xm);
		if (ret)
			goto out_free;
	}

	machine->trampolines_mapped = mi.cnt;
out_free:
	free(mi.maps);
	return ret;
}

#endif
+7 −0
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@ struct perf_annotate {
	bool	   print_line;
	bool	   skip_missing;
	bool	   has_br_stack;
	bool	   group_set;
	const char *sym_hist_filter;
	const char *cpu_list;
	DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
@@ -508,6 +509,9 @@ int cmd_annotate(int argc, const char **argv)
		    "Don't shorten the displayed pathnames"),
	OPT_BOOLEAN(0, "skip-missing", &annotate.skip_missing,
		    "Skip symbols that cannot be annotated"),
	OPT_BOOLEAN_SET(0, "group", &symbol_conf.event_group,
			&annotate.group_set,
			"Show event group information together"),
	OPT_STRING('C', "cpu", &annotate.cpu_list, "cpu", "list of cpus to profile"),
	OPT_CALLBACK(0, "symfs", NULL, "directory",
		     "Look for files with symbols relative to this directory",
@@ -570,6 +574,9 @@ int cmd_annotate(int argc, const char **argv)
	annotate.has_br_stack = perf_header__has_feat(&annotate.session->header,
						      HEADER_BRANCH_STACK);

	if (annotate.group_set)
		perf_evlist__force_leader(annotate.session->evlist);

	ret = symbol__annotation_init();
	if (ret < 0)
		goto out_delete;
+2 −11
Original line number Diff line number Diff line
@@ -194,20 +194,11 @@ static int hist_iter__branch_callback(struct hist_entry_iter *iter,
	return err;
}

/*
 * Events in data file are not collect in groups, but we still want
 * the group display. Set the artificial group and set the leader's
 * forced_leader flag to notify the display code.
 */
static void setup_forced_leader(struct report *report,
				struct perf_evlist *evlist)
{
	if (report->group_set && !evlist->nr_groups) {
		struct perf_evsel *leader = perf_evlist__first(evlist);

		perf_evlist__set_leader(evlist);
		leader->forced_leader = true;
	}
	if (report->group_set)
		perf_evlist__force_leader(evlist);
}

static int process_feature_event(struct perf_tool *tool,
Loading