diff options
Diffstat (limited to 'tools/perf/builtin-test.c')
-rw-r--r-- | tools/perf/builtin-test.c | 188 |
1 files changed, 179 insertions, 9 deletions
diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c index 3854e869dce1..3e087ce8daa6 100644 --- a/tools/perf/builtin-test.c +++ b/tools/perf/builtin-test.c | |||
@@ -15,6 +15,8 @@ | |||
15 | #include "util/thread_map.h" | 15 | #include "util/thread_map.h" |
16 | #include "../../include/linux/hw_breakpoint.h" | 16 | #include "../../include/linux/hw_breakpoint.h" |
17 | 17 | ||
18 | #include <sys/mman.h> | ||
19 | |||
18 | static int vmlinux_matches_kallsyms_filter(struct map *map __used, struct symbol *sym) | 20 | static int vmlinux_matches_kallsyms_filter(struct map *map __used, struct symbol *sym) |
19 | { | 21 | { |
20 | bool *visited = symbol__priv(sym); | 22 | bool *visited = symbol__priv(sym); |
@@ -276,7 +278,7 @@ static int test__open_syscall_event(void) | |||
276 | return -1; | 278 | return -1; |
277 | } | 279 | } |
278 | 280 | ||
279 | threads = thread_map__new(-1, getpid()); | 281 | threads = thread_map__new(-1, getpid(), UINT_MAX); |
280 | if (threads == NULL) { | 282 | if (threads == NULL) { |
281 | pr_debug("thread_map__new\n"); | 283 | pr_debug("thread_map__new\n"); |
282 | return -1; | 284 | return -1; |
@@ -342,7 +344,7 @@ static int test__open_syscall_event_on_all_cpus(void) | |||
342 | return -1; | 344 | return -1; |
343 | } | 345 | } |
344 | 346 | ||
345 | threads = thread_map__new(-1, getpid()); | 347 | threads = thread_map__new(-1, getpid(), UINT_MAX); |
346 | if (threads == NULL) { | 348 | if (threads == NULL) { |
347 | pr_debug("thread_map__new\n"); | 349 | pr_debug("thread_map__new\n"); |
348 | return -1; | 350 | return -1; |
@@ -490,7 +492,7 @@ static int test__basic_mmap(void) | |||
490 | expected_nr_events[i] = random() % 257; | 492 | expected_nr_events[i] = random() % 257; |
491 | } | 493 | } |
492 | 494 | ||
493 | threads = thread_map__new(-1, getpid()); | 495 | threads = thread_map__new(-1, getpid(), UINT_MAX); |
494 | if (threads == NULL) { | 496 | if (threads == NULL) { |
495 | pr_debug("thread_map__new\n"); | 497 | pr_debug("thread_map__new\n"); |
496 | return -1; | 498 | return -1; |
@@ -1008,12 +1010,9 @@ realloc: | |||
1008 | static int test__PERF_RECORD(void) | 1010 | static int test__PERF_RECORD(void) |
1009 | { | 1011 | { |
1010 | struct perf_record_opts opts = { | 1012 | struct perf_record_opts opts = { |
1011 | .target_pid = -1, | ||
1012 | .target_tid = -1, | ||
1013 | .no_delay = true, | 1013 | .no_delay = true, |
1014 | .freq = 10, | 1014 | .freq = 10, |
1015 | .mmap_pages = 256, | 1015 | .mmap_pages = 256, |
1016 | .sample_id_all_avail = true, | ||
1017 | }; | 1016 | }; |
1018 | cpu_set_t *cpu_mask = NULL; | 1017 | cpu_set_t *cpu_mask = NULL; |
1019 | size_t cpu_mask_size = 0; | 1018 | size_t cpu_mask_size = 0; |
@@ -1054,7 +1053,7 @@ static int test__PERF_RECORD(void) | |||
1054 | * we're monitoring, the one forked there. | 1053 | * we're monitoring, the one forked there. |
1055 | */ | 1054 | */ |
1056 | err = perf_evlist__create_maps(evlist, opts.target_pid, | 1055 | err = perf_evlist__create_maps(evlist, opts.target_pid, |
1057 | opts.target_tid, opts.cpu_list); | 1056 | opts.target_tid, UINT_MAX, opts.cpu_list); |
1058 | if (err < 0) { | 1057 | if (err < 0) { |
1059 | pr_debug("Not enough memory to create thread/cpu maps\n"); | 1058 | pr_debug("Not enough memory to create thread/cpu maps\n"); |
1060 | goto out_delete_evlist; | 1059 | goto out_delete_evlist; |
@@ -1296,6 +1295,173 @@ out: | |||
1296 | return (err < 0 || errs > 0) ? -1 : 0; | 1295 | return (err < 0 || errs > 0) ? -1 : 0; |
1297 | } | 1296 | } |
1298 | 1297 | ||
1298 | |||
1299 | #if defined(__x86_64__) || defined(__i386__) | ||
1300 | |||
1301 | #define barrier() asm volatile("" ::: "memory") | ||
1302 | |||
1303 | static u64 rdpmc(unsigned int counter) | ||
1304 | { | ||
1305 | unsigned int low, high; | ||
1306 | |||
1307 | asm volatile("rdpmc" : "=a" (low), "=d" (high) : "c" (counter)); | ||
1308 | |||
1309 | return low | ((u64)high) << 32; | ||
1310 | } | ||
1311 | |||
1312 | static u64 rdtsc(void) | ||
1313 | { | ||
1314 | unsigned int low, high; | ||
1315 | |||
1316 | asm volatile("rdtsc" : "=a" (low), "=d" (high)); | ||
1317 | |||
1318 | return low | ((u64)high) << 32; | ||
1319 | } | ||
1320 | |||
1321 | static u64 mmap_read_self(void *addr) | ||
1322 | { | ||
1323 | struct perf_event_mmap_page *pc = addr; | ||
1324 | u32 seq, idx, time_mult = 0, time_shift = 0; | ||
1325 | u64 count, cyc = 0, time_offset = 0, enabled, running, delta; | ||
1326 | |||
1327 | do { | ||
1328 | seq = pc->lock; | ||
1329 | barrier(); | ||
1330 | |||
1331 | enabled = pc->time_enabled; | ||
1332 | running = pc->time_running; | ||
1333 | |||
1334 | if (enabled != running) { | ||
1335 | cyc = rdtsc(); | ||
1336 | time_mult = pc->time_mult; | ||
1337 | time_shift = pc->time_shift; | ||
1338 | time_offset = pc->time_offset; | ||
1339 | } | ||
1340 | |||
1341 | idx = pc->index; | ||
1342 | count = pc->offset; | ||
1343 | if (idx) | ||
1344 | count += rdpmc(idx - 1); | ||
1345 | |||
1346 | barrier(); | ||
1347 | } while (pc->lock != seq); | ||
1348 | |||
1349 | if (enabled != running) { | ||
1350 | u64 quot, rem; | ||
1351 | |||
1352 | quot = (cyc >> time_shift); | ||
1353 | rem = cyc & ((1 << time_shift) - 1); | ||
1354 | delta = time_offset + quot * time_mult + | ||
1355 | ((rem * time_mult) >> time_shift); | ||
1356 | |||
1357 | enabled += delta; | ||
1358 | if (idx) | ||
1359 | running += delta; | ||
1360 | |||
1361 | quot = count / running; | ||
1362 | rem = count % running; | ||
1363 | count = quot * enabled + (rem * enabled) / running; | ||
1364 | } | ||
1365 | |||
1366 | return count; | ||
1367 | } | ||
1368 | |||
1369 | /* | ||
1370 | * If the RDPMC instruction faults then signal this back to the test parent task: | ||
1371 | */ | ||
1372 | static void segfault_handler(int sig __used, siginfo_t *info __used, void *uc __used) | ||
1373 | { | ||
1374 | exit(-1); | ||
1375 | } | ||
1376 | |||
1377 | static int __test__rdpmc(void) | ||
1378 | { | ||
1379 | long page_size = sysconf(_SC_PAGE_SIZE); | ||
1380 | volatile int tmp = 0; | ||
1381 | u64 i, loops = 1000; | ||
1382 | int n; | ||
1383 | int fd; | ||
1384 | void *addr; | ||
1385 | struct perf_event_attr attr = { | ||
1386 | .type = PERF_TYPE_HARDWARE, | ||
1387 | .config = PERF_COUNT_HW_INSTRUCTIONS, | ||
1388 | .exclude_kernel = 1, | ||
1389 | }; | ||
1390 | u64 delta_sum = 0; | ||
1391 | struct sigaction sa; | ||
1392 | |||
1393 | sigfillset(&sa.sa_mask); | ||
1394 | sa.sa_sigaction = segfault_handler; | ||
1395 | sigaction(SIGSEGV, &sa, NULL); | ||
1396 | |||
1397 | fprintf(stderr, "\n\n"); | ||
1398 | |||
1399 | fd = sys_perf_event_open(&attr, 0, -1, -1, 0); | ||
1400 | if (fd < 0) { | ||
1401 | die("Error: sys_perf_event_open() syscall returned " | ||
1402 | "with %d (%s)\n", fd, strerror(errno)); | ||
1403 | } | ||
1404 | |||
1405 | addr = mmap(NULL, page_size, PROT_READ, MAP_SHARED, fd, 0); | ||
1406 | if (addr == (void *)(-1)) { | ||
1407 | die("Error: mmap() syscall returned " | ||
1408 | "with (%s)\n", strerror(errno)); | ||
1409 | } | ||
1410 | |||
1411 | for (n = 0; n < 6; n++) { | ||
1412 | u64 stamp, now, delta; | ||
1413 | |||
1414 | stamp = mmap_read_self(addr); | ||
1415 | |||
1416 | for (i = 0; i < loops; i++) | ||
1417 | tmp++; | ||
1418 | |||
1419 | now = mmap_read_self(addr); | ||
1420 | loops *= 10; | ||
1421 | |||
1422 | delta = now - stamp; | ||
1423 | fprintf(stderr, "%14d: %14Lu\n", n, (long long)delta); | ||
1424 | |||
1425 | delta_sum += delta; | ||
1426 | } | ||
1427 | |||
1428 | munmap(addr, page_size); | ||
1429 | close(fd); | ||
1430 | |||
1431 | fprintf(stderr, " "); | ||
1432 | |||
1433 | if (!delta_sum) | ||
1434 | return -1; | ||
1435 | |||
1436 | return 0; | ||
1437 | } | ||
1438 | |||
1439 | static int test__rdpmc(void) | ||
1440 | { | ||
1441 | int status = 0; | ||
1442 | int wret = 0; | ||
1443 | int ret; | ||
1444 | int pid; | ||
1445 | |||
1446 | pid = fork(); | ||
1447 | if (pid < 0) | ||
1448 | return -1; | ||
1449 | |||
1450 | if (!pid) { | ||
1451 | ret = __test__rdpmc(); | ||
1452 | |||
1453 | exit(ret); | ||
1454 | } | ||
1455 | |||
1456 | wret = waitpid(pid, &status, 0); | ||
1457 | if (wret < 0 || status) | ||
1458 | return -1; | ||
1459 | |||
1460 | return 0; | ||
1461 | } | ||
1462 | |||
1463 | #endif | ||
1464 | |||
1299 | static struct test { | 1465 | static struct test { |
1300 | const char *desc; | 1466 | const char *desc; |
1301 | int (*func)(void); | 1467 | int (*func)(void); |
@@ -1320,6 +1486,12 @@ static struct test { | |||
1320 | .desc = "parse events tests", | 1486 | .desc = "parse events tests", |
1321 | .func = test__parse_events, | 1487 | .func = test__parse_events, |
1322 | }, | 1488 | }, |
1489 | #if defined(__x86_64__) || defined(__i386__) | ||
1490 | { | ||
1491 | .desc = "x86 rdpmc test", | ||
1492 | .func = test__rdpmc, | ||
1493 | }, | ||
1494 | #endif | ||
1323 | { | 1495 | { |
1324 | .desc = "Validate PERF_RECORD_* events & perf_sample fields", | 1496 | .desc = "Validate PERF_RECORD_* events & perf_sample fields", |
1325 | .func = test__PERF_RECORD, | 1497 | .func = test__PERF_RECORD, |
@@ -1412,7 +1584,5 @@ int cmd_test(int argc, const char **argv, const char *prefix __used) | |||
1412 | if (symbol__init() < 0) | 1584 | if (symbol__init() < 0) |
1413 | return -1; | 1585 | return -1; |
1414 | 1586 | ||
1415 | setup_pager(); | ||
1416 | |||
1417 | return __cmd_test(argc, argv); | 1587 | return __cmd_test(argc, argv); |
1418 | } | 1588 | } |