aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorRobert Richter <robert.richter@amd.com>2012-08-16 15:10:24 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2012-08-22 14:22:55 -0400
commit50a9667c9383982d7ec4e6bbc707f67be0e163d2 (patch)
tree47fa9669f07689f6bb77a9607d94c5b9dc11c685 /tools
parent7c2f7afd36cc111dd08eb8eb8ef74fb6564fd131 (diff)
perf tools: Add pmu mappings to header information
With dynamic pmu allocation there are also dynamically assigned pmu ids. These ids are used in event->attr.type to describe the pmu to be used for that event. The information is available in sysfs, e.g: /sys/bus/event_source/devices/breakpoint/type: 5 /sys/bus/event_source/devices/cpu/type: 4 /sys/bus/event_source/devices/ibs_fetch/type: 6 /sys/bus/event_source/devices/ibs_op/type: 7 /sys/bus/event_source/devices/software/type: 1 /sys/bus/event_source/devices/tracepoint/type: 2 These mappings are needed to know which samples belong to which pmu. If a pmu is added dynamically like for ibs_fetch or ibs_op the type value may vary. Now, when decoding samples from perf.data this information in sysfs might be no longer available or may have changed. We need to store it in perf.data. Using the header for this. Now the header information created with perf report contains an additional section looking like this: # pmu mappings: ibs_op = 7, ibs_fetch = 6, cpu = 4, breakpoint = 5, tracepoint = 2, software = 1 Signed-off-by: Robert Richter <robert.richter@amd.com> Acked-by: Peter Zijlstra <peterz@infradead.org> Cc: Ingo Molnar <mingo@kernel.org> Cc: Jiri Olsa <jolsa@redhat.com> Cc: Peter Zijlstra <peterz@infradead.org> Link: http://lkml.kernel.org/r/1345144224-27280-9-git-send-email-robert.richter@amd.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools')
-rw-r--r--tools/perf/util/header.c78
-rw-r--r--tools/perf/util/header.h1
-rw-r--r--tools/perf/util/pmu.c50
-rw-r--r--tools/perf/util/pmu.h2
4 files changed, 129 insertions, 2 deletions
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 69374deeb4a8..63aad3109e34 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -20,6 +20,7 @@
20#include "symbol.h" 20#include "symbol.h"
21#include "debug.h" 21#include "debug.h"
22#include "cpumap.h" 22#include "cpumap.h"
23#include "pmu.h"
23 24
24static bool no_buildid_cache = false; 25static bool no_buildid_cache = false;
25 26
@@ -1004,6 +1005,45 @@ done:
1004} 1005}
1005 1006
1006/* 1007/*
1008 * File format:
1009 *
1010 * struct pmu_mappings {
1011 * u32 pmu_num;
1012 * struct pmu_map {
1013 * u32 type;
1014 * char name[];
1015 * }[pmu_num];
1016 * };
1017 */
1018
1019static int write_pmu_mappings(int fd, struct perf_header *h __used,
1020 struct perf_evlist *evlist __used)
1021{
1022 struct perf_pmu *pmu = NULL;
1023 off_t offset = lseek(fd, 0, SEEK_CUR);
1024 __u32 pmu_num = 0;
1025
1026 /* write real pmu_num later */
1027 do_write(fd, &pmu_num, sizeof(pmu_num));
1028
1029 while ((pmu = perf_pmu__scan(pmu))) {
1030 if (!pmu->name)
1031 continue;
1032 pmu_num++;
1033 do_write(fd, &pmu->type, sizeof(pmu->type));
1034 do_write_string(fd, pmu->name);
1035 }
1036
1037 if (pwrite(fd, &pmu_num, sizeof(pmu_num), offset) != sizeof(pmu_num)) {
1038 /* discard all */
1039 lseek(fd, offset, SEEK_SET);
1040 return -1;
1041 }
1042
1043 return 0;
1044}
1045
1046/*
1007 * default get_cpuid(): nothing gets recorded 1047 * default get_cpuid(): nothing gets recorded
1008 * actual implementation must be in arch/$(ARCH)/util/header.c 1048 * actual implementation must be in arch/$(ARCH)/util/header.c
1009 */ 1049 */
@@ -1389,6 +1429,43 @@ static void print_branch_stack(struct perf_header *ph __used, int fd __used,
1389 fprintf(fp, "# contains samples with branch stack\n"); 1429 fprintf(fp, "# contains samples with branch stack\n");
1390} 1430}
1391 1431
1432static void print_pmu_mappings(struct perf_header *ph, int fd, FILE *fp)
1433{
1434 const char *delimiter = "# pmu mappings: ";
1435 char *name;
1436 int ret;
1437 u32 pmu_num;
1438 u32 type;
1439
1440 ret = read(fd, &pmu_num, sizeof(pmu_num));
1441 if (ret != sizeof(pmu_num))
1442 goto error;
1443
1444 if (!pmu_num) {
1445 fprintf(fp, "# pmu mappings: not available\n");
1446 return;
1447 }
1448
1449 while (pmu_num) {
1450 if (read(fd, &type, sizeof(type)) != sizeof(type))
1451 break;
1452 name = do_read_string(fd, ph);
1453 if (!name)
1454 break;
1455 pmu_num--;
1456 fprintf(fp, "%s%s = %" PRIu32, delimiter, name, type);
1457 free(name);
1458 delimiter = ", ";
1459 }
1460
1461 fprintf(fp, "\n");
1462
1463 if (!pmu_num)
1464 return;
1465error:
1466 fprintf(fp, "# pmu mappings: unable to read\n");
1467}
1468
1392static int __event_process_build_id(struct build_id_event *bev, 1469static int __event_process_build_id(struct build_id_event *bev,
1393 char *filename, 1470 char *filename,
1394 struct perf_session *session) 1471 struct perf_session *session)
@@ -1644,6 +1721,7 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = {
1644 FEAT_OPF(HEADER_CPU_TOPOLOGY, cpu_topology), 1721 FEAT_OPF(HEADER_CPU_TOPOLOGY, cpu_topology),
1645 FEAT_OPF(HEADER_NUMA_TOPOLOGY, numa_topology), 1722 FEAT_OPF(HEADER_NUMA_TOPOLOGY, numa_topology),
1646 FEAT_OPA(HEADER_BRANCH_STACK, branch_stack), 1723 FEAT_OPA(HEADER_BRANCH_STACK, branch_stack),
1724 FEAT_OPA(HEADER_PMU_MAPPINGS, pmu_mappings),
1647}; 1725};
1648 1726
1649struct header_print_data { 1727struct header_print_data {
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 24962e707e5b..9d5eedceda72 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -28,6 +28,7 @@ enum {
28 HEADER_CPU_TOPOLOGY, 28 HEADER_CPU_TOPOLOGY,
29 HEADER_NUMA_TOPOLOGY, 29 HEADER_NUMA_TOPOLOGY,
30 HEADER_BRANCH_STACK, 30 HEADER_BRANCH_STACK,
31 HEADER_PMU_MAPPINGS,
31 HEADER_LAST_FEATURE, 32 HEADER_LAST_FEATURE,
32 HEADER_FEAT_BITS = 256, 33 HEADER_FEAT_BITS = 256,
33}; 34};
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index 67715a42cd6d..6631d828db3d 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -10,6 +10,8 @@
10#include "pmu.h" 10#include "pmu.h"
11#include "parse-events.h" 11#include "parse-events.h"
12 12
13#define EVENT_SOURCE_DEVICE_PATH "/bus/event_source/devices/"
14
13int perf_pmu_parse(struct list_head *list, char *name); 15int perf_pmu_parse(struct list_head *list, char *name);
14extern FILE *perf_pmu_in; 16extern FILE *perf_pmu_in;
15 17
@@ -69,7 +71,7 @@ static int pmu_format(char *name, struct list_head *format)
69 return -1; 71 return -1;
70 72
71 snprintf(path, PATH_MAX, 73 snprintf(path, PATH_MAX,
72 "%s/bus/event_source/devices/%s/format", sysfs, name); 74 "%s" EVENT_SOURCE_DEVICE_PATH "%s/format", sysfs, name);
73 75
74 if (stat(path, &st) < 0) 76 if (stat(path, &st) < 0)
75 return 0; /* no error if format does not exist */ 77 return 0; /* no error if format does not exist */
@@ -206,7 +208,7 @@ static int pmu_type(char *name, __u32 *type)
206 return -1; 208 return -1;
207 209
208 snprintf(path, PATH_MAX, 210 snprintf(path, PATH_MAX,
209 "%s/bus/event_source/devices/%s/type", sysfs, name); 211 "%s" EVENT_SOURCE_DEVICE_PATH "%s/type", sysfs, name);
210 212
211 if (stat(path, &st) < 0) 213 if (stat(path, &st) < 0)
212 return -1; 214 return -1;
@@ -222,6 +224,35 @@ static int pmu_type(char *name, __u32 *type)
222 return ret; 224 return ret;
223} 225}
224 226
227/* Add all pmus in sysfs to pmu list: */
228static void pmu_read_sysfs(void)
229{
230 char path[PATH_MAX];
231 const char *sysfs;
232 DIR *dir;
233 struct dirent *dent;
234
235 sysfs = sysfs_find_mountpoint();
236 if (!sysfs)
237 return;
238
239 snprintf(path, PATH_MAX,
240 "%s" EVENT_SOURCE_DEVICE_PATH, sysfs);
241
242 dir = opendir(path);
243 if (!dir)
244 return;
245
246 while ((dent = readdir(dir))) {
247 if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
248 continue;
249 /* add to static LIST_HEAD(pmus): */
250 perf_pmu__find(dent->d_name);
251 }
252
253 closedir(dir);
254}
255
225static struct perf_pmu *pmu_lookup(char *name) 256static struct perf_pmu *pmu_lookup(char *name)
226{ 257{
227 struct perf_pmu *pmu; 258 struct perf_pmu *pmu;
@@ -267,6 +298,21 @@ static struct perf_pmu *pmu_find(char *name)
267 return NULL; 298 return NULL;
268} 299}
269 300
301struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu)
302{
303 /*
304 * pmu iterator: If pmu is NULL, we start at the begin,
305 * otherwise return the next pmu. Returns NULL on end.
306 */
307 if (!pmu) {
308 pmu_read_sysfs();
309 pmu = list_prepare_entry(pmu, &pmus, list);
310 }
311 list_for_each_entry_continue(pmu, &pmus, list)
312 return pmu;
313 return NULL;
314}
315
270struct perf_pmu *perf_pmu__find(char *name) 316struct perf_pmu *perf_pmu__find(char *name)
271{ 317{
272 struct perf_pmu *pmu; 318 struct perf_pmu *pmu;
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index 535f2c5258ab..47f68d3cc5d1 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h
@@ -46,5 +46,7 @@ int perf_pmu__new_format(struct list_head *list, char *name,
46 int config, unsigned long *bits); 46 int config, unsigned long *bits);
47void perf_pmu__set_format(unsigned long *bits, long from, long to); 47void perf_pmu__set_format(unsigned long *bits, long from, long to);
48 48
49struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu);
50
49int perf_pmu__test(void); 51int perf_pmu__test(void);
50#endif /* __PMU_H */ 52#endif /* __PMU_H */