diff options
Diffstat (limited to 'tools/perf')
-rw-r--r-- | tools/perf/Makefile | 2 | ||||
-rw-r--r-- | tools/perf/util/header.c | 265 | ||||
-rw-r--r-- | tools/perf/util/header.h | 1 | ||||
-rw-r--r-- | tools/perf/util/parse-events-test.c | 37 | ||||
-rw-r--r-- | tools/perf/util/parse-events.c | 12 | ||||
-rw-r--r-- | tools/perf/util/parse-events.h | 1 | ||||
-rw-r--r-- | tools/perf/util/parse-events.l | 50 | ||||
-rw-r--r-- | tools/perf/util/parse-events.y | 20 | ||||
-rw-r--r-- | tools/perf/util/pmu.c | 50 | ||||
-rw-r--r-- | tools/perf/util/pmu.h | 2 |
10 files changed, 366 insertions, 74 deletions
diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 6bd888d04b6e..722ddee61f9f 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile | |||
@@ -493,7 +493,7 @@ endif | |||
493 | 493 | ||
494 | FLAGS_UNWIND=$(LIBUNWIND_CFLAGS) $(ALL_CFLAGS) $(LIBUNWIND_LDFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) $(LIBUNWIND_LIBS) | 494 | FLAGS_UNWIND=$(LIBUNWIND_CFLAGS) $(ALL_CFLAGS) $(LIBUNWIND_LDFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) $(LIBUNWIND_LIBS) |
495 | ifneq ($(call try-cc,$(SOURCE_LIBUNWIND),$(FLAGS_UNWIND)),y) | 495 | ifneq ($(call try-cc,$(SOURCE_LIBUNWIND),$(FLAGS_UNWIND)),y) |
496 | msg := $(warning No libunwind found. Please install libunwind >= 0.99); | 496 | msg := $(warning No libunwind found, disabling post unwind support. Please install libunwind-dev[el] >= 0.99); |
497 | NO_LIBUNWIND := 1 | 497 | NO_LIBUNWIND := 1 |
498 | endif # Libunwind support | 498 | endif # Libunwind support |
499 | endif # NO_LIBUNWIND | 499 | endif # NO_LIBUNWIND |
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 1e5b6aa60523..9696e64c9dbd 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 | ||
24 | static bool no_buildid_cache = false; | 25 | static 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 | |||
1019 | static 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 | */ |
@@ -1148,12 +1188,29 @@ static void print_cpu_topology(struct perf_header *ph, int fd, FILE *fp) | |||
1148 | } | 1188 | } |
1149 | } | 1189 | } |
1150 | 1190 | ||
1151 | static void print_event_desc(struct perf_header *ph, int fd, FILE *fp) | 1191 | static void free_event_desc(struct perf_evsel *events) |
1192 | { | ||
1193 | struct perf_evsel *evsel; | ||
1194 | |||
1195 | if (!events) | ||
1196 | return; | ||
1197 | |||
1198 | for (evsel = events; evsel->attr.size; evsel++) { | ||
1199 | if (evsel->name) | ||
1200 | free(evsel->name); | ||
1201 | if (evsel->id) | ||
1202 | free(evsel->id); | ||
1203 | } | ||
1204 | |||
1205 | free(events); | ||
1206 | } | ||
1207 | |||
1208 | static struct perf_evsel * | ||
1209 | read_event_desc(struct perf_header *ph, int fd) | ||
1152 | { | 1210 | { |
1153 | struct perf_event_attr attr; | 1211 | struct perf_evsel *evsel, *events = NULL; |
1154 | uint64_t id; | 1212 | u64 *id; |
1155 | void *buf = NULL; | 1213 | void *buf = NULL; |
1156 | char *str; | ||
1157 | u32 nre, sz, nr, i, j; | 1214 | u32 nre, sz, nr, i, j; |
1158 | ssize_t ret; | 1215 | ssize_t ret; |
1159 | size_t msz; | 1216 | size_t msz; |
@@ -1173,18 +1230,22 @@ static void print_event_desc(struct perf_header *ph, int fd, FILE *fp) | |||
1173 | if (ph->needs_swap) | 1230 | if (ph->needs_swap) |
1174 | sz = bswap_32(sz); | 1231 | sz = bswap_32(sz); |
1175 | 1232 | ||
1176 | memset(&attr, 0, sizeof(attr)); | ||
1177 | |||
1178 | /* buffer to hold on file attr struct */ | 1233 | /* buffer to hold on file attr struct */ |
1179 | buf = malloc(sz); | 1234 | buf = malloc(sz); |
1180 | if (!buf) | 1235 | if (!buf) |
1181 | goto error; | 1236 | goto error; |
1182 | 1237 | ||
1183 | msz = sizeof(attr); | 1238 | /* the last event terminates with evsel->attr.size == 0: */ |
1239 | events = calloc(nre + 1, sizeof(*events)); | ||
1240 | if (!events) | ||
1241 | goto error; | ||
1242 | |||
1243 | msz = sizeof(evsel->attr); | ||
1184 | if (sz < msz) | 1244 | if (sz < msz) |
1185 | msz = sz; | 1245 | msz = sz; |
1186 | 1246 | ||
1187 | for (i = 0 ; i < nre; i++) { | 1247 | for (i = 0, evsel = events; i < nre; evsel++, i++) { |
1248 | evsel->idx = i; | ||
1188 | 1249 | ||
1189 | /* | 1250 | /* |
1190 | * must read entire on-file attr struct to | 1251 | * must read entire on-file attr struct to |
@@ -1197,7 +1258,7 @@ static void print_event_desc(struct perf_header *ph, int fd, FILE *fp) | |||
1197 | if (ph->needs_swap) | 1258 | if (ph->needs_swap) |
1198 | perf_event__attr_swap(buf); | 1259 | perf_event__attr_swap(buf); |
1199 | 1260 | ||
1200 | memcpy(&attr, buf, msz); | 1261 | memcpy(&evsel->attr, buf, msz); |
1201 | 1262 | ||
1202 | ret = read(fd, &nr, sizeof(nr)); | 1263 | ret = read(fd, &nr, sizeof(nr)); |
1203 | if (ret != (ssize_t)sizeof(nr)) | 1264 | if (ret != (ssize_t)sizeof(nr)) |
@@ -1206,51 +1267,82 @@ static void print_event_desc(struct perf_header *ph, int fd, FILE *fp) | |||
1206 | if (ph->needs_swap) | 1267 | if (ph->needs_swap) |
1207 | nr = bswap_32(nr); | 1268 | nr = bswap_32(nr); |
1208 | 1269 | ||
1209 | str = do_read_string(fd, ph); | 1270 | evsel->name = do_read_string(fd, ph); |
1210 | fprintf(fp, "# event : name = %s, ", str); | 1271 | |
1211 | free(str); | 1272 | if (!nr) |
1273 | continue; | ||
1274 | |||
1275 | id = calloc(nr, sizeof(*id)); | ||
1276 | if (!id) | ||
1277 | goto error; | ||
1278 | evsel->ids = nr; | ||
1279 | evsel->id = id; | ||
1280 | |||
1281 | for (j = 0 ; j < nr; j++) { | ||
1282 | ret = read(fd, id, sizeof(*id)); | ||
1283 | if (ret != (ssize_t)sizeof(*id)) | ||
1284 | goto error; | ||
1285 | if (ph->needs_swap) | ||
1286 | *id = bswap_64(*id); | ||
1287 | id++; | ||
1288 | } | ||
1289 | } | ||
1290 | out: | ||
1291 | if (buf) | ||
1292 | free(buf); | ||
1293 | return events; | ||
1294 | error: | ||
1295 | if (events) | ||
1296 | free_event_desc(events); | ||
1297 | events = NULL; | ||
1298 | goto out; | ||
1299 | } | ||
1300 | |||
1301 | static void print_event_desc(struct perf_header *ph, int fd, FILE *fp) | ||
1302 | { | ||
1303 | struct perf_evsel *evsel, *events = read_event_desc(ph, fd); | ||
1304 | u32 j; | ||
1305 | u64 *id; | ||
1306 | |||
1307 | if (!events) { | ||
1308 | fprintf(fp, "# event desc: not available or unable to read\n"); | ||
1309 | return; | ||
1310 | } | ||
1311 | |||
1312 | for (evsel = events; evsel->attr.size; evsel++) { | ||
1313 | fprintf(fp, "# event : name = %s, ", evsel->name); | ||
1212 | 1314 | ||
1213 | fprintf(fp, "type = %d, config = 0x%"PRIx64 | 1315 | fprintf(fp, "type = %d, config = 0x%"PRIx64 |
1214 | ", config1 = 0x%"PRIx64", config2 = 0x%"PRIx64, | 1316 | ", config1 = 0x%"PRIx64", config2 = 0x%"PRIx64, |
1215 | attr.type, | 1317 | evsel->attr.type, |
1216 | (u64)attr.config, | 1318 | (u64)evsel->attr.config, |
1217 | (u64)attr.config1, | 1319 | (u64)evsel->attr.config1, |
1218 | (u64)attr.config2); | 1320 | (u64)evsel->attr.config2); |
1219 | 1321 | ||
1220 | fprintf(fp, ", excl_usr = %d, excl_kern = %d", | 1322 | fprintf(fp, ", excl_usr = %d, excl_kern = %d", |
1221 | attr.exclude_user, | 1323 | evsel->attr.exclude_user, |
1222 | attr.exclude_kernel); | 1324 | evsel->attr.exclude_kernel); |
1223 | 1325 | ||
1224 | fprintf(fp, ", excl_host = %d, excl_guest = %d", | 1326 | fprintf(fp, ", excl_host = %d, excl_guest = %d", |
1225 | attr.exclude_host, | 1327 | evsel->attr.exclude_host, |
1226 | attr.exclude_guest); | 1328 | evsel->attr.exclude_guest); |
1227 | 1329 | ||
1228 | fprintf(fp, ", precise_ip = %d", attr.precise_ip); | 1330 | fprintf(fp, ", precise_ip = %d", evsel->attr.precise_ip); |
1229 | 1331 | ||
1230 | if (nr) | 1332 | if (evsel->ids) { |
1231 | fprintf(fp, ", id = {"); | 1333 | fprintf(fp, ", id = {"); |
1232 | 1334 | for (j = 0, id = evsel->id; j < evsel->ids; j++, id++) { | |
1233 | for (j = 0 ; j < nr; j++) { | 1335 | if (j) |
1234 | ret = read(fd, &id, sizeof(id)); | 1336 | fputc(',', fp); |
1235 | if (ret != (ssize_t)sizeof(id)) | 1337 | fprintf(fp, " %"PRIu64, *id); |
1236 | goto error; | 1338 | } |
1237 | |||
1238 | if (ph->needs_swap) | ||
1239 | id = bswap_64(id); | ||
1240 | |||
1241 | if (j) | ||
1242 | fputc(',', fp); | ||
1243 | |||
1244 | fprintf(fp, " %"PRIu64, id); | ||
1245 | } | ||
1246 | if (nr && j == nr) | ||
1247 | fprintf(fp, " }"); | 1339 | fprintf(fp, " }"); |
1340 | } | ||
1341 | |||
1248 | fputc('\n', fp); | 1342 | fputc('\n', fp); |
1249 | } | 1343 | } |
1250 | free(buf); | 1344 | |
1251 | return; | 1345 | free_event_desc(events); |
1252 | error: | ||
1253 | fprintf(fp, "# event desc: not available or unable to read\n"); | ||
1254 | } | 1346 | } |
1255 | 1347 | ||
1256 | static void print_total_mem(struct perf_header *h __used, int fd, FILE *fp) | 1348 | static void print_total_mem(struct perf_header *h __used, int fd, FILE *fp) |
@@ -1337,6 +1429,43 @@ static void print_branch_stack(struct perf_header *ph __used, int fd __used, | |||
1337 | fprintf(fp, "# contains samples with branch stack\n"); | 1429 | fprintf(fp, "# contains samples with branch stack\n"); |
1338 | } | 1430 | } |
1339 | 1431 | ||
1432 | static 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; | ||
1465 | error: | ||
1466 | fprintf(fp, "# pmu mappings: unable to read\n"); | ||
1467 | } | ||
1468 | |||
1340 | static int __event_process_build_id(struct build_id_event *bev, | 1469 | static int __event_process_build_id(struct build_id_event *bev, |
1341 | char *filename, | 1470 | char *filename, |
1342 | struct perf_session *session) | 1471 | struct perf_session *session) |
@@ -1504,6 +1633,56 @@ static int process_build_id(struct perf_file_section *section, | |||
1504 | return 0; | 1633 | return 0; |
1505 | } | 1634 | } |
1506 | 1635 | ||
1636 | static struct perf_evsel * | ||
1637 | perf_evlist__find_by_index(struct perf_evlist *evlist, int idx) | ||
1638 | { | ||
1639 | struct perf_evsel *evsel; | ||
1640 | |||
1641 | list_for_each_entry(evsel, &evlist->entries, node) { | ||
1642 | if (evsel->idx == idx) | ||
1643 | return evsel; | ||
1644 | } | ||
1645 | |||
1646 | return NULL; | ||
1647 | } | ||
1648 | |||
1649 | static void | ||
1650 | perf_evlist__set_event_name(struct perf_evlist *evlist, struct perf_evsel *event) | ||
1651 | { | ||
1652 | struct perf_evsel *evsel; | ||
1653 | |||
1654 | if (!event->name) | ||
1655 | return; | ||
1656 | |||
1657 | evsel = perf_evlist__find_by_index(evlist, event->idx); | ||
1658 | if (!evsel) | ||
1659 | return; | ||
1660 | |||
1661 | if (evsel->name) | ||
1662 | return; | ||
1663 | |||
1664 | evsel->name = strdup(event->name); | ||
1665 | } | ||
1666 | |||
1667 | static int | ||
1668 | process_event_desc(struct perf_file_section *section __unused, | ||
1669 | struct perf_header *header, int feat __unused, int fd, | ||
1670 | void *data __used) | ||
1671 | { | ||
1672 | struct perf_session *session = container_of(header, struct perf_session, header); | ||
1673 | struct perf_evsel *evsel, *events = read_event_desc(header, fd); | ||
1674 | |||
1675 | if (!events) | ||
1676 | return 0; | ||
1677 | |||
1678 | for (evsel = events; evsel->attr.size; evsel++) | ||
1679 | perf_evlist__set_event_name(session->evlist, evsel); | ||
1680 | |||
1681 | free_event_desc(events); | ||
1682 | |||
1683 | return 0; | ||
1684 | } | ||
1685 | |||
1507 | struct feature_ops { | 1686 | struct feature_ops { |
1508 | int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist); | 1687 | int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist); |
1509 | void (*print)(struct perf_header *h, int fd, FILE *fp); | 1688 | void (*print)(struct perf_header *h, int fd, FILE *fp); |
@@ -1537,11 +1716,12 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = { | |||
1537 | FEAT_OPA(HEADER_CPUDESC, cpudesc), | 1716 | FEAT_OPA(HEADER_CPUDESC, cpudesc), |
1538 | FEAT_OPA(HEADER_CPUID, cpuid), | 1717 | FEAT_OPA(HEADER_CPUID, cpuid), |
1539 | FEAT_OPA(HEADER_TOTAL_MEM, total_mem), | 1718 | FEAT_OPA(HEADER_TOTAL_MEM, total_mem), |
1540 | FEAT_OPA(HEADER_EVENT_DESC, event_desc), | 1719 | FEAT_OPP(HEADER_EVENT_DESC, event_desc), |
1541 | FEAT_OPA(HEADER_CMDLINE, cmdline), | 1720 | FEAT_OPA(HEADER_CMDLINE, cmdline), |
1542 | FEAT_OPF(HEADER_CPU_TOPOLOGY, cpu_topology), | 1721 | FEAT_OPF(HEADER_CPU_TOPOLOGY, cpu_topology), |
1543 | FEAT_OPF(HEADER_NUMA_TOPOLOGY, numa_topology), | 1722 | FEAT_OPF(HEADER_NUMA_TOPOLOGY, numa_topology), |
1544 | FEAT_OPA(HEADER_BRANCH_STACK, branch_stack), | 1723 | FEAT_OPA(HEADER_BRANCH_STACK, branch_stack), |
1724 | FEAT_OPA(HEADER_PMU_MAPPINGS, pmu_mappings), | ||
1545 | }; | 1725 | }; |
1546 | 1726 | ||
1547 | struct header_print_data { | 1727 | struct header_print_data { |
@@ -1831,7 +2011,6 @@ static const int attr_file_abi_sizes[] = { | |||
1831 | [1] = PERF_ATTR_SIZE_VER1, | 2011 | [1] = PERF_ATTR_SIZE_VER1, |
1832 | [2] = PERF_ATTR_SIZE_VER2, | 2012 | [2] = PERF_ATTR_SIZE_VER2, |
1833 | [3] = PERF_ATTR_SIZE_VER3, | 2013 | [3] = PERF_ATTR_SIZE_VER3, |
1834 | [4] = PERF_ATTR_SIZE_VER4, | ||
1835 | 0, | 2014 | 0, |
1836 | }; | 2015 | }; |
1837 | 2016 | ||
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/parse-events-test.c b/tools/perf/util/parse-events-test.c index bf055ce1916e..bc8b65130ae0 100644 --- a/tools/perf/util/parse-events-test.c +++ b/tools/perf/util/parse-events-test.c | |||
@@ -301,12 +301,13 @@ static int test__checkevent_breakpoint_modifier(struct perf_evlist *evlist) | |||
301 | { | 301 | { |
302 | struct perf_evsel *evsel = perf_evlist__first(evlist); | 302 | struct perf_evsel *evsel = perf_evlist__first(evlist); |
303 | 303 | ||
304 | |||
304 | TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); | 305 | TEST_ASSERT_VAL("wrong exclude_user", !evsel->attr.exclude_user); |
305 | TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); | 306 | TEST_ASSERT_VAL("wrong exclude_kernel", evsel->attr.exclude_kernel); |
306 | TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); | 307 | TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); |
307 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); | 308 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); |
308 | TEST_ASSERT_VAL("wrong name", | 309 | TEST_ASSERT_VAL("wrong name", |
309 | !strcmp(perf_evsel__name(evsel), "mem:0x0:rw:u")); | 310 | !strcmp(perf_evsel__name(evsel), "mem:0:u")); |
310 | 311 | ||
311 | return test__checkevent_breakpoint(evlist); | 312 | return test__checkevent_breakpoint(evlist); |
312 | } | 313 | } |
@@ -320,7 +321,7 @@ static int test__checkevent_breakpoint_x_modifier(struct perf_evlist *evlist) | |||
320 | TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); | 321 | TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); |
321 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); | 322 | TEST_ASSERT_VAL("wrong precise_ip", !evsel->attr.precise_ip); |
322 | TEST_ASSERT_VAL("wrong name", | 323 | TEST_ASSERT_VAL("wrong name", |
323 | !strcmp(perf_evsel__name(evsel), "mem:0x0:x:k")); | 324 | !strcmp(perf_evsel__name(evsel), "mem:0:x:k")); |
324 | 325 | ||
325 | return test__checkevent_breakpoint_x(evlist); | 326 | return test__checkevent_breakpoint_x(evlist); |
326 | } | 327 | } |
@@ -334,7 +335,7 @@ static int test__checkevent_breakpoint_r_modifier(struct perf_evlist *evlist) | |||
334 | TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); | 335 | TEST_ASSERT_VAL("wrong exclude_hv", !evsel->attr.exclude_hv); |
335 | TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip); | 336 | TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip); |
336 | TEST_ASSERT_VAL("wrong name", | 337 | TEST_ASSERT_VAL("wrong name", |
337 | !strcmp(perf_evsel__name(evsel), "mem:0x0:r:hp")); | 338 | !strcmp(perf_evsel__name(evsel), "mem:0:r:hp")); |
338 | 339 | ||
339 | return test__checkevent_breakpoint_r(evlist); | 340 | return test__checkevent_breakpoint_r(evlist); |
340 | } | 341 | } |
@@ -348,7 +349,7 @@ static int test__checkevent_breakpoint_w_modifier(struct perf_evlist *evlist) | |||
348 | TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); | 349 | TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); |
349 | TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip); | 350 | TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip); |
350 | TEST_ASSERT_VAL("wrong name", | 351 | TEST_ASSERT_VAL("wrong name", |
351 | !strcmp(perf_evsel__name(evsel), "mem:0x0:w:up")); | 352 | !strcmp(perf_evsel__name(evsel), "mem:0:w:up")); |
352 | 353 | ||
353 | return test__checkevent_breakpoint_w(evlist); | 354 | return test__checkevent_breakpoint_w(evlist); |
354 | } | 355 | } |
@@ -362,7 +363,7 @@ static int test__checkevent_breakpoint_rw_modifier(struct perf_evlist *evlist) | |||
362 | TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); | 363 | TEST_ASSERT_VAL("wrong exclude_hv", evsel->attr.exclude_hv); |
363 | TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip); | 364 | TEST_ASSERT_VAL("wrong precise_ip", evsel->attr.precise_ip); |
364 | TEST_ASSERT_VAL("wrong name", | 365 | TEST_ASSERT_VAL("wrong name", |
365 | !strcmp(perf_evsel__name(evsel), "mem:0x0:rw:kp")); | 366 | !strcmp(perf_evsel__name(evsel), "mem:0:rw:kp")); |
366 | 367 | ||
367 | return test__checkevent_breakpoint_rw(evlist); | 368 | return test__checkevent_breakpoint_rw(evlist); |
368 | } | 369 | } |
@@ -437,7 +438,7 @@ static int test__checkevent_pmu_name(struct perf_evlist *evlist) | |||
437 | TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type); | 438 | TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->attr.type); |
438 | TEST_ASSERT_VAL("wrong config", 2 == evsel->attr.config); | 439 | TEST_ASSERT_VAL("wrong config", 2 == evsel->attr.config); |
439 | TEST_ASSERT_VAL("wrong name", | 440 | TEST_ASSERT_VAL("wrong name", |
440 | !strcmp(perf_evsel__name(evsel), "raw 0x2:u")); | 441 | !strcmp(perf_evsel__name(evsel), "cpu/config=2/u")); |
441 | 442 | ||
442 | return 0; | 443 | return 0; |
443 | } | 444 | } |
@@ -948,19 +949,19 @@ static int test_event(struct test__event_st *e) | |||
948 | 949 | ||
949 | static int test_events(struct test__event_st *events, unsigned cnt) | 950 | static int test_events(struct test__event_st *events, unsigned cnt) |
950 | { | 951 | { |
951 | int ret = 0; | 952 | int ret1, ret2 = 0; |
952 | unsigned i; | 953 | unsigned i; |
953 | 954 | ||
954 | for (i = 0; i < cnt; i++) { | 955 | for (i = 0; i < cnt; i++) { |
955 | struct test__event_st *e = &events[i]; | 956 | struct test__event_st *e = &events[i]; |
956 | 957 | ||
957 | pr_debug("running test %d '%s'\n", i, e->name); | 958 | pr_debug("running test %d '%s'\n", i, e->name); |
958 | ret = test_event(e); | 959 | ret1 = test_event(e); |
959 | if (ret) | 960 | if (ret1) |
960 | break; | 961 | ret2 = ret1; |
961 | } | 962 | } |
962 | 963 | ||
963 | return ret; | 964 | return ret2; |
964 | } | 965 | } |
965 | 966 | ||
966 | static int test_term(struct test__term *t) | 967 | static int test_term(struct test__term *t) |
@@ -1021,13 +1022,13 @@ static int test_pmu(void) | |||
1021 | 1022 | ||
1022 | int parse_events__test(void) | 1023 | int parse_events__test(void) |
1023 | { | 1024 | { |
1024 | int ret; | 1025 | int ret1, ret2 = 0; |
1025 | 1026 | ||
1026 | #define TEST_EVENTS(tests) \ | 1027 | #define TEST_EVENTS(tests) \ |
1027 | do { \ | 1028 | do { \ |
1028 | ret = test_events(tests, ARRAY_SIZE(tests)); \ | 1029 | ret1 = test_events(tests, ARRAY_SIZE(tests)); \ |
1029 | if (ret) \ | 1030 | if (!ret2) \ |
1030 | return ret; \ | 1031 | ret2 = ret1; \ |
1031 | } while (0) | 1032 | } while (0) |
1032 | 1033 | ||
1033 | TEST_EVENTS(test__events); | 1034 | TEST_EVENTS(test__events); |
@@ -1035,5 +1036,9 @@ do { \ | |||
1035 | if (test_pmu()) | 1036 | if (test_pmu()) |
1036 | TEST_EVENTS(test__events_pmu); | 1037 | TEST_EVENTS(test__events_pmu); |
1037 | 1038 | ||
1038 | return test_terms(test__terms, ARRAY_SIZE(test__terms)); | 1039 | ret1 = test_terms(test__terms, ARRAY_SIZE(test__terms)); |
1040 | if (!ret2) | ||
1041 | ret2 = ret1; | ||
1042 | |||
1043 | return ret2; | ||
1039 | } | 1044 | } |
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 925784a930a8..b24630398b92 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
@@ -751,6 +751,18 @@ int parse_events__modifier_event(struct list_head *list, char *str, bool add) | |||
751 | return 0; | 751 | return 0; |
752 | } | 752 | } |
753 | 753 | ||
754 | int parse_events_name(struct list_head *list, char *name) | ||
755 | { | ||
756 | struct perf_evsel *evsel; | ||
757 | |||
758 | list_for_each_entry(evsel, list, node) { | ||
759 | if (!evsel->name) | ||
760 | evsel->name = strdup(name); | ||
761 | } | ||
762 | |||
763 | return 0; | ||
764 | } | ||
765 | |||
754 | static int parse_events__scanner(const char *str, void *data, int start_token) | 766 | static int parse_events__scanner(const char *str, void *data, int start_token) |
755 | { | 767 | { |
756 | YY_BUFFER_STATE buffer; | 768 | YY_BUFFER_STATE buffer; |
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index 0b9782dc3da2..c356e443448d 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h | |||
@@ -81,6 +81,7 @@ int parse_events__term_clone(struct parse_events__term **new, | |||
81 | void parse_events__free_terms(struct list_head *terms); | 81 | void parse_events__free_terms(struct list_head *terms); |
82 | int parse_events__modifier_event(struct list_head *list, char *str, bool add); | 82 | int parse_events__modifier_event(struct list_head *list, char *str, bool add); |
83 | int parse_events__modifier_group(struct list_head *list, char *event_mod); | 83 | int parse_events__modifier_group(struct list_head *list, char *event_mod); |
84 | int parse_events_name(struct list_head *list, char *name); | ||
84 | int parse_events_add_tracepoint(struct list_head **list, int *idx, | 85 | int parse_events_add_tracepoint(struct list_head **list, int *idx, |
85 | char *sys, char *event); | 86 | char *sys, char *event); |
86 | int parse_events_add_numeric(struct list_head **list, int *idx, | 87 | int parse_events_add_numeric(struct list_head **list, int *idx, |
diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l index 2c0d006d43db..f5e28dc68270 100644 --- a/tools/perf/util/parse-events.l +++ b/tools/perf/util/parse-events.l | |||
@@ -70,6 +70,12 @@ static int term(yyscan_t scanner, int type) | |||
70 | %} | 70 | %} |
71 | 71 | ||
72 | %x mem | 72 | %x mem |
73 | %s config | ||
74 | %x event | ||
75 | |||
76 | group [^,{}/]*[{][^}]*[}][^,{}/]* | ||
77 | event_pmu [^,{}/]+[/][^/]*[/][^,{}/]* | ||
78 | event [^,{}/]+ | ||
73 | 79 | ||
74 | num_dec [0-9]+ | 80 | num_dec [0-9]+ |
75 | num_hex 0x[a-fA-F0-9]+ | 81 | num_hex 0x[a-fA-F0-9]+ |
@@ -84,7 +90,13 @@ modifier_bp [rwx]{1,3} | |||
84 | { | 90 | { |
85 | int start_token; | 91 | int start_token; |
86 | 92 | ||
87 | start_token = (int) parse_events_get_extra(yyscanner); | 93 | start_token = parse_events_get_extra(yyscanner); |
94 | |||
95 | if (start_token == PE_START_TERMS) | ||
96 | BEGIN(config); | ||
97 | else if (start_token == PE_START_EVENTS) | ||
98 | BEGIN(event); | ||
99 | |||
88 | if (start_token) { | 100 | if (start_token) { |
89 | parse_events_set_extra(NULL, yyscanner); | 101 | parse_events_set_extra(NULL, yyscanner); |
90 | return start_token; | 102 | return start_token; |
@@ -92,6 +104,26 @@ modifier_bp [rwx]{1,3} | |||
92 | } | 104 | } |
93 | %} | 105 | %} |
94 | 106 | ||
107 | <event>{ | ||
108 | |||
109 | {group} { | ||
110 | BEGIN(INITIAL); yyless(0); | ||
111 | } | ||
112 | |||
113 | {event_pmu} | | ||
114 | {event} { | ||
115 | str(yyscanner, PE_EVENT_NAME); | ||
116 | BEGIN(INITIAL); yyless(0); | ||
117 | return PE_EVENT_NAME; | ||
118 | } | ||
119 | |||
120 | . | | ||
121 | <<EOF>> { | ||
122 | BEGIN(INITIAL); yyless(0); | ||
123 | } | ||
124 | |||
125 | } | ||
126 | |||
95 | cpu-cycles|cycles { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES); } | 127 | cpu-cycles|cycles { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES); } |
96 | stalled-cycles-frontend|idle-cycles-frontend { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND); } | 128 | stalled-cycles-frontend|idle-cycles-frontend { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND); } |
97 | stalled-cycles-backend|idle-cycles-backend { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_BACKEND); } | 129 | stalled-cycles-backend|idle-cycles-backend { return sym(yyscanner, PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_BACKEND); } |
@@ -127,18 +159,16 @@ speculative-read|speculative-load | | |||
127 | refs|Reference|ops|access | | 159 | refs|Reference|ops|access | |
128 | misses|miss { return str(yyscanner, PE_NAME_CACHE_OP_RESULT); } | 160 | misses|miss { return str(yyscanner, PE_NAME_CACHE_OP_RESULT); } |
129 | 161 | ||
130 | /* | 162 | <config>{ |
131 | * These are event config hardcoded term names to be specified | ||
132 | * within xxx/.../ syntax. So far we dont clash with other names, | ||
133 | * so we can put them here directly. In case the we have a conflict | ||
134 | * in future, this needs to go into '//' condition block. | ||
135 | */ | ||
136 | config { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG); } | 163 | config { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG); } |
137 | config1 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG1); } | 164 | config1 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG1); } |
138 | config2 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG2); } | 165 | config2 { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_CONFIG2); } |
139 | name { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NAME); } | 166 | name { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_NAME); } |
140 | period { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD); } | 167 | period { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD); } |
141 | branch_type { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); } | 168 | branch_type { return term(yyscanner, PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); } |
169 | , { return ','; } | ||
170 | "/" { BEGIN(INITIAL); return '/'; } | ||
171 | } | ||
142 | 172 | ||
143 | mem: { BEGIN(mem); return PE_PREFIX_MEM; } | 173 | mem: { BEGIN(mem); return PE_PREFIX_MEM; } |
144 | r{num_raw_hex} { return raw(yyscanner); } | 174 | r{num_raw_hex} { return raw(yyscanner); } |
@@ -147,11 +177,11 @@ r{num_raw_hex} { return raw(yyscanner); } | |||
147 | 177 | ||
148 | {modifier_event} { return str(yyscanner, PE_MODIFIER_EVENT); } | 178 | {modifier_event} { return str(yyscanner, PE_MODIFIER_EVENT); } |
149 | {name} { return str(yyscanner, PE_NAME); } | 179 | {name} { return str(yyscanner, PE_NAME); } |
150 | "/" { return '/'; } | 180 | "/" { BEGIN(config); return '/'; } |
151 | - { return '-'; } | 181 | - { return '-'; } |
152 | , { return ','; } | 182 | , { BEGIN(event); return ','; } |
153 | : { return ':'; } | 183 | : { return ':'; } |
154 | "{" { return '{'; } | 184 | "{" { BEGIN(event); return '{'; } |
155 | "}" { return '}'; } | 185 | "}" { return '}'; } |
156 | = { return '='; } | 186 | = { return '='; } |
157 | \n { } | 187 | \n { } |
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index 66850f820df9..42d9a17b83b1 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y | |||
@@ -27,6 +27,7 @@ do { \ | |||
27 | 27 | ||
28 | %token PE_START_EVENTS PE_START_TERMS | 28 | %token PE_START_EVENTS PE_START_TERMS |
29 | %token PE_VALUE PE_VALUE_SYM_HW PE_VALUE_SYM_SW PE_RAW PE_TERM | 29 | %token PE_VALUE PE_VALUE_SYM_HW PE_VALUE_SYM_SW PE_RAW PE_TERM |
30 | %token PE_EVENT_NAME | ||
30 | %token PE_NAME | 31 | %token PE_NAME |
31 | %token PE_MODIFIER_EVENT PE_MODIFIER_BP | 32 | %token PE_MODIFIER_EVENT PE_MODIFIER_BP |
32 | %token PE_NAME_CACHE_TYPE PE_NAME_CACHE_OP_RESULT | 33 | %token PE_NAME_CACHE_TYPE PE_NAME_CACHE_OP_RESULT |
@@ -42,6 +43,7 @@ do { \ | |||
42 | %type <str> PE_NAME_CACHE_OP_RESULT | 43 | %type <str> PE_NAME_CACHE_OP_RESULT |
43 | %type <str> PE_MODIFIER_EVENT | 44 | %type <str> PE_MODIFIER_EVENT |
44 | %type <str> PE_MODIFIER_BP | 45 | %type <str> PE_MODIFIER_BP |
46 | %type <str> PE_EVENT_NAME | ||
45 | %type <num> value_sym | 47 | %type <num> value_sym |
46 | %type <head> event_config | 48 | %type <head> event_config |
47 | %type <term> event_term | 49 | %type <term> event_term |
@@ -53,6 +55,8 @@ do { \ | |||
53 | %type <head> event_legacy_numeric | 55 | %type <head> event_legacy_numeric |
54 | %type <head> event_legacy_raw | 56 | %type <head> event_legacy_raw |
55 | %type <head> event_def | 57 | %type <head> event_def |
58 | %type <head> event_mod | ||
59 | %type <head> event_name | ||
56 | %type <head> event | 60 | %type <head> event |
57 | %type <head> events | 61 | %type <head> events |
58 | %type <head> group_def | 62 | %type <head> group_def |
@@ -143,8 +147,10 @@ events ',' event | |||
143 | | | 147 | | |
144 | event | 148 | event |
145 | 149 | ||
146 | event: | 150 | event: event_mod |
147 | event_def PE_MODIFIER_EVENT | 151 | |
152 | event_mod: | ||
153 | event_name PE_MODIFIER_EVENT | ||
148 | { | 154 | { |
149 | struct list_head *list = $1; | 155 | struct list_head *list = $1; |
150 | 156 | ||
@@ -157,6 +163,16 @@ event_def PE_MODIFIER_EVENT | |||
157 | $$ = list; | 163 | $$ = list; |
158 | } | 164 | } |
159 | | | 165 | | |
166 | event_name | ||
167 | |||
168 | event_name: | ||
169 | PE_EVENT_NAME event_def | ||
170 | { | ||
171 | ABORT_ON(parse_events_name($2, $1)); | ||
172 | free($1); | ||
173 | $$ = $2; | ||
174 | } | ||
175 | | | ||
160 | event_def | 176 | event_def |
161 | 177 | ||
162 | event_def: event_pmu | | 178 | event_def: event_pmu | |
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 | |||
13 | int perf_pmu_parse(struct list_head *list, char *name); | 15 | int perf_pmu_parse(struct list_head *list, char *name); |
14 | extern FILE *perf_pmu_in; | 16 | extern 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: */ | ||
228 | static 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 | |||
225 | static struct perf_pmu *pmu_lookup(char *name) | 256 | static 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 | ||
301 | struct 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 | |||
270 | struct perf_pmu *perf_pmu__find(char *name) | 316 | struct 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); |
47 | void perf_pmu__set_format(unsigned long *bits, long from, long to); | 47 | void perf_pmu__set_format(unsigned long *bits, long from, long to); |
48 | 48 | ||
49 | struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu); | ||
50 | |||
49 | int perf_pmu__test(void); | 51 | int perf_pmu__test(void); |
50 | #endif /* __PMU_H */ | 52 | #endif /* __PMU_H */ |