aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorNamhyung Kim <namhyung.kim@lge.com>2013-01-22 04:09:31 -0500
committerArnaldo Carvalho de Melo <acme@redhat.com>2013-01-31 11:07:44 -0500
commita8bb559bd4eff5c71601e2e61a4bd1deef44a03c (patch)
tree2e1f82e4e6024aa66e10b7a73241ff25e0d10105 /tools
parent8d7d8474d7b04dc89aa653d67425b61d3ff5c6f0 (diff)
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: Namhyung Kim <namhyung@kernel.org> Acked-by: Jiri 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: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools')
-rw-r--r--tools/perf/builtin-record.c3
-rw-r--r--tools/perf/util/header.c164
-rw-r--r--tools/perf/util/header.h2
3 files changed, 169 insertions, 0 deletions
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 2ac690cad411..774c90713a53 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -486,6 +486,9 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
486 goto out_delete_session; 486 goto out_delete_session;
487 } 487 }
488 488
489 if (!evsel_list->nr_groups)
490 perf_header__clear_feat(&session->header, HEADER_GROUP_DESC);
491
489 /* 492 /*
490 * perf_session__delete(session) will be called at perf_record__exit() 493 * perf_session__delete(session) will be called at perf_record__exit()
491 */ 494 */
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index f6081cb3fca3..8022b5254f75 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -1085,6 +1085,52 @@ static int write_pmu_mappings(int fd, struct perf_header *h __maybe_unused,
1085} 1085}
1086 1086
1087/* 1087/*
1088 * File format:
1089 *
1090 * struct group_descs {
1091 * u32 nr_groups;
1092 * struct group_desc {
1093 * char name[];
1094 * u32 leader_idx;
1095 * u32 nr_members;
1096 * }[nr_groups];
1097 * };
1098 */
1099static int write_group_desc(int fd, struct perf_header *h __maybe_unused,
1100 struct perf_evlist *evlist)
1101{
1102 u32 nr_groups = evlist->nr_groups;
1103 struct perf_evsel *evsel;
1104 int ret;
1105
1106 ret = do_write(fd, &nr_groups, sizeof(nr_groups));
1107 if (ret < 0)
1108 return ret;
1109
1110 list_for_each_entry(evsel, &evlist->entries, node) {
1111 if (perf_evsel__is_group_leader(evsel) &&
1112 evsel->nr_members > 1) {
1113 const char *name = evsel->group_name ?: "{anon_group}";
1114 u32 leader_idx = evsel->idx;
1115 u32 nr_members = evsel->nr_members;
1116
1117 ret = do_write_string(fd, name);
1118 if (ret < 0)
1119 return ret;
1120
1121 ret = do_write(fd, &leader_idx, sizeof(leader_idx));
1122 if (ret < 0)
1123 return ret;
1124
1125 ret = do_write(fd, &nr_members, sizeof(nr_members));
1126 if (ret < 0)
1127 return ret;
1128 }
1129 }
1130 return 0;
1131}
1132
1133/*
1088 * default get_cpuid(): nothing gets recorded 1134 * default get_cpuid(): nothing gets recorded
1089 * actual implementation must be in arch/$(ARCH)/util/header.c 1135 * actual implementation must be in arch/$(ARCH)/util/header.c
1090 */ 1136 */
@@ -1447,6 +1493,31 @@ error:
1447 fprintf(fp, "# pmu mappings: unable to read\n"); 1493 fprintf(fp, "# pmu mappings: unable to read\n");
1448} 1494}
1449 1495
1496static void print_group_desc(struct perf_header *ph, int fd __maybe_unused,
1497 FILE *fp)
1498{
1499 struct perf_session *session;
1500 struct perf_evsel *evsel;
1501 u32 nr = 0;
1502
1503 session = container_of(ph, struct perf_session, header);
1504
1505 list_for_each_entry(evsel, &session->evlist->entries, node) {
1506 if (perf_evsel__is_group_leader(evsel) &&
1507 evsel->nr_members > 1) {
1508 fprintf(fp, "# group: %s{%s", evsel->group_name ?: "",
1509 perf_evsel__name(evsel));
1510
1511 nr = evsel->nr_members - 1;
1512 } else if (nr) {
1513 fprintf(fp, ",%s", perf_evsel__name(evsel));
1514
1515 if (--nr == 0)
1516 fprintf(fp, "}\n");
1517 }
1518 }
1519}
1520
1450static int __event_process_build_id(struct build_id_event *bev, 1521static int __event_process_build_id(struct build_id_event *bev,
1451 char *filename, 1522 char *filename,
1452 struct perf_session *session) 1523 struct perf_session *session)
@@ -1961,6 +2032,98 @@ error:
1961 return -1; 2032 return -1;
1962} 2033}
1963 2034
2035static int process_group_desc(struct perf_file_section *section __maybe_unused,
2036 struct perf_header *ph, int fd,
2037 void *data __maybe_unused)
2038{
2039 size_t ret = -1;
2040 u32 i, nr, nr_groups;
2041 struct perf_session *session;
2042 struct perf_evsel *evsel, *leader = NULL;
2043 struct group_desc {
2044 char *name;
2045 u32 leader_idx;
2046 u32 nr_members;
2047 } *desc;
2048
2049 if (readn(fd, &nr_groups, sizeof(nr_groups)) != sizeof(nr_groups))
2050 return -1;
2051
2052 if (ph->needs_swap)
2053 nr_groups = bswap_32(nr_groups);
2054
2055 ph->env.nr_groups = nr_groups;
2056 if (!nr_groups) {
2057 pr_debug("group desc not available\n");
2058 return 0;
2059 }
2060
2061 desc = calloc(nr_groups, sizeof(*desc));
2062 if (!desc)
2063 return -1;
2064
2065 for (i = 0; i < nr_groups; i++) {
2066 desc[i].name = do_read_string(fd, ph);
2067 if (!desc[i].name)
2068 goto out_free;
2069
2070 if (readn(fd, &desc[i].leader_idx, sizeof(u32)) != sizeof(u32))
2071 goto out_free;
2072
2073 if (readn(fd, &desc[i].nr_members, sizeof(u32)) != sizeof(u32))
2074 goto out_free;
2075
2076 if (ph->needs_swap) {
2077 desc[i].leader_idx = bswap_32(desc[i].leader_idx);
2078 desc[i].nr_members = bswap_32(desc[i].nr_members);
2079 }
2080 }
2081
2082 /*
2083 * Rebuild group relationship based on the group_desc
2084 */
2085 session = container_of(ph, struct perf_session, header);
2086 session->evlist->nr_groups = nr_groups;
2087
2088 i = nr = 0;
2089 list_for_each_entry(evsel, &session->evlist->entries, node) {
2090 if (evsel->idx == (int) desc[i].leader_idx) {
2091 evsel->leader = evsel;
2092 /* {anon_group} is a dummy name */
2093 if (strcmp(desc[i].name, "{anon_group}"))
2094 evsel->group_name = desc[i].name;
2095 evsel->nr_members = desc[i].nr_members;
2096
2097 if (i >= nr_groups || nr > 0) {
2098 pr_debug("invalid group desc\n");
2099 goto out_free;
2100 }
2101
2102 leader = evsel;
2103 nr = evsel->nr_members - 1;
2104 i++;
2105 } else if (nr) {
2106 /* This is a group member */
2107 evsel->leader = leader;
2108
2109 nr--;
2110 }
2111 }
2112
2113 if (i != nr_groups || nr != 0) {
2114 pr_debug("invalid group desc\n");
2115 goto out_free;
2116 }
2117
2118 ret = 0;
2119out_free:
2120 while ((int) --i >= 0)
2121 free(desc[i].name);
2122 free(desc);
2123
2124 return ret;
2125}
2126
1964struct feature_ops { 2127struct feature_ops {
1965 int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist); 2128 int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist);
1966 void (*print)(struct perf_header *h, int fd, FILE *fp); 2129 void (*print)(struct perf_header *h, int fd, FILE *fp);
@@ -2000,6 +2163,7 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = {
2000 FEAT_OPF(HEADER_NUMA_TOPOLOGY, numa_topology), 2163 FEAT_OPF(HEADER_NUMA_TOPOLOGY, numa_topology),
2001 FEAT_OPA(HEADER_BRANCH_STACK, branch_stack), 2164 FEAT_OPA(HEADER_BRANCH_STACK, branch_stack),
2002 FEAT_OPP(HEADER_PMU_MAPPINGS, pmu_mappings), 2165 FEAT_OPP(HEADER_PMU_MAPPINGS, pmu_mappings),
2166 FEAT_OPP(HEADER_GROUP_DESC, group_desc),
2003}; 2167};
2004 2168
2005struct header_print_data { 2169struct header_print_data {
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 20f0344accb1..c9fc55cada6d 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -29,6 +29,7 @@ enum {
29 HEADER_NUMA_TOPOLOGY, 29 HEADER_NUMA_TOPOLOGY,
30 HEADER_BRANCH_STACK, 30 HEADER_BRANCH_STACK,
31 HEADER_PMU_MAPPINGS, 31 HEADER_PMU_MAPPINGS,
32 HEADER_GROUP_DESC,
32 HEADER_LAST_FEATURE, 33 HEADER_LAST_FEATURE,
33 HEADER_FEAT_BITS = 256, 34 HEADER_FEAT_BITS = 256,
34}; 35};
@@ -79,6 +80,7 @@ struct perf_session_env {
79 char *numa_nodes; 80 char *numa_nodes;
80 int nr_pmu_mappings; 81 int nr_pmu_mappings;
81 char *pmu_mappings; 82 char *pmu_mappings;
83 int nr_groups;
82}; 84};
83 85
84struct perf_header { 86struct perf_header {