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

Commit a8bb559b authored by Namhyung Kim's avatar Namhyung Kim Committed by Arnaldo Carvalho de Melo
Browse files

perf header: Add HEADER_GROUP_DESC feature



Save group relationship information so that it can be restored when perf
report is running.

Signed-off-by: default avatarNamhyung Kim <namhyung@kernel.org>
Acked-by: default avatarJiri Olsa <jolsa@redhat.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/r/1358845787-1350-4-git-send-email-namhyung@kernel.org


Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 8d7d8474
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -486,6 +486,9 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
		goto out_delete_session;
	}

	if (!evsel_list->nr_groups)
		perf_header__clear_feat(&session->header, HEADER_GROUP_DESC);

	/*
	 * perf_session__delete(session) will be called at perf_record__exit()
	 */
+164 −0
Original line number Diff line number Diff line
@@ -1084,6 +1084,52 @@ static int write_pmu_mappings(int fd, struct perf_header *h __maybe_unused,
	return 0;
}

/*
 * File format:
 *
 * struct group_descs {
 *	u32	nr_groups;
 *	struct group_desc {
 *		char	name[];
 *		u32	leader_idx;
 *		u32	nr_members;
 *	}[nr_groups];
 * };
 */
static int write_group_desc(int fd, struct perf_header *h __maybe_unused,
			    struct perf_evlist *evlist)
{
	u32 nr_groups = evlist->nr_groups;
	struct perf_evsel *evsel;
	int ret;

	ret = do_write(fd, &nr_groups, sizeof(nr_groups));
	if (ret < 0)
		return ret;

	list_for_each_entry(evsel, &evlist->entries, node) {
		if (perf_evsel__is_group_leader(evsel) &&
		    evsel->nr_members > 1) {
			const char *name = evsel->group_name ?: "{anon_group}";
			u32 leader_idx = evsel->idx;
			u32 nr_members = evsel->nr_members;

			ret = do_write_string(fd, name);
			if (ret < 0)
				return ret;

			ret = do_write(fd, &leader_idx, sizeof(leader_idx));
			if (ret < 0)
				return ret;

			ret = do_write(fd, &nr_members, sizeof(nr_members));
			if (ret < 0)
				return ret;
		}
	}
	return 0;
}

/*
 * default get_cpuid(): nothing gets recorded
 * actual implementation must be in arch/$(ARCH)/util/header.c
@@ -1447,6 +1493,31 @@ static void print_pmu_mappings(struct perf_header *ph, int fd __maybe_unused,
	fprintf(fp, "# pmu mappings: unable to read\n");
}

static void print_group_desc(struct perf_header *ph, int fd __maybe_unused,
			     FILE *fp)
{
	struct perf_session *session;
	struct perf_evsel *evsel;
	u32 nr = 0;

	session = container_of(ph, struct perf_session, header);

	list_for_each_entry(evsel, &session->evlist->entries, node) {
		if (perf_evsel__is_group_leader(evsel) &&
		    evsel->nr_members > 1) {
			fprintf(fp, "# group: %s{%s", evsel->group_name ?: "",
				perf_evsel__name(evsel));

			nr = evsel->nr_members - 1;
		} else if (nr) {
			fprintf(fp, ",%s", perf_evsel__name(evsel));

			if (--nr == 0)
				fprintf(fp, "}\n");
		}
	}
}

static int __event_process_build_id(struct build_id_event *bev,
				    char *filename,
				    struct perf_session *session)
@@ -1961,6 +2032,98 @@ static int process_pmu_mappings(struct perf_file_section *section __maybe_unused
	return -1;
}

static int process_group_desc(struct perf_file_section *section __maybe_unused,
			      struct perf_header *ph, int fd,
			      void *data __maybe_unused)
{
	size_t ret = -1;
	u32 i, nr, nr_groups;
	struct perf_session *session;
	struct perf_evsel *evsel, *leader = NULL;
	struct group_desc {
		char *name;
		u32 leader_idx;
		u32 nr_members;
	} *desc;

	if (readn(fd, &nr_groups, sizeof(nr_groups)) != sizeof(nr_groups))
		return -1;

	if (ph->needs_swap)
		nr_groups = bswap_32(nr_groups);

	ph->env.nr_groups = nr_groups;
	if (!nr_groups) {
		pr_debug("group desc not available\n");
		return 0;
	}

	desc = calloc(nr_groups, sizeof(*desc));
	if (!desc)
		return -1;

	for (i = 0; i < nr_groups; i++) {
		desc[i].name = do_read_string(fd, ph);
		if (!desc[i].name)
			goto out_free;

		if (readn(fd, &desc[i].leader_idx, sizeof(u32)) != sizeof(u32))
			goto out_free;

		if (readn(fd, &desc[i].nr_members, sizeof(u32)) != sizeof(u32))
			goto out_free;

		if (ph->needs_swap) {
			desc[i].leader_idx = bswap_32(desc[i].leader_idx);
			desc[i].nr_members = bswap_32(desc[i].nr_members);
		}
	}

	/*
	 * Rebuild group relationship based on the group_desc
	 */
	session = container_of(ph, struct perf_session, header);
	session->evlist->nr_groups = nr_groups;

	i = nr = 0;
	list_for_each_entry(evsel, &session->evlist->entries, node) {
		if (evsel->idx == (int) desc[i].leader_idx) {
			evsel->leader = evsel;
			/* {anon_group} is a dummy name */
			if (strcmp(desc[i].name, "{anon_group}"))
				evsel->group_name = desc[i].name;
			evsel->nr_members = desc[i].nr_members;

			if (i >= nr_groups || nr > 0) {
				pr_debug("invalid group desc\n");
				goto out_free;
			}

			leader = evsel;
			nr = evsel->nr_members - 1;
			i++;
		} else if (nr) {
			/* This is a group member */
			evsel->leader = leader;

			nr--;
		}
	}

	if (i != nr_groups || nr != 0) {
		pr_debug("invalid group desc\n");
		goto out_free;
	}

	ret = 0;
out_free:
	while ((int) --i >= 0)
		free(desc[i].name);
	free(desc);

	return ret;
}

struct feature_ops {
	int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist);
	void (*print)(struct perf_header *h, int fd, FILE *fp);
@@ -2000,6 +2163,7 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = {
	FEAT_OPF(HEADER_NUMA_TOPOLOGY,	numa_topology),
	FEAT_OPA(HEADER_BRANCH_STACK,	branch_stack),
	FEAT_OPP(HEADER_PMU_MAPPINGS,	pmu_mappings),
	FEAT_OPP(HEADER_GROUP_DESC,	group_desc),
};

struct header_print_data {
+2 −0
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ enum {
	HEADER_NUMA_TOPOLOGY,
	HEADER_BRANCH_STACK,
	HEADER_PMU_MAPPINGS,
	HEADER_GROUP_DESC,
	HEADER_LAST_FEATURE,
	HEADER_FEAT_BITS	= 256,
};
@@ -79,6 +80,7 @@ struct perf_session_env {
	char			*numa_nodes;
	int			nr_pmu_mappings;
	char			*pmu_mappings;
	int			nr_groups;
};

struct perf_header {