diff options
author | Ingo Molnar <mingo@kernel.org> | 2016-04-13 14:27:58 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2016-04-13 14:27:58 -0400 |
commit | c5ab6ad7f627f031e2bbde575c7e6e27ea36da55 (patch) | |
tree | 75bbf85deaff38eaa562eefb45bdb38fbcd38849 | |
parent | 31d50c551e30923b86a1b5b420920dd1927fa63b (diff) | |
parent | 59247e33ff494e3643cdff54b64bf72575052b76 (diff) |
Merge tag 'perf-core-for-mingo-20160413' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core
Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo:
User visible changes:
- Print callchains asked for events requested via 'perf trace --event' too:
(Arnaldo Carvalho de Melo)
# trace -e nanosleep --call dwarf --event sched:sched_switch/call-graph=fp/ usleep 1
0.346 (0.005 ms): usleep/24428 nanosleep(rqtp: 0x7fffa15a0540) ...
0.346 ( ): sched:sched_switch:usleep:24428 [120] S ==> swapper/3:0 [120])
__schedule+0xfe200402 ([kernel.kallsyms])
schedule+0xfe200035 ([kernel.kallsyms])
do_nanosleep+0xfe20006f ([kernel.kallsyms])
hrtimer_nanosleep+0xfe2000dc ([kernel.kallsyms])
sys_nanosleep+0xfe20007a ([kernel.kallsyms])
do_syscall_64+0xfe200062 ([kernel.kallsyms])
return_from_SYSCALL_64+0xfe200000 ([kernel.kallsyms])
__nanosleep+0xffff005b8d602010 (/usr/lib64/libc-2.22.so)
0.400 (0.059 ms): usleep/24428 ... [continued]: nanosleep()) = 0
__nanosleep+0x10 (/usr/lib64/libc-2.22.so)
usleep+0x34 (/usr/lib64/libc-2.22.so)
main+0x1eb (/usr/bin/usleep)
__libc_start_main+0xf0 (/usr/lib64/libc-2.22.so)
_start+0x29 (/usr/bin/usleep)
- Allow requesting that some CPUs or PIDs be highlighted in 'perf sched map' (Jiri Olsa)
- Compact 'perf sched map' to show just CPUs with activity, improving the output
in high core count systems (Jiri Olsa)
- Fix segfault with 'perf trace --no-syscalls -e syscall-names' by bailing out
such request, doesn't make sense to ask for no syscalls and then specify which
ones should be printed (Arnaldo Carvalho de Melo)
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r-- | tools/perf/Documentation/perf-sched.txt | 16 | ||||
-rw-r--r-- | tools/perf/builtin-sched.c | 198 | ||||
-rw-r--r-- | tools/perf/builtin-script.c | 14 | ||||
-rw-r--r-- | tools/perf/builtin-trace.c | 48 | ||||
-rw-r--r-- | tools/perf/util/cpumap.c | 12 | ||||
-rw-r--r-- | tools/perf/util/cpumap.h | 2 | ||||
-rw-r--r-- | tools/perf/util/evsel.c | 131 | ||||
-rw-r--r-- | tools/perf/util/evsel.h | 13 | ||||
-rw-r--r-- | tools/perf/util/session.c | 130 | ||||
-rw-r--r-- | tools/perf/util/session.h | 13 | ||||
-rw-r--r-- | tools/perf/util/thread_map.c | 14 | ||||
-rw-r--r-- | tools/perf/util/thread_map.h | 3 |
12 files changed, 416 insertions, 178 deletions
diff --git a/tools/perf/Documentation/perf-sched.txt b/tools/perf/Documentation/perf-sched.txt index 8ff4df956951..1cc08cc47ac5 100644 --- a/tools/perf/Documentation/perf-sched.txt +++ b/tools/perf/Documentation/perf-sched.txt | |||
@@ -50,6 +50,22 @@ OPTIONS | |||
50 | --dump-raw-trace=:: | 50 | --dump-raw-trace=:: |
51 | Display verbose dump of the sched data. | 51 | Display verbose dump of the sched data. |
52 | 52 | ||
53 | OPTIONS for 'perf sched map' | ||
54 | ---------------------------- | ||
55 | |||
56 | --compact:: | ||
57 | Show only CPUs with activity. Helps visualizing on high core | ||
58 | count systems. | ||
59 | |||
60 | --cpus:: | ||
61 | Show just entries with activities for the given CPUs. | ||
62 | |||
63 | --color-cpus:: | ||
64 | Highlight the given cpus. | ||
65 | |||
66 | --color-pids:: | ||
67 | Highlight the given pids. | ||
68 | |||
53 | SEE ALSO | 69 | SEE ALSO |
54 | -------- | 70 | -------- |
55 | linkperf:perf-record[1] | 71 | linkperf:perf-record[1] |
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index 871b55ae22a4..afa057666c2a 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c | |||
@@ -11,6 +11,8 @@ | |||
11 | #include "util/session.h" | 11 | #include "util/session.h" |
12 | #include "util/tool.h" | 12 | #include "util/tool.h" |
13 | #include "util/cloexec.h" | 13 | #include "util/cloexec.h" |
14 | #include "util/thread_map.h" | ||
15 | #include "util/color.h" | ||
14 | 16 | ||
15 | #include <subcmd/parse-options.h> | 17 | #include <subcmd/parse-options.h> |
16 | #include "util/trace-event.h" | 18 | #include "util/trace-event.h" |
@@ -122,6 +124,21 @@ struct trace_sched_handler { | |||
122 | struct machine *machine); | 124 | struct machine *machine); |
123 | }; | 125 | }; |
124 | 126 | ||
127 | #define COLOR_PIDS PERF_COLOR_BLUE | ||
128 | #define COLOR_CPUS PERF_COLOR_BG_RED | ||
129 | |||
130 | struct perf_sched_map { | ||
131 | DECLARE_BITMAP(comp_cpus_mask, MAX_CPUS); | ||
132 | int *comp_cpus; | ||
133 | bool comp; | ||
134 | struct thread_map *color_pids; | ||
135 | const char *color_pids_str; | ||
136 | struct cpu_map *color_cpus; | ||
137 | const char *color_cpus_str; | ||
138 | struct cpu_map *cpus; | ||
139 | const char *cpus_str; | ||
140 | }; | ||
141 | |||
125 | struct perf_sched { | 142 | struct perf_sched { |
126 | struct perf_tool tool; | 143 | struct perf_tool tool; |
127 | const char *sort_order; | 144 | const char *sort_order; |
@@ -173,6 +190,7 @@ struct perf_sched { | |||
173 | struct list_head sort_list, cmp_pid; | 190 | struct list_head sort_list, cmp_pid; |
174 | bool force; | 191 | bool force; |
175 | bool skip_merge; | 192 | bool skip_merge; |
193 | struct perf_sched_map map; | ||
176 | }; | 194 | }; |
177 | 195 | ||
178 | static u64 get_nsecs(void) | 196 | static u64 get_nsecs(void) |
@@ -1339,6 +1357,38 @@ static int process_sched_wakeup_event(struct perf_tool *tool, | |||
1339 | return 0; | 1357 | return 0; |
1340 | } | 1358 | } |
1341 | 1359 | ||
1360 | union map_priv { | ||
1361 | void *ptr; | ||
1362 | bool color; | ||
1363 | }; | ||
1364 | |||
1365 | static bool thread__has_color(struct thread *thread) | ||
1366 | { | ||
1367 | union map_priv priv = { | ||
1368 | .ptr = thread__priv(thread), | ||
1369 | }; | ||
1370 | |||
1371 | return priv.color; | ||
1372 | } | ||
1373 | |||
1374 | static struct thread* | ||
1375 | map__findnew_thread(struct perf_sched *sched, struct machine *machine, pid_t pid, pid_t tid) | ||
1376 | { | ||
1377 | struct thread *thread = machine__findnew_thread(machine, pid, tid); | ||
1378 | union map_priv priv = { | ||
1379 | .color = false, | ||
1380 | }; | ||
1381 | |||
1382 | if (!sched->map.color_pids || !thread || thread__priv(thread)) | ||
1383 | return thread; | ||
1384 | |||
1385 | if (thread_map__has(sched->map.color_pids, tid)) | ||
1386 | priv.color = true; | ||
1387 | |||
1388 | thread__set_priv(thread, priv.ptr); | ||
1389 | return thread; | ||
1390 | } | ||
1391 | |||
1342 | static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel, | 1392 | static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel, |
1343 | struct perf_sample *sample, struct machine *machine) | 1393 | struct perf_sample *sample, struct machine *machine) |
1344 | { | 1394 | { |
@@ -1347,13 +1397,25 @@ static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel, | |||
1347 | int new_shortname; | 1397 | int new_shortname; |
1348 | u64 timestamp0, timestamp = sample->time; | 1398 | u64 timestamp0, timestamp = sample->time; |
1349 | s64 delta; | 1399 | s64 delta; |
1350 | int cpu, this_cpu = sample->cpu; | 1400 | int i, this_cpu = sample->cpu; |
1401 | int cpus_nr; | ||
1402 | bool new_cpu = false; | ||
1403 | const char *color = PERF_COLOR_NORMAL; | ||
1351 | 1404 | ||
1352 | BUG_ON(this_cpu >= MAX_CPUS || this_cpu < 0); | 1405 | BUG_ON(this_cpu >= MAX_CPUS || this_cpu < 0); |
1353 | 1406 | ||
1354 | if (this_cpu > sched->max_cpu) | 1407 | if (this_cpu > sched->max_cpu) |
1355 | sched->max_cpu = this_cpu; | 1408 | sched->max_cpu = this_cpu; |
1356 | 1409 | ||
1410 | if (sched->map.comp) { | ||
1411 | cpus_nr = bitmap_weight(sched->map.comp_cpus_mask, MAX_CPUS); | ||
1412 | if (!test_and_set_bit(this_cpu, sched->map.comp_cpus_mask)) { | ||
1413 | sched->map.comp_cpus[cpus_nr++] = this_cpu; | ||
1414 | new_cpu = true; | ||
1415 | } | ||
1416 | } else | ||
1417 | cpus_nr = sched->max_cpu; | ||
1418 | |||
1357 | timestamp0 = sched->cpu_last_switched[this_cpu]; | 1419 | timestamp0 = sched->cpu_last_switched[this_cpu]; |
1358 | sched->cpu_last_switched[this_cpu] = timestamp; | 1420 | sched->cpu_last_switched[this_cpu] = timestamp; |
1359 | if (timestamp0) | 1421 | if (timestamp0) |
@@ -1366,7 +1428,7 @@ static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel, | |||
1366 | return -1; | 1428 | return -1; |
1367 | } | 1429 | } |
1368 | 1430 | ||
1369 | sched_in = machine__findnew_thread(machine, -1, next_pid); | 1431 | sched_in = map__findnew_thread(sched, machine, -1, next_pid); |
1370 | if (sched_in == NULL) | 1432 | if (sched_in == NULL) |
1371 | return -1; | 1433 | return -1; |
1372 | 1434 | ||
@@ -1400,26 +1462,52 @@ static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel, | |||
1400 | new_shortname = 1; | 1462 | new_shortname = 1; |
1401 | } | 1463 | } |
1402 | 1464 | ||
1403 | for (cpu = 0; cpu <= sched->max_cpu; cpu++) { | 1465 | for (i = 0; i < cpus_nr; i++) { |
1466 | int cpu = sched->map.comp ? sched->map.comp_cpus[i] : i; | ||
1467 | struct thread *curr_thread = sched->curr_thread[cpu]; | ||
1468 | const char *pid_color = color; | ||
1469 | const char *cpu_color = color; | ||
1470 | |||
1471 | if (curr_thread && thread__has_color(curr_thread)) | ||
1472 | pid_color = COLOR_PIDS; | ||
1473 | |||
1474 | if (sched->map.cpus && !cpu_map__has(sched->map.cpus, cpu)) | ||
1475 | continue; | ||
1476 | |||
1477 | if (sched->map.color_cpus && cpu_map__has(sched->map.color_cpus, cpu)) | ||
1478 | cpu_color = COLOR_CPUS; | ||
1479 | |||
1404 | if (cpu != this_cpu) | 1480 | if (cpu != this_cpu) |
1405 | printf(" "); | 1481 | color_fprintf(stdout, cpu_color, " "); |
1406 | else | 1482 | else |
1407 | printf("*"); | 1483 | color_fprintf(stdout, cpu_color, "*"); |
1408 | 1484 | ||
1409 | if (sched->curr_thread[cpu]) | 1485 | if (sched->curr_thread[cpu]) |
1410 | printf("%2s ", sched->curr_thread[cpu]->shortname); | 1486 | color_fprintf(stdout, pid_color, "%2s ", sched->curr_thread[cpu]->shortname); |
1411 | else | 1487 | else |
1412 | printf(" "); | 1488 | color_fprintf(stdout, color, " "); |
1413 | } | 1489 | } |
1414 | 1490 | ||
1415 | printf(" %12.6f secs ", (double)timestamp/1e9); | 1491 | if (sched->map.cpus && !cpu_map__has(sched->map.cpus, this_cpu)) |
1492 | goto out; | ||
1493 | |||
1494 | color_fprintf(stdout, color, " %12.6f secs ", (double)timestamp/1e9); | ||
1416 | if (new_shortname) { | 1495 | if (new_shortname) { |
1417 | printf("%s => %s:%d\n", | 1496 | const char *pid_color = color; |
1497 | |||
1498 | if (thread__has_color(sched_in)) | ||
1499 | pid_color = COLOR_PIDS; | ||
1500 | |||
1501 | color_fprintf(stdout, pid_color, "%s => %s:%d", | ||
1418 | sched_in->shortname, thread__comm_str(sched_in), sched_in->tid); | 1502 | sched_in->shortname, thread__comm_str(sched_in), sched_in->tid); |
1419 | } else { | ||
1420 | printf("\n"); | ||
1421 | } | 1503 | } |
1422 | 1504 | ||
1505 | if (sched->map.comp && new_cpu) | ||
1506 | color_fprintf(stdout, color, " (CPU %d)", this_cpu); | ||
1507 | |||
1508 | out: | ||
1509 | color_fprintf(stdout, color, "\n"); | ||
1510 | |||
1423 | thread__put(sched_in); | 1511 | thread__put(sched_in); |
1424 | 1512 | ||
1425 | return 0; | 1513 | return 0; |
@@ -1675,9 +1763,75 @@ static int perf_sched__lat(struct perf_sched *sched) | |||
1675 | return 0; | 1763 | return 0; |
1676 | } | 1764 | } |
1677 | 1765 | ||
1766 | static int setup_map_cpus(struct perf_sched *sched) | ||
1767 | { | ||
1768 | struct cpu_map *map; | ||
1769 | |||
1770 | sched->max_cpu = sysconf(_SC_NPROCESSORS_CONF); | ||
1771 | |||
1772 | if (sched->map.comp) { | ||
1773 | sched->map.comp_cpus = zalloc(sched->max_cpu * sizeof(int)); | ||
1774 | if (!sched->map.comp_cpus) | ||
1775 | return -1; | ||
1776 | } | ||
1777 | |||
1778 | if (!sched->map.cpus_str) | ||
1779 | return 0; | ||
1780 | |||
1781 | map = cpu_map__new(sched->map.cpus_str); | ||
1782 | if (!map) { | ||
1783 | pr_err("failed to get cpus map from %s\n", sched->map.cpus_str); | ||
1784 | return -1; | ||
1785 | } | ||
1786 | |||
1787 | sched->map.cpus = map; | ||
1788 | return 0; | ||
1789 | } | ||
1790 | |||
1791 | static int setup_color_pids(struct perf_sched *sched) | ||
1792 | { | ||
1793 | struct thread_map *map; | ||
1794 | |||
1795 | if (!sched->map.color_pids_str) | ||
1796 | return 0; | ||
1797 | |||
1798 | map = thread_map__new_by_tid_str(sched->map.color_pids_str); | ||
1799 | if (!map) { | ||
1800 | pr_err("failed to get thread map from %s\n", sched->map.color_pids_str); | ||
1801 | return -1; | ||
1802 | } | ||
1803 | |||
1804 | sched->map.color_pids = map; | ||
1805 | return 0; | ||
1806 | } | ||
1807 | |||
1808 | static int setup_color_cpus(struct perf_sched *sched) | ||
1809 | { | ||
1810 | struct cpu_map *map; | ||
1811 | |||
1812 | if (!sched->map.color_cpus_str) | ||
1813 | return 0; | ||
1814 | |||
1815 | map = cpu_map__new(sched->map.color_cpus_str); | ||
1816 | if (!map) { | ||
1817 | pr_err("failed to get thread map from %s\n", sched->map.color_cpus_str); | ||
1818 | return -1; | ||
1819 | } | ||
1820 | |||
1821 | sched->map.color_cpus = map; | ||
1822 | return 0; | ||
1823 | } | ||
1824 | |||
1678 | static int perf_sched__map(struct perf_sched *sched) | 1825 | static int perf_sched__map(struct perf_sched *sched) |
1679 | { | 1826 | { |
1680 | sched->max_cpu = sysconf(_SC_NPROCESSORS_CONF); | 1827 | if (setup_map_cpus(sched)) |
1828 | return -1; | ||
1829 | |||
1830 | if (setup_color_pids(sched)) | ||
1831 | return -1; | ||
1832 | |||
1833 | if (setup_color_cpus(sched)) | ||
1834 | return -1; | ||
1681 | 1835 | ||
1682 | setup_pager(); | 1836 | setup_pager(); |
1683 | if (perf_sched__read_events(sched)) | 1837 | if (perf_sched__read_events(sched)) |
@@ -1831,6 +1985,17 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1831 | "dump raw trace in ASCII"), | 1985 | "dump raw trace in ASCII"), |
1832 | OPT_END() | 1986 | OPT_END() |
1833 | }; | 1987 | }; |
1988 | const struct option map_options[] = { | ||
1989 | OPT_BOOLEAN(0, "compact", &sched.map.comp, | ||
1990 | "map output in compact mode"), | ||
1991 | OPT_STRING(0, "color-pids", &sched.map.color_pids_str, "pids", | ||
1992 | "highlight given pids in map"), | ||
1993 | OPT_STRING(0, "color-cpus", &sched.map.color_cpus_str, "cpus", | ||
1994 | "highlight given CPUs in map"), | ||
1995 | OPT_STRING(0, "cpus", &sched.map.cpus_str, "cpus", | ||
1996 | "display given CPUs in map"), | ||
1997 | OPT_END() | ||
1998 | }; | ||
1834 | const char * const latency_usage[] = { | 1999 | const char * const latency_usage[] = { |
1835 | "perf sched latency [<options>]", | 2000 | "perf sched latency [<options>]", |
1836 | NULL | 2001 | NULL |
@@ -1839,6 +2004,10 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1839 | "perf sched replay [<options>]", | 2004 | "perf sched replay [<options>]", |
1840 | NULL | 2005 | NULL |
1841 | }; | 2006 | }; |
2007 | const char * const map_usage[] = { | ||
2008 | "perf sched map [<options>]", | ||
2009 | NULL | ||
2010 | }; | ||
1842 | const char *const sched_subcommands[] = { "record", "latency", "map", | 2011 | const char *const sched_subcommands[] = { "record", "latency", "map", |
1843 | "replay", "script", NULL }; | 2012 | "replay", "script", NULL }; |
1844 | const char *sched_usage[] = { | 2013 | const char *sched_usage[] = { |
@@ -1887,6 +2056,11 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1887 | setup_sorting(&sched, latency_options, latency_usage); | 2056 | setup_sorting(&sched, latency_options, latency_usage); |
1888 | return perf_sched__lat(&sched); | 2057 | return perf_sched__lat(&sched); |
1889 | } else if (!strcmp(argv[0], "map")) { | 2058 | } else if (!strcmp(argv[0], "map")) { |
2059 | if (argc) { | ||
2060 | argc = parse_options(argc, argv, map_options, map_usage, 0); | ||
2061 | if (argc) | ||
2062 | usage_with_options(map_usage, map_options); | ||
2063 | } | ||
1890 | sched.tp_handler = &map_ops; | 2064 | sched.tp_handler = &map_ops; |
1891 | setup_sorting(&sched, latency_options, latency_usage); | 2065 | setup_sorting(&sched, latency_options, latency_usage); |
1892 | return perf_sched__map(&sched); | 2066 | return perf_sched__map(&sched); |
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index ddd5b79e94c2..838c0bc38105 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c | |||
@@ -317,19 +317,19 @@ static void set_print_ip_opts(struct perf_event_attr *attr) | |||
317 | 317 | ||
318 | output[type].print_ip_opts = 0; | 318 | output[type].print_ip_opts = 0; |
319 | if (PRINT_FIELD(IP)) | 319 | if (PRINT_FIELD(IP)) |
320 | output[type].print_ip_opts |= PRINT_IP_OPT_IP; | 320 | output[type].print_ip_opts |= EVSEL__PRINT_IP; |
321 | 321 | ||
322 | if (PRINT_FIELD(SYM)) | 322 | if (PRINT_FIELD(SYM)) |
323 | output[type].print_ip_opts |= PRINT_IP_OPT_SYM; | 323 | output[type].print_ip_opts |= EVSEL__PRINT_SYM; |
324 | 324 | ||
325 | if (PRINT_FIELD(DSO)) | 325 | if (PRINT_FIELD(DSO)) |
326 | output[type].print_ip_opts |= PRINT_IP_OPT_DSO; | 326 | output[type].print_ip_opts |= EVSEL__PRINT_DSO; |
327 | 327 | ||
328 | if (PRINT_FIELD(SYMOFFSET)) | 328 | if (PRINT_FIELD(SYMOFFSET)) |
329 | output[type].print_ip_opts |= PRINT_IP_OPT_SYMOFFSET; | 329 | output[type].print_ip_opts |= EVSEL__PRINT_SYMOFFSET; |
330 | 330 | ||
331 | if (PRINT_FIELD(SRCLINE)) | 331 | if (PRINT_FIELD(SRCLINE)) |
332 | output[type].print_ip_opts |= PRINT_IP_OPT_SRCLINE; | 332 | output[type].print_ip_opts |= EVSEL__PRINT_SRCLINE; |
333 | } | 333 | } |
334 | 334 | ||
335 | /* | 335 | /* |
@@ -574,9 +574,9 @@ static void print_sample_bts(struct perf_sample *sample, | |||
574 | printf("\n"); | 574 | printf("\n"); |
575 | } else { | 575 | } else { |
576 | printf(" "); | 576 | printf(" "); |
577 | if (print_opts & PRINT_IP_OPT_SRCLINE) { | 577 | if (print_opts & EVSEL__PRINT_SRCLINE) { |
578 | print_srcline_last = true; | 578 | print_srcline_last = true; |
579 | print_opts &= ~PRINT_IP_OPT_SRCLINE; | 579 | print_opts &= ~EVSEL__PRINT_SRCLINE; |
580 | } | 580 | } |
581 | } | 581 | } |
582 | perf_evsel__fprintf_sym(evsel, sample, al, 0, print_opts, | 582 | perf_evsel__fprintf_sym(evsel, sample, al, 0, print_opts, |
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 2ec53edcf649..d49c131bb5de 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c | |||
@@ -2114,6 +2114,28 @@ out_put: | |||
2114 | return err; | 2114 | return err; |
2115 | } | 2115 | } |
2116 | 2116 | ||
2117 | static int trace__fprintf_callchain(struct trace *trace, struct perf_evsel *evsel, | ||
2118 | struct perf_sample *sample) | ||
2119 | { | ||
2120 | struct addr_location al; | ||
2121 | /* TODO: user-configurable print_opts */ | ||
2122 | const unsigned int print_opts = EVSEL__PRINT_SYM | | ||
2123 | EVSEL__PRINT_DSO | | ||
2124 | EVSEL__PRINT_UNKNOWN_AS_ADDR; | ||
2125 | |||
2126 | if (sample->callchain == NULL) | ||
2127 | return 0; | ||
2128 | |||
2129 | if (machine__resolve(trace->host, &al, sample) < 0) { | ||
2130 | pr_err("Problem processing %s callchain, skipping...\n", | ||
2131 | perf_evsel__name(evsel)); | ||
2132 | return 0; | ||
2133 | } | ||
2134 | |||
2135 | return perf_evsel__fprintf_callchain(evsel, sample, &al, 38, print_opts, | ||
2136 | scripting_max_stack, trace->output); | ||
2137 | } | ||
2138 | |||
2117 | static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel, | 2139 | static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel, |
2118 | union perf_event *event __maybe_unused, | 2140 | union perf_event *event __maybe_unused, |
2119 | struct perf_sample *sample) | 2141 | struct perf_sample *sample) |
@@ -2193,21 +2215,7 @@ signed_print: | |||
2193 | 2215 | ||
2194 | fputc('\n', trace->output); | 2216 | fputc('\n', trace->output); |
2195 | 2217 | ||
2196 | if (sample->callchain) { | 2218 | trace__fprintf_callchain(trace, evsel, sample); |
2197 | struct addr_location al; | ||
2198 | /* TODO: user-configurable print_opts */ | ||
2199 | const unsigned int print_opts = PRINT_IP_OPT_SYM | | ||
2200 | PRINT_IP_OPT_DSO | | ||
2201 | PRINT_IP_OPT_UNKNOWN_AS_ADDR; | ||
2202 | |||
2203 | if (machine__resolve(trace->host, &al, sample) < 0) { | ||
2204 | pr_err("problem processing %d event, skipping it.\n", | ||
2205 | event->header.type); | ||
2206 | goto out_put; | ||
2207 | } | ||
2208 | perf_evsel__fprintf_callchain(evsel, sample, &al, 38, print_opts, | ||
2209 | scripting_max_stack, trace->output); | ||
2210 | } | ||
2211 | out: | 2219 | out: |
2212 | ttrace->entry_pending = false; | 2220 | ttrace->entry_pending = false; |
2213 | err = 0; | 2221 | err = 0; |
@@ -2355,6 +2363,9 @@ static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel, | |||
2355 | } | 2363 | } |
2356 | 2364 | ||
2357 | fprintf(trace->output, ")\n"); | 2365 | fprintf(trace->output, ")\n"); |
2366 | |||
2367 | trace__fprintf_callchain(trace, evsel, sample); | ||
2368 | |||
2358 | return 0; | 2369 | return 0; |
2359 | } | 2370 | } |
2360 | 2371 | ||
@@ -3333,6 +3344,8 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused) | |||
3333 | goto out; | 3344 | goto out; |
3334 | } | 3345 | } |
3335 | 3346 | ||
3347 | err = -1; | ||
3348 | |||
3336 | if (trace.trace_pgfaults) { | 3349 | if (trace.trace_pgfaults) { |
3337 | trace.opts.sample_address = true; | 3350 | trace.opts.sample_address = true; |
3338 | trace.opts.sample_time = true; | 3351 | trace.opts.sample_time = true; |
@@ -3357,6 +3370,11 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused) | |||
3357 | return -1; | 3370 | return -1; |
3358 | } | 3371 | } |
3359 | 3372 | ||
3373 | if (!trace.trace_syscalls && ev_qualifier_str) { | ||
3374 | pr_err("The -e option can't be used with --no-syscalls.\n"); | ||
3375 | goto out; | ||
3376 | } | ||
3377 | |||
3360 | if (output_name != NULL) { | 3378 | if (output_name != NULL) { |
3361 | err = trace__open_output(&trace, output_name); | 3379 | err = trace__open_output(&trace, output_name); |
3362 | if (err < 0) { | 3380 | if (err < 0) { |
diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c index 9bcf2bed3a6d..02d801670f30 100644 --- a/tools/perf/util/cpumap.c +++ b/tools/perf/util/cpumap.c | |||
@@ -587,3 +587,15 @@ int cpu__setup_cpunode_map(void) | |||
587 | closedir(dir1); | 587 | closedir(dir1); |
588 | return 0; | 588 | return 0; |
589 | } | 589 | } |
590 | |||
591 | bool cpu_map__has(struct cpu_map *cpus, int cpu) | ||
592 | { | ||
593 | int i; | ||
594 | |||
595 | for (i = 0; i < cpus->nr; ++i) { | ||
596 | if (cpus->map[i] == cpu) | ||
597 | return true; | ||
598 | } | ||
599 | |||
600 | return false; | ||
601 | } | ||
diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h index 81a2562aaa2b..1a0a35073ce1 100644 --- a/tools/perf/util/cpumap.h +++ b/tools/perf/util/cpumap.h | |||
@@ -66,4 +66,6 @@ int cpu__get_node(int cpu); | |||
66 | int cpu_map__build_map(struct cpu_map *cpus, struct cpu_map **res, | 66 | int cpu_map__build_map(struct cpu_map *cpus, struct cpu_map **res, |
67 | int (*f)(struct cpu_map *map, int cpu, void *data), | 67 | int (*f)(struct cpu_map *map, int cpu, void *data), |
68 | void *data); | 68 | void *data); |
69 | |||
70 | bool cpu_map__has(struct cpu_map *cpus, int cpu); | ||
69 | #endif /* __PERF_CPUMAP_H */ | 71 | #endif /* __PERF_CPUMAP_H */ |
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index d475a4ec8b57..6e86598682be 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
@@ -2343,6 +2343,137 @@ out: | |||
2343 | return ++printed; | 2343 | return ++printed; |
2344 | } | 2344 | } |
2345 | 2345 | ||
2346 | int perf_evsel__fprintf_callchain(struct perf_evsel *evsel, struct perf_sample *sample, | ||
2347 | struct addr_location *al, int left_alignment, | ||
2348 | unsigned int print_opts, unsigned int stack_depth, | ||
2349 | FILE *fp) | ||
2350 | { | ||
2351 | int printed = 0; | ||
2352 | struct callchain_cursor_node *node; | ||
2353 | int print_ip = print_opts & EVSEL__PRINT_IP; | ||
2354 | int print_sym = print_opts & EVSEL__PRINT_SYM; | ||
2355 | int print_dso = print_opts & EVSEL__PRINT_DSO; | ||
2356 | int print_symoffset = print_opts & EVSEL__PRINT_SYMOFFSET; | ||
2357 | int print_oneline = print_opts & EVSEL__PRINT_ONELINE; | ||
2358 | int print_srcline = print_opts & EVSEL__PRINT_SRCLINE; | ||
2359 | int print_unknown_as_addr = print_opts & EVSEL__PRINT_UNKNOWN_AS_ADDR; | ||
2360 | char s = print_oneline ? ' ' : '\t'; | ||
2361 | |||
2362 | if (sample->callchain) { | ||
2363 | struct addr_location node_al; | ||
2364 | |||
2365 | if (thread__resolve_callchain(al->thread, evsel, | ||
2366 | sample, NULL, NULL, | ||
2367 | stack_depth) != 0) { | ||
2368 | if (verbose) | ||
2369 | error("Failed to resolve callchain. Skipping\n"); | ||
2370 | return printed; | ||
2371 | } | ||
2372 | callchain_cursor_commit(&callchain_cursor); | ||
2373 | |||
2374 | if (print_symoffset) | ||
2375 | node_al = *al; | ||
2376 | |||
2377 | while (stack_depth) { | ||
2378 | u64 addr = 0; | ||
2379 | |||
2380 | node = callchain_cursor_current(&callchain_cursor); | ||
2381 | if (!node) | ||
2382 | break; | ||
2383 | |||
2384 | if (node->sym && node->sym->ignore) | ||
2385 | goto next; | ||
2386 | |||
2387 | printed += fprintf(fp, "%-*.*s", left_alignment, left_alignment, " "); | ||
2388 | |||
2389 | if (print_ip) | ||
2390 | printed += fprintf(fp, "%c%16" PRIx64, s, node->ip); | ||
2391 | |||
2392 | if (node->map) | ||
2393 | addr = node->map->map_ip(node->map, node->ip); | ||
2394 | |||
2395 | if (print_sym) { | ||
2396 | printed += fprintf(fp, " "); | ||
2397 | node_al.addr = addr; | ||
2398 | node_al.map = node->map; | ||
2399 | |||
2400 | if (print_symoffset) { | ||
2401 | printed += __symbol__fprintf_symname_offs(node->sym, &node_al, | ||
2402 | print_unknown_as_addr, fp); | ||
2403 | } else { | ||
2404 | printed += __symbol__fprintf_symname(node->sym, &node_al, | ||
2405 | print_unknown_as_addr, fp); | ||
2406 | } | ||
2407 | } | ||
2408 | |||
2409 | if (print_dso) { | ||
2410 | printed += fprintf(fp, " ("); | ||
2411 | printed += map__fprintf_dsoname(node->map, fp); | ||
2412 | printed += fprintf(fp, ")"); | ||
2413 | } | ||
2414 | |||
2415 | if (print_srcline) | ||
2416 | printed += map__fprintf_srcline(node->map, addr, "\n ", fp); | ||
2417 | |||
2418 | if (!print_oneline) | ||
2419 | printed += fprintf(fp, "\n"); | ||
2420 | |||
2421 | stack_depth--; | ||
2422 | next: | ||
2423 | callchain_cursor_advance(&callchain_cursor); | ||
2424 | } | ||
2425 | } | ||
2426 | |||
2427 | return printed; | ||
2428 | } | ||
2429 | |||
2430 | int perf_evsel__fprintf_sym(struct perf_evsel *evsel, struct perf_sample *sample, | ||
2431 | struct addr_location *al, int left_alignment, | ||
2432 | unsigned int print_opts, unsigned int stack_depth, | ||
2433 | FILE *fp) | ||
2434 | { | ||
2435 | int printed = 0; | ||
2436 | int print_ip = print_opts & EVSEL__PRINT_IP; | ||
2437 | int print_sym = print_opts & EVSEL__PRINT_SYM; | ||
2438 | int print_dso = print_opts & EVSEL__PRINT_DSO; | ||
2439 | int print_symoffset = print_opts & EVSEL__PRINT_SYMOFFSET; | ||
2440 | int print_srcline = print_opts & EVSEL__PRINT_SRCLINE; | ||
2441 | int print_unknown_as_addr = print_opts & EVSEL__PRINT_UNKNOWN_AS_ADDR; | ||
2442 | |||
2443 | if (symbol_conf.use_callchain && sample->callchain) { | ||
2444 | printed += perf_evsel__fprintf_callchain(evsel, sample, al, left_alignment, | ||
2445 | print_opts, stack_depth, fp); | ||
2446 | } else if (!(al->sym && al->sym->ignore)) { | ||
2447 | printed += fprintf(fp, "%-*.*s", left_alignment, left_alignment, " "); | ||
2448 | |||
2449 | if (print_ip) | ||
2450 | printed += fprintf(fp, "%16" PRIx64, sample->ip); | ||
2451 | |||
2452 | if (print_sym) { | ||
2453 | printed += fprintf(fp, " "); | ||
2454 | if (print_symoffset) { | ||
2455 | printed += __symbol__fprintf_symname_offs(al->sym, al, | ||
2456 | print_unknown_as_addr, fp); | ||
2457 | } else { | ||
2458 | printed += __symbol__fprintf_symname(al->sym, al, | ||
2459 | print_unknown_as_addr, fp); | ||
2460 | } | ||
2461 | } | ||
2462 | |||
2463 | if (print_dso) { | ||
2464 | printed += fprintf(fp, " ("); | ||
2465 | printed += map__fprintf_dsoname(al->map, fp); | ||
2466 | printed += fprintf(fp, ")"); | ||
2467 | } | ||
2468 | |||
2469 | if (print_srcline) | ||
2470 | printed += map__fprintf_srcline(al->map, al->addr, "\n ", fp); | ||
2471 | } | ||
2472 | |||
2473 | return printed; | ||
2474 | } | ||
2475 | |||
2476 | |||
2346 | bool perf_evsel__fallback(struct perf_evsel *evsel, int err, | 2477 | bool perf_evsel__fallback(struct perf_evsel *evsel, int err, |
2347 | char *msg, size_t msgsize) | 2478 | char *msg, size_t msgsize) |
2348 | { | 2479 | { |
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 1bd6c2e02dfa..36edd3c91d5c 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h | |||
@@ -387,12 +387,25 @@ struct perf_attr_details { | |||
387 | int perf_evsel__fprintf(struct perf_evsel *evsel, | 387 | int perf_evsel__fprintf(struct perf_evsel *evsel, |
388 | struct perf_attr_details *details, FILE *fp); | 388 | struct perf_attr_details *details, FILE *fp); |
389 | 389 | ||
390 | #define EVSEL__PRINT_IP (1<<0) | ||
391 | #define EVSEL__PRINT_SYM (1<<1) | ||
392 | #define EVSEL__PRINT_DSO (1<<2) | ||
393 | #define EVSEL__PRINT_SYMOFFSET (1<<3) | ||
394 | #define EVSEL__PRINT_ONELINE (1<<4) | ||
395 | #define EVSEL__PRINT_SRCLINE (1<<5) | ||
396 | #define EVSEL__PRINT_UNKNOWN_AS_ADDR (1<<6) | ||
397 | |||
390 | int perf_evsel__fprintf_callchain(struct perf_evsel *evsel, | 398 | int perf_evsel__fprintf_callchain(struct perf_evsel *evsel, |
391 | struct perf_sample *sample, | 399 | struct perf_sample *sample, |
392 | struct addr_location *al, int left_alignment, | 400 | struct addr_location *al, int left_alignment, |
393 | unsigned int print_opts, | 401 | unsigned int print_opts, |
394 | unsigned int stack_depth, FILE *fp); | 402 | unsigned int stack_depth, FILE *fp); |
395 | 403 | ||
404 | int perf_evsel__fprintf_sym(struct perf_evsel *evsel, struct perf_sample *sample, | ||
405 | struct addr_location *al, int left_alignment, | ||
406 | unsigned int print_opts, unsigned int stack_depth, | ||
407 | FILE *fp); | ||
408 | |||
396 | bool perf_evsel__fallback(struct perf_evsel *evsel, int err, | 409 | bool perf_evsel__fallback(struct perf_evsel *evsel, int err, |
397 | char *msg, size_t msgsize); | 410 | char *msg, size_t msgsize); |
398 | int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target, | 411 | int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target, |
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 0516d06a2741..91d4528d71fa 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
@@ -1953,136 +1953,6 @@ struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, | |||
1953 | return NULL; | 1953 | return NULL; |
1954 | } | 1954 | } |
1955 | 1955 | ||
1956 | int perf_evsel__fprintf_callchain(struct perf_evsel *evsel, struct perf_sample *sample, | ||
1957 | struct addr_location *al, int left_alignment, | ||
1958 | unsigned int print_opts, unsigned int stack_depth, | ||
1959 | FILE *fp) | ||
1960 | { | ||
1961 | int printed = 0; | ||
1962 | struct callchain_cursor_node *node; | ||
1963 | int print_ip = print_opts & PRINT_IP_OPT_IP; | ||
1964 | int print_sym = print_opts & PRINT_IP_OPT_SYM; | ||
1965 | int print_dso = print_opts & PRINT_IP_OPT_DSO; | ||
1966 | int print_symoffset = print_opts & PRINT_IP_OPT_SYMOFFSET; | ||
1967 | int print_oneline = print_opts & PRINT_IP_OPT_ONELINE; | ||
1968 | int print_srcline = print_opts & PRINT_IP_OPT_SRCLINE; | ||
1969 | int print_unknown_as_addr = print_opts & PRINT_IP_OPT_UNKNOWN_AS_ADDR; | ||
1970 | char s = print_oneline ? ' ' : '\t'; | ||
1971 | |||
1972 | if (sample->callchain) { | ||
1973 | struct addr_location node_al; | ||
1974 | |||
1975 | if (thread__resolve_callchain(al->thread, evsel, | ||
1976 | sample, NULL, NULL, | ||
1977 | stack_depth) != 0) { | ||
1978 | if (verbose) | ||
1979 | error("Failed to resolve callchain. Skipping\n"); | ||
1980 | return printed; | ||
1981 | } | ||
1982 | callchain_cursor_commit(&callchain_cursor); | ||
1983 | |||
1984 | if (print_symoffset) | ||
1985 | node_al = *al; | ||
1986 | |||
1987 | while (stack_depth) { | ||
1988 | u64 addr = 0; | ||
1989 | |||
1990 | node = callchain_cursor_current(&callchain_cursor); | ||
1991 | if (!node) | ||
1992 | break; | ||
1993 | |||
1994 | if (node->sym && node->sym->ignore) | ||
1995 | goto next; | ||
1996 | |||
1997 | printed += fprintf(fp, "%-*.*s", left_alignment, left_alignment, " "); | ||
1998 | |||
1999 | if (print_ip) | ||
2000 | printed += fprintf(fp, "%c%16" PRIx64, s, node->ip); | ||
2001 | |||
2002 | if (node->map) | ||
2003 | addr = node->map->map_ip(node->map, node->ip); | ||
2004 | |||
2005 | if (print_sym) { | ||
2006 | printed += fprintf(fp, " "); | ||
2007 | node_al.addr = addr; | ||
2008 | node_al.map = node->map; | ||
2009 | |||
2010 | if (print_symoffset) { | ||
2011 | printed += __symbol__fprintf_symname_offs(node->sym, &node_al, | ||
2012 | print_unknown_as_addr, fp); | ||
2013 | } else { | ||
2014 | printed += __symbol__fprintf_symname(node->sym, &node_al, | ||
2015 | print_unknown_as_addr, fp); | ||
2016 | } | ||
2017 | } | ||
2018 | |||
2019 | if (print_dso) { | ||
2020 | printed += fprintf(fp, " ("); | ||
2021 | printed += map__fprintf_dsoname(node->map, fp); | ||
2022 | printed += fprintf(fp, ")"); | ||
2023 | } | ||
2024 | |||
2025 | if (print_srcline) | ||
2026 | printed += map__fprintf_srcline(node->map, addr, "\n ", fp); | ||
2027 | |||
2028 | if (!print_oneline) | ||
2029 | printed += fprintf(fp, "\n"); | ||
2030 | |||
2031 | stack_depth--; | ||
2032 | next: | ||
2033 | callchain_cursor_advance(&callchain_cursor); | ||
2034 | } | ||
2035 | } | ||
2036 | |||
2037 | return printed; | ||
2038 | } | ||
2039 | |||
2040 | int perf_evsel__fprintf_sym(struct perf_evsel *evsel, struct perf_sample *sample, | ||
2041 | struct addr_location *al, int left_alignment, | ||
2042 | unsigned int print_opts, unsigned int stack_depth, | ||
2043 | FILE *fp) | ||
2044 | { | ||
2045 | int printed = 0; | ||
2046 | int print_ip = print_opts & PRINT_IP_OPT_IP; | ||
2047 | int print_sym = print_opts & PRINT_IP_OPT_SYM; | ||
2048 | int print_dso = print_opts & PRINT_IP_OPT_DSO; | ||
2049 | int print_symoffset = print_opts & PRINT_IP_OPT_SYMOFFSET; | ||
2050 | int print_srcline = print_opts & PRINT_IP_OPT_SRCLINE; | ||
2051 | int print_unknown_as_addr = print_opts & PRINT_IP_OPT_UNKNOWN_AS_ADDR; | ||
2052 | |||
2053 | if (symbol_conf.use_callchain && sample->callchain) { | ||
2054 | printed += perf_evsel__fprintf_callchain(evsel, sample, al, left_alignment, | ||
2055 | print_opts, stack_depth, fp); | ||
2056 | } else if (!(al->sym && al->sym->ignore)) { | ||
2057 | printed += fprintf(fp, "%-*.*s", left_alignment, left_alignment, " "); | ||
2058 | |||
2059 | if (print_ip) | ||
2060 | printed += fprintf(fp, "%16" PRIx64, sample->ip); | ||
2061 | |||
2062 | if (print_sym) { | ||
2063 | printed += fprintf(fp, " "); | ||
2064 | if (print_symoffset) { | ||
2065 | printed += __symbol__fprintf_symname_offs(al->sym, al, | ||
2066 | print_unknown_as_addr, fp); | ||
2067 | } else { | ||
2068 | printed += __symbol__fprintf_symname(al->sym, al, | ||
2069 | print_unknown_as_addr, fp); | ||
2070 | } | ||
2071 | } | ||
2072 | |||
2073 | if (print_dso) { | ||
2074 | printed += fprintf(fp, " ("); | ||
2075 | printed += map__fprintf_dsoname(al->map, fp); | ||
2076 | printed += fprintf(fp, ")"); | ||
2077 | } | ||
2078 | |||
2079 | if (print_srcline) | ||
2080 | printed += map__fprintf_srcline(al->map, al->addr, "\n ", fp); | ||
2081 | } | ||
2082 | |||
2083 | return printed; | ||
2084 | } | ||
2085 | |||
2086 | int perf_session__cpu_bitmap(struct perf_session *session, | 1956 | int perf_session__cpu_bitmap(struct perf_session *session, |
2087 | const char *cpu_list, unsigned long *cpu_bitmap) | 1957 | const char *cpu_list, unsigned long *cpu_bitmap) |
2088 | { | 1958 | { |
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 4257fac56618..4bd758553450 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h | |||
@@ -36,14 +36,6 @@ struct perf_session { | |||
36 | struct perf_tool *tool; | 36 | struct perf_tool *tool; |
37 | }; | 37 | }; |
38 | 38 | ||
39 | #define PRINT_IP_OPT_IP (1<<0) | ||
40 | #define PRINT_IP_OPT_SYM (1<<1) | ||
41 | #define PRINT_IP_OPT_DSO (1<<2) | ||
42 | #define PRINT_IP_OPT_SYMOFFSET (1<<3) | ||
43 | #define PRINT_IP_OPT_ONELINE (1<<4) | ||
44 | #define PRINT_IP_OPT_SRCLINE (1<<5) | ||
45 | #define PRINT_IP_OPT_UNKNOWN_AS_ADDR (1<<6) | ||
46 | |||
47 | struct perf_tool; | 39 | struct perf_tool; |
48 | 40 | ||
49 | struct perf_session *perf_session__new(struct perf_data_file *file, | 41 | struct perf_session *perf_session__new(struct perf_data_file *file, |
@@ -105,11 +97,6 @@ size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp); | |||
105 | struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, | 97 | struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, |
106 | unsigned int type); | 98 | unsigned int type); |
107 | 99 | ||
108 | int perf_evsel__fprintf_sym(struct perf_evsel *evsel, struct perf_sample *sample, | ||
109 | struct addr_location *al, int left_alignment, | ||
110 | unsigned int print_opts, unsigned int stack_depth, | ||
111 | FILE *fp); | ||
112 | |||
113 | int perf_session__cpu_bitmap(struct perf_session *session, | 100 | int perf_session__cpu_bitmap(struct perf_session *session, |
114 | const char *cpu_list, unsigned long *cpu_bitmap); | 101 | const char *cpu_list, unsigned long *cpu_bitmap); |
115 | 102 | ||
diff --git a/tools/perf/util/thread_map.c b/tools/perf/util/thread_map.c index 267112b4e3db..5654fe15e036 100644 --- a/tools/perf/util/thread_map.c +++ b/tools/perf/util/thread_map.c | |||
@@ -260,7 +260,7 @@ struct thread_map *thread_map__new_dummy(void) | |||
260 | return threads; | 260 | return threads; |
261 | } | 261 | } |
262 | 262 | ||
263 | static struct thread_map *thread_map__new_by_tid_str(const char *tid_str) | 263 | struct thread_map *thread_map__new_by_tid_str(const char *tid_str) |
264 | { | 264 | { |
265 | struct thread_map *threads = NULL, *nt; | 265 | struct thread_map *threads = NULL, *nt; |
266 | int ntasks = 0; | 266 | int ntasks = 0; |
@@ -436,3 +436,15 @@ struct thread_map *thread_map__new_event(struct thread_map_event *event) | |||
436 | 436 | ||
437 | return threads; | 437 | return threads; |
438 | } | 438 | } |
439 | |||
440 | bool thread_map__has(struct thread_map *threads, pid_t pid) | ||
441 | { | ||
442 | int i; | ||
443 | |||
444 | for (i = 0; i < threads->nr; ++i) { | ||
445 | if (threads->map[i].pid == pid) | ||
446 | return true; | ||
447 | } | ||
448 | |||
449 | return false; | ||
450 | } | ||
diff --git a/tools/perf/util/thread_map.h b/tools/perf/util/thread_map.h index 85e4c7c4fbde..bd3b971588da 100644 --- a/tools/perf/util/thread_map.h +++ b/tools/perf/util/thread_map.h | |||
@@ -31,6 +31,8 @@ void thread_map__put(struct thread_map *map); | |||
31 | struct thread_map *thread_map__new_str(const char *pid, | 31 | struct thread_map *thread_map__new_str(const char *pid, |
32 | const char *tid, uid_t uid); | 32 | const char *tid, uid_t uid); |
33 | 33 | ||
34 | struct thread_map *thread_map__new_by_tid_str(const char *tid_str); | ||
35 | |||
34 | size_t thread_map__fprintf(struct thread_map *threads, FILE *fp); | 36 | size_t thread_map__fprintf(struct thread_map *threads, FILE *fp); |
35 | 37 | ||
36 | static inline int thread_map__nr(struct thread_map *threads) | 38 | static inline int thread_map__nr(struct thread_map *threads) |
@@ -55,4 +57,5 @@ static inline char *thread_map__comm(struct thread_map *map, int thread) | |||
55 | } | 57 | } |
56 | 58 | ||
57 | void thread_map__read_comms(struct thread_map *threads); | 59 | void thread_map__read_comms(struct thread_map *threads); |
60 | bool thread_map__has(struct thread_map *threads, pid_t pid); | ||
58 | #endif /* __PERF_THREAD_MAP_H */ | 61 | #endif /* __PERF_THREAD_MAP_H */ |