diff options
| author | Namhyung Kim <namhyung.kim@lge.com> | 2013-01-22 04:09:31 -0500 |
|---|---|---|
| committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2013-01-31 11:07:44 -0500 |
| commit | a8bb559bd4eff5c71601e2e61a4bd1deef44a03c (patch) | |
| tree | 2e1f82e4e6024aa66e10b7a73241ff25e0d10105 /tools | |
| parent | 8d7d8474d7b04dc89aa653d67425b61d3ff5c6f0 (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.c | 3 | ||||
| -rw-r--r-- | tools/perf/util/header.c | 164 | ||||
| -rw-r--r-- | tools/perf/util/header.h | 2 |
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 | */ | ||
| 1099 | static 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 | ||
| 1496 | static 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 | |||
| 1450 | static int __event_process_build_id(struct build_id_event *bev, | 1521 | static 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 | ||
| 2035 | static 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; | ||
