aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorDavid Ahern <dsahern@gmail.com>2012-02-08 11:32:52 -0500
committerArnaldo Carvalho de Melo <acme@redhat.com>2012-02-13 19:54:11 -0500
commitb52956c961be3a04182ae7b776623531601e0fb7 (patch)
tree2f7ebf4a910dc8cd9014ac9df59f7e2441a5b034 /tools
parenteca1c3e3f937307331fd1fd5ee5205e57f2131ca (diff)
perf tools: Allow multiple threads or processes in record, stat, top
Allow a user to collect events for multiple threads or processes using a comma separated list. e.g., collect data on a VM and its vhost thread: perf top -p 21483,21485 perf stat -p 21483,21485 -ddd perf record -p 21483,21485 or monitoring vcpu threads perf top -t 21488,21489 perf stat -t 21488,21489 -ddd perf record -t 21488,21489 Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Link: http://lkml.kernel.org/r/1328718772-16688-1-git-send-email-dsahern@gmail.com Signed-off-by: David Ahern <dsahern@gmail.com> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools')
-rw-r--r--tools/perf/Documentation/perf-record.txt4
-rw-r--r--tools/perf/Documentation/perf-stat.txt4
-rw-r--r--tools/perf/Documentation/perf-top.txt4
-rw-r--r--tools/perf/builtin-record.c10
-rw-r--r--tools/perf/builtin-stat.c31
-rw-r--r--tools/perf/builtin-test.c2
-rw-r--r--tools/perf/builtin-top.c12
-rw-r--r--tools/perf/perf.h4
-rw-r--r--tools/perf/util/evlist.c10
-rw-r--r--tools/perf/util/evlist.h4
-rw-r--r--tools/perf/util/evsel.c2
-rw-r--r--tools/perf/util/python-ext-sources2
-rw-r--r--tools/perf/util/thread_map.c128
-rw-r--r--tools/perf/util/thread_map.h4
-rw-r--r--tools/perf/util/top.c10
-rw-r--r--tools/perf/util/top.h2
-rw-r--r--tools/perf/util/usage.c6
-rw-r--r--tools/perf/util/util.h2
18 files changed, 185 insertions, 56 deletions
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
index ff9a66e0d4e4..a5766b4b0125 100644
--- a/tools/perf/Documentation/perf-record.txt
+++ b/tools/perf/Documentation/perf-record.txt
@@ -52,11 +52,11 @@ OPTIONS
52 52
53-p:: 53-p::
54--pid=:: 54--pid=::
55 Record events on existing process ID. 55 Record events on existing process ID (comma separated list).
56 56
57-t:: 57-t::
58--tid=:: 58--tid=::
59 Record events on existing thread ID. 59 Record events on existing thread ID (comma separated list).
60 60
61-u:: 61-u::
62--uid=:: 62--uid=::
diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt
index 8966b9ab2014..2fa173b51970 100644
--- a/tools/perf/Documentation/perf-stat.txt
+++ b/tools/perf/Documentation/perf-stat.txt
@@ -35,11 +35,11 @@ OPTIONS
35 child tasks do not inherit counters 35 child tasks do not inherit counters
36-p:: 36-p::
37--pid=<pid>:: 37--pid=<pid>::
38 stat events on existing process id 38 stat events on existing process id (comma separated list)
39 39
40-t:: 40-t::
41--tid=<tid>:: 41--tid=<tid>::
42 stat events on existing thread id 42 stat events on existing thread id (comma separated list)
43 43
44 44
45-a:: 45-a::
diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt
index ab1454ed450f..4a5680cb242e 100644
--- a/tools/perf/Documentation/perf-top.txt
+++ b/tools/perf/Documentation/perf-top.txt
@@ -72,11 +72,11 @@ Default is to monitor all CPUS.
72 72
73-p <pid>:: 73-p <pid>::
74--pid=<pid>:: 74--pid=<pid>::
75 Profile events on existing Process ID. 75 Profile events on existing Process ID (comma separated list).
76 76
77-t <tid>:: 77-t <tid>::
78--tid=<tid>:: 78--tid=<tid>::
79 Profile events on existing thread ID. 79 Profile events on existing thread ID (comma separated list).
80 80
81-u:: 81-u::
82--uid=:: 82--uid=::
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index d6d1c6cdcfe6..08ed24b66ffe 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -645,8 +645,6 @@ static const char * const record_usage[] = {
645 */ 645 */
646static struct perf_record record = { 646static struct perf_record record = {
647 .opts = { 647 .opts = {
648 .target_pid = -1,
649 .target_tid = -1,
650 .mmap_pages = UINT_MAX, 648 .mmap_pages = UINT_MAX,
651 .user_freq = UINT_MAX, 649 .user_freq = UINT_MAX,
652 .user_interval = ULLONG_MAX, 650 .user_interval = ULLONG_MAX,
@@ -670,9 +668,9 @@ const struct option record_options[] = {
670 parse_events_option), 668 parse_events_option),
671 OPT_CALLBACK(0, "filter", &record.evlist, "filter", 669 OPT_CALLBACK(0, "filter", &record.evlist, "filter",
672 "event filter", parse_filter), 670 "event filter", parse_filter),
673 OPT_INTEGER('p', "pid", &record.opts.target_pid, 671 OPT_STRING('p', "pid", &record.opts.target_pid, "pid",
674 "record events on existing process id"), 672 "record events on existing process id"),
675 OPT_INTEGER('t', "tid", &record.opts.target_tid, 673 OPT_STRING('t', "tid", &record.opts.target_tid, "tid",
676 "record events on existing thread id"), 674 "record events on existing thread id"),
677 OPT_INTEGER('r', "realtime", &record.realtime_prio, 675 OPT_INTEGER('r', "realtime", &record.realtime_prio,
678 "collect data with this RT SCHED_FIFO priority"), 676 "collect data with this RT SCHED_FIFO priority"),
@@ -739,7 +737,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
739 737
740 argc = parse_options(argc, argv, record_options, record_usage, 738 argc = parse_options(argc, argv, record_options, record_usage,
741 PARSE_OPT_STOP_AT_NON_OPTION); 739 PARSE_OPT_STOP_AT_NON_OPTION);
742 if (!argc && rec->opts.target_pid == -1 && rec->opts.target_tid == -1 && 740 if (!argc && !rec->opts.target_pid && !rec->opts.target_tid &&
743 !rec->opts.system_wide && !rec->opts.cpu_list && !rec->uid_str) 741 !rec->opts.system_wide && !rec->opts.cpu_list && !rec->uid_str)
744 usage_with_options(record_usage, record_options); 742 usage_with_options(record_usage, record_options);
745 743
@@ -785,7 +783,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
785 if (rec->uid_str != NULL && rec->opts.uid == UINT_MAX - 1) 783 if (rec->uid_str != NULL && rec->opts.uid == UINT_MAX - 1)
786 goto out_free_fd; 784 goto out_free_fd;
787 785
788 if (rec->opts.target_pid != -1) 786 if (rec->opts.target_pid)
789 rec->opts.target_tid = rec->opts.target_pid; 787 rec->opts.target_tid = rec->opts.target_pid;
790 788
791 if (perf_evlist__create_maps(evsel_list, rec->opts.target_pid, 789 if (perf_evlist__create_maps(evsel_list, rec->opts.target_pid,
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index d14b37ad7638..ea40e4e8b227 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -182,8 +182,8 @@ static int run_count = 1;
182static bool no_inherit = false; 182static bool no_inherit = false;
183static bool scale = true; 183static bool scale = true;
184static bool no_aggr = false; 184static bool no_aggr = false;
185static pid_t target_pid = -1; 185static const char *target_pid;
186static pid_t target_tid = -1; 186static const char *target_tid;
187static pid_t child_pid = -1; 187static pid_t child_pid = -1;
188static bool null_run = false; 188static bool null_run = false;
189static int detailed_run = 0; 189static int detailed_run = 0;
@@ -296,7 +296,7 @@ static int create_perf_stat_counter(struct perf_evsel *evsel,
296 if (system_wide) 296 if (system_wide)
297 return perf_evsel__open_per_cpu(evsel, evsel_list->cpus, 297 return perf_evsel__open_per_cpu(evsel, evsel_list->cpus,
298 group, group_fd); 298 group, group_fd);
299 if (target_pid == -1 && target_tid == -1) { 299 if (!target_pid && !target_tid) {
300 attr->disabled = 1; 300 attr->disabled = 1;
301 attr->enable_on_exec = 1; 301 attr->enable_on_exec = 1;
302 } 302 }
@@ -446,7 +446,7 @@ static int run_perf_stat(int argc __used, const char **argv)
446 exit(-1); 446 exit(-1);
447 } 447 }
448 448
449 if (target_tid == -1 && target_pid == -1 && !system_wide) 449 if (!target_tid && !target_pid && !system_wide)
450 evsel_list->threads->map[0] = child_pid; 450 evsel_list->threads->map[0] = child_pid;
451 451
452 /* 452 /*
@@ -968,14 +968,14 @@ static void print_stat(int argc, const char **argv)
968 if (!csv_output) { 968 if (!csv_output) {
969 fprintf(output, "\n"); 969 fprintf(output, "\n");
970 fprintf(output, " Performance counter stats for "); 970 fprintf(output, " Performance counter stats for ");
971 if(target_pid == -1 && target_tid == -1) { 971 if (!target_pid && !target_tid) {
972 fprintf(output, "\'%s", argv[0]); 972 fprintf(output, "\'%s", argv[0]);
973 for (i = 1; i < argc; i++) 973 for (i = 1; i < argc; i++)
974 fprintf(output, " %s", argv[i]); 974 fprintf(output, " %s", argv[i]);
975 } else if (target_pid != -1) 975 } else if (target_pid)
976 fprintf(output, "process id \'%d", target_pid); 976 fprintf(output, "process id \'%s", target_pid);
977 else 977 else
978 fprintf(output, "thread id \'%d", target_tid); 978 fprintf(output, "thread id \'%s", target_tid);
979 979
980 fprintf(output, "\'"); 980 fprintf(output, "\'");
981 if (run_count > 1) 981 if (run_count > 1)
@@ -1049,10 +1049,10 @@ static const struct option options[] = {
1049 "event filter", parse_filter), 1049 "event filter", parse_filter),
1050 OPT_BOOLEAN('i', "no-inherit", &no_inherit, 1050 OPT_BOOLEAN('i', "no-inherit", &no_inherit,
1051 "child tasks do not inherit counters"), 1051 "child tasks do not inherit counters"),
1052 OPT_INTEGER('p', "pid", &target_pid, 1052 OPT_STRING('p', "pid", &target_pid, "pid",
1053 "stat events on existing process id"), 1053 "stat events on existing process id"),
1054 OPT_INTEGER('t', "tid", &target_tid, 1054 OPT_STRING('t', "tid", &target_tid, "tid",
1055 "stat events on existing thread id"), 1055 "stat events on existing thread id"),
1056 OPT_BOOLEAN('a', "all-cpus", &system_wide, 1056 OPT_BOOLEAN('a', "all-cpus", &system_wide,
1057 "system-wide collection from all CPUs"), 1057 "system-wide collection from all CPUs"),
1058 OPT_BOOLEAN('g', "group", &group, 1058 OPT_BOOLEAN('g', "group", &group,
@@ -1190,7 +1190,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
1190 } else if (big_num_opt == 0) /* User passed --no-big-num */ 1190 } else if (big_num_opt == 0) /* User passed --no-big-num */
1191 big_num = false; 1191 big_num = false;
1192 1192
1193 if (!argc && target_pid == -1 && target_tid == -1) 1193 if (!argc && !target_pid && !target_tid)
1194 usage_with_options(stat_usage, options); 1194 usage_with_options(stat_usage, options);
1195 if (run_count <= 0) 1195 if (run_count <= 0)
1196 usage_with_options(stat_usage, options); 1196 usage_with_options(stat_usage, options);
@@ -1206,10 +1206,11 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
1206 if (add_default_attributes()) 1206 if (add_default_attributes())
1207 goto out; 1207 goto out;
1208 1208
1209 if (target_pid != -1) 1209 if (target_pid)
1210 target_tid = target_pid; 1210 target_tid = target_pid;
1211 1211
1212 evsel_list->threads = thread_map__new(target_pid, target_tid, UINT_MAX); 1212 evsel_list->threads = thread_map__new_str(target_pid,
1213 target_tid, UINT_MAX);
1213 if (evsel_list->threads == NULL) { 1214 if (evsel_list->threads == NULL) {
1214 pr_err("Problems finding threads of monitor\n"); 1215 pr_err("Problems finding threads of monitor\n");
1215 usage_with_options(stat_usage, options); 1216 usage_with_options(stat_usage, options);
diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c
index 70c4eb2bdf72..0f151952a770 100644
--- a/tools/perf/builtin-test.c
+++ b/tools/perf/builtin-test.c
@@ -1010,8 +1010,6 @@ realloc:
1010static int test__PERF_RECORD(void) 1010static int test__PERF_RECORD(void)
1011{ 1011{
1012 struct perf_record_opts opts = { 1012 struct perf_record_opts opts = {
1013 .target_pid = -1,
1014 .target_tid = -1,
1015 .no_delay = true, 1013 .no_delay = true,
1016 .freq = 10, 1014 .freq = 10,
1017 .mmap_pages = 256, 1015 .mmap_pages = 256,
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index d869b214ada2..94d55cb2048c 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -965,7 +965,7 @@ static int __cmd_top(struct perf_top *top)
965 if (ret) 965 if (ret)
966 goto out_delete; 966 goto out_delete;
967 967
968 if (top->target_tid != -1 || top->uid != UINT_MAX) 968 if (top->target_tid || top->uid != UINT_MAX)
969 perf_event__synthesize_thread_map(&top->tool, top->evlist->threads, 969 perf_event__synthesize_thread_map(&top->tool, top->evlist->threads,
970 perf_event__process, 970 perf_event__process,
971 &top->session->host_machine); 971 &top->session->host_machine);
@@ -1103,8 +1103,6 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1103 struct perf_top top = { 1103 struct perf_top top = {
1104 .count_filter = 5, 1104 .count_filter = 5,
1105 .delay_secs = 2, 1105 .delay_secs = 2,
1106 .target_pid = -1,
1107 .target_tid = -1,
1108 .uid = UINT_MAX, 1106 .uid = UINT_MAX,
1109 .freq = 1000, /* 1 KHz */ 1107 .freq = 1000, /* 1 KHz */
1110 .sample_id_all_avail = true, 1108 .sample_id_all_avail = true,
@@ -1118,9 +1116,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1118 parse_events_option), 1116 parse_events_option),
1119 OPT_INTEGER('c', "count", &top.default_interval, 1117 OPT_INTEGER('c', "count", &top.default_interval,
1120 "event period to sample"), 1118 "event period to sample"),
1121 OPT_INTEGER('p', "pid", &top.target_pid, 1119 OPT_STRING('p', "pid", &top.target_pid, "pid",
1122 "profile events on existing process id"), 1120 "profile events on existing process id"),
1123 OPT_INTEGER('t', "tid", &top.target_tid, 1121 OPT_STRING('t', "tid", &top.target_tid, "tid",
1124 "profile events on existing thread id"), 1122 "profile events on existing thread id"),
1125 OPT_BOOLEAN('a', "all-cpus", &top.system_wide, 1123 OPT_BOOLEAN('a', "all-cpus", &top.system_wide,
1126 "system-wide collection from all CPUs"), 1124 "system-wide collection from all CPUs"),
@@ -1210,13 +1208,13 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1210 goto out_delete_evlist; 1208 goto out_delete_evlist;
1211 1209
1212 /* CPU and PID are mutually exclusive */ 1210 /* CPU and PID are mutually exclusive */
1213 if (top.target_tid > 0 && top.cpu_list) { 1211 if (top.target_tid && top.cpu_list) {
1214 printf("WARNING: PID switch overriding CPU\n"); 1212 printf("WARNING: PID switch overriding CPU\n");
1215 sleep(1); 1213 sleep(1);
1216 top.cpu_list = NULL; 1214 top.cpu_list = NULL;
1217 } 1215 }
1218 1216
1219 if (top.target_pid != -1) 1217 if (top.target_pid)
1220 top.target_tid = top.target_pid; 1218 top.target_tid = top.target_pid;
1221 1219
1222 if (perf_evlist__create_maps(top.evlist, top.target_pid, 1220 if (perf_evlist__create_maps(top.evlist, top.target_pid,
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index 92af1688bae4..deb17dba4a5b 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -186,8 +186,8 @@ extern const char perf_version_string[];
186void pthread__unblock_sigwinch(void); 186void pthread__unblock_sigwinch(void);
187 187
188struct perf_record_opts { 188struct perf_record_opts {
189 pid_t target_pid; 189 const char *target_pid;
190 pid_t target_tid; 190 const char *target_tid;
191 uid_t uid; 191 uid_t uid;
192 bool call_graph; 192 bool call_graph;
193 bool group; 193 bool group;
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index a57a8cfc5d90..5c61dc57d7c7 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -593,15 +593,15 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
593 return perf_evlist__mmap_per_cpu(evlist, prot, mask); 593 return perf_evlist__mmap_per_cpu(evlist, prot, mask);
594} 594}
595 595
596int perf_evlist__create_maps(struct perf_evlist *evlist, pid_t target_pid, 596int perf_evlist__create_maps(struct perf_evlist *evlist, const char *target_pid,
597 pid_t target_tid, uid_t uid, const char *cpu_list) 597 const char *target_tid, uid_t uid, const char *cpu_list)
598{ 598{
599 evlist->threads = thread_map__new(target_pid, target_tid, uid); 599 evlist->threads = thread_map__new_str(target_pid, target_tid, uid);
600 600
601 if (evlist->threads == NULL) 601 if (evlist->threads == NULL)
602 return -1; 602 return -1;
603 603
604 if (uid != UINT_MAX || (cpu_list == NULL && target_tid != -1)) 604 if (uid != UINT_MAX || (cpu_list == NULL && target_tid))
605 evlist->cpus = cpu_map__dummy_new(); 605 evlist->cpus = cpu_map__dummy_new();
606 else 606 else
607 evlist->cpus = cpu_map__new(cpu_list); 607 evlist->cpus = cpu_map__new(cpu_list);
@@ -820,7 +820,7 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist,
820 exit(-1); 820 exit(-1);
821 } 821 }
822 822
823 if (!opts->system_wide && opts->target_tid == -1 && opts->target_pid == -1) 823 if (!opts->system_wide && !opts->target_tid && !opts->target_pid)
824 evlist->threads->map[0] = evlist->workload.pid; 824 evlist->threads->map[0] = evlist->workload.pid;
825 825
826 close(child_ready_pipe[1]); 826 close(child_ready_pipe[1]);
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 1b4282be8fe7..21f1c9e57f13 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -106,8 +106,8 @@ static inline void perf_evlist__set_maps(struct perf_evlist *evlist,
106 evlist->threads = threads; 106 evlist->threads = threads;
107} 107}
108 108
109int perf_evlist__create_maps(struct perf_evlist *evlist, pid_t target_pid, 109int perf_evlist__create_maps(struct perf_evlist *evlist, const char *target_pid,
110 pid_t tid, uid_t uid, const char *cpu_list); 110 const char *tid, uid_t uid, const char *cpu_list);
111void perf_evlist__delete_maps(struct perf_evlist *evlist); 111void perf_evlist__delete_maps(struct perf_evlist *evlist);
112int perf_evlist__set_filters(struct perf_evlist *evlist); 112int perf_evlist__set_filters(struct perf_evlist *evlist);
113 113
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 9a11f9edac12..f910f50136d0 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -130,7 +130,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts)
130 attr->mmap = track; 130 attr->mmap = track;
131 attr->comm = track; 131 attr->comm = track;
132 132
133 if (opts->target_pid == -1 && opts->target_tid == -1 && !opts->system_wide) { 133 if (!opts->target_pid && !opts->target_tid && !opts->system_wide) {
134 attr->disabled = 1; 134 attr->disabled = 1;
135 attr->enable_on_exec = 1; 135 attr->enable_on_exec = 1;
136 } 136 }
diff --git a/tools/perf/util/python-ext-sources b/tools/perf/util/python-ext-sources
index ff606f482a7c..2884e67ee625 100644
--- a/tools/perf/util/python-ext-sources
+++ b/tools/perf/util/python-ext-sources
@@ -15,3 +15,5 @@ util/util.c
15util/xyarray.c 15util/xyarray.c
16util/cgroup.c 16util/cgroup.c
17util/debugfs.c 17util/debugfs.c
18util/strlist.c
19../../lib/rbtree.c
diff --git a/tools/perf/util/thread_map.c b/tools/perf/util/thread_map.c
index 3d4b6c5931b9..e15983cf077d 100644
--- a/tools/perf/util/thread_map.c
+++ b/tools/perf/util/thread_map.c
@@ -6,6 +6,8 @@
6#include <sys/types.h> 6#include <sys/types.h>
7#include <sys/stat.h> 7#include <sys/stat.h>
8#include <unistd.h> 8#include <unistd.h>
9#include "strlist.h"
10#include <string.h>
9#include "thread_map.h" 11#include "thread_map.h"
10 12
11/* Skip "." and ".." directories */ 13/* Skip "." and ".." directories */
@@ -152,6 +154,132 @@ struct thread_map *thread_map__new(pid_t pid, pid_t tid, uid_t uid)
152 return thread_map__new_by_tid(tid); 154 return thread_map__new_by_tid(tid);
153} 155}
154 156
157static struct thread_map *thread_map__new_by_pid_str(const char *pid_str)
158{
159 struct thread_map *threads = NULL, *nt;
160 char name[256];
161 int items, total_tasks = 0;
162 struct dirent **namelist = NULL;
163 int i, j = 0;
164 pid_t pid, prev_pid = INT_MAX;
165 char *end_ptr;
166 struct str_node *pos;
167 struct strlist *slist = strlist__new(false, pid_str);
168
169 if (!slist)
170 return NULL;
171
172 strlist__for_each(pos, slist) {
173 pid = strtol(pos->s, &end_ptr, 10);
174
175 if (pid == INT_MIN || pid == INT_MAX ||
176 (*end_ptr != '\0' && *end_ptr != ','))
177 goto out_free_threads;
178
179 if (pid == prev_pid)
180 continue;
181
182 sprintf(name, "/proc/%d/task", pid);
183 items = scandir(name, &namelist, filter, NULL);
184 if (items <= 0)
185 goto out_free_threads;
186
187 total_tasks += items;
188 nt = realloc(threads, (sizeof(*threads) +
189 sizeof(pid_t) * total_tasks));
190 if (nt == NULL)
191 goto out_free_threads;
192
193 threads = nt;
194
195 if (threads) {
196 for (i = 0; i < items; i++)
197 threads->map[j++] = atoi(namelist[i]->d_name);
198 threads->nr = total_tasks;
199 }
200
201 for (i = 0; i < items; i++)
202 free(namelist[i]);
203 free(namelist);
204
205 if (!threads)
206 break;
207 }
208
209out:
210 strlist__delete(slist);
211 return threads;
212
213out_free_threads:
214 free(threads);
215 threads = NULL;
216 goto out;
217}
218
219static struct thread_map *thread_map__new_by_tid_str(const char *tid_str)
220{
221 struct thread_map *threads = NULL, *nt;
222 int ntasks = 0;
223 pid_t tid, prev_tid = INT_MAX;
224 char *end_ptr;
225 struct str_node *pos;
226 struct strlist *slist;
227
228 /* perf-stat expects threads to be generated even if tid not given */
229 if (!tid_str) {
230 threads = malloc(sizeof(*threads) + sizeof(pid_t));
231 if (threads != NULL) {
232 threads->map[1] = -1;
233 threads->nr = 1;
234 }
235 return threads;
236 }
237
238 slist = strlist__new(false, tid_str);
239 if (!slist)
240 return NULL;
241
242 strlist__for_each(pos, slist) {
243 tid = strtol(pos->s, &end_ptr, 10);
244
245 if (tid == INT_MIN || tid == INT_MAX ||
246 (*end_ptr != '\0' && *end_ptr != ','))
247 goto out_free_threads;
248
249 if (tid == prev_tid)
250 continue;
251
252 ntasks++;
253 nt = realloc(threads, sizeof(*threads) + sizeof(pid_t) * ntasks);
254
255 if (nt == NULL)
256 goto out_free_threads;
257
258 threads = nt;
259 threads->map[ntasks - 1] = tid;
260 threads->nr = ntasks;
261 }
262out:
263 return threads;
264
265out_free_threads:
266 free(threads);
267 threads = NULL;
268 goto out;
269}
270
271struct thread_map *thread_map__new_str(const char *pid, const char *tid,
272 uid_t uid)
273{
274 if (pid)
275 return thread_map__new_by_pid_str(pid);
276
277 if (!tid && uid != UINT_MAX)
278 return thread_map__new_by_uid(uid);
279
280 return thread_map__new_by_tid_str(tid);
281}
282
155void thread_map__delete(struct thread_map *threads) 283void thread_map__delete(struct thread_map *threads)
156{ 284{
157 free(threads); 285 free(threads);
diff --git a/tools/perf/util/thread_map.h b/tools/perf/util/thread_map.h
index c75ddbaba005..7da80f14418b 100644
--- a/tools/perf/util/thread_map.h
+++ b/tools/perf/util/thread_map.h
@@ -13,6 +13,10 @@ struct thread_map *thread_map__new_by_pid(pid_t pid);
13struct thread_map *thread_map__new_by_tid(pid_t tid); 13struct thread_map *thread_map__new_by_tid(pid_t tid);
14struct thread_map *thread_map__new_by_uid(uid_t uid); 14struct thread_map *thread_map__new_by_uid(uid_t uid);
15struct thread_map *thread_map__new(pid_t pid, pid_t tid, uid_t uid); 15struct thread_map *thread_map__new(pid_t pid, pid_t tid, uid_t uid);
16
17struct thread_map *thread_map__new_str(const char *pid,
18 const char *tid, uid_t uid);
19
16void thread_map__delete(struct thread_map *threads); 20void thread_map__delete(struct thread_map *threads);
17 21
18size_t thread_map__fprintf(struct thread_map *threads, FILE *fp); 22size_t thread_map__fprintf(struct thread_map *threads, FILE *fp);
diff --git a/tools/perf/util/top.c b/tools/perf/util/top.c
index e4370ca27193..09fe579ccafb 100644
--- a/tools/perf/util/top.c
+++ b/tools/perf/util/top.c
@@ -69,11 +69,11 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size)
69 69
70 ret += SNPRINTF(bf + ret, size - ret, "], "); 70 ret += SNPRINTF(bf + ret, size - ret, "], ");
71 71
72 if (top->target_pid != -1) 72 if (top->target_pid)
73 ret += SNPRINTF(bf + ret, size - ret, " (target_pid: %d", 73 ret += SNPRINTF(bf + ret, size - ret, " (target_pid: %s",
74 top->target_pid); 74 top->target_pid);
75 else if (top->target_tid != -1) 75 else if (top->target_tid)
76 ret += SNPRINTF(bf + ret, size - ret, " (target_tid: %d", 76 ret += SNPRINTF(bf + ret, size - ret, " (target_tid: %s",
77 top->target_tid); 77 top->target_tid);
78 else if (top->uid_str != NULL) 78 else if (top->uid_str != NULL)
79 ret += SNPRINTF(bf + ret, size - ret, " (uid: %s", 79 ret += SNPRINTF(bf + ret, size - ret, " (uid: %s",
@@ -85,7 +85,7 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size)
85 ret += SNPRINTF(bf + ret, size - ret, ", CPU%s: %s)", 85 ret += SNPRINTF(bf + ret, size - ret, ", CPU%s: %s)",
86 top->evlist->cpus->nr > 1 ? "s" : "", top->cpu_list); 86 top->evlist->cpus->nr > 1 ? "s" : "", top->cpu_list);
87 else { 87 else {
88 if (top->target_tid != -1) 88 if (top->target_tid)
89 ret += SNPRINTF(bf + ret, size - ret, ")"); 89 ret += SNPRINTF(bf + ret, size - ret, ")");
90 else 90 else
91 ret += SNPRINTF(bf + ret, size - ret, ", %d CPU%s)", 91 ret += SNPRINTF(bf + ret, size - ret, ", %d CPU%s)",
diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h
index def3e53e0fe0..49eb8481f19f 100644
--- a/tools/perf/util/top.h
+++ b/tools/perf/util/top.h
@@ -23,7 +23,7 @@ struct perf_top {
23 u64 guest_us_samples, guest_kernel_samples; 23 u64 guest_us_samples, guest_kernel_samples;
24 int print_entries, count_filter, delay_secs; 24 int print_entries, count_filter, delay_secs;
25 int freq; 25 int freq;
26 pid_t target_pid, target_tid; 26 const char *target_pid, *target_tid;
27 uid_t uid; 27 uid_t uid;
28 bool hide_kernel_symbols, hide_user_symbols, zero; 28 bool hide_kernel_symbols, hide_user_symbols, zero;
29 bool system_wide; 29 bool system_wide;
diff --git a/tools/perf/util/usage.c b/tools/perf/util/usage.c
index d0c013934f30..52bb07c6442a 100644
--- a/tools/perf/util/usage.c
+++ b/tools/perf/util/usage.c
@@ -83,7 +83,7 @@ void warning(const char *warn, ...)
83 va_end(params); 83 va_end(params);
84} 84}
85 85
86uid_t parse_target_uid(const char *str, pid_t tid, pid_t pid) 86uid_t parse_target_uid(const char *str, const char *tid, const char *pid)
87{ 87{
88 struct passwd pwd, *result; 88 struct passwd pwd, *result;
89 char buf[1024]; 89 char buf[1024];
@@ -91,8 +91,8 @@ uid_t parse_target_uid(const char *str, pid_t tid, pid_t pid)
91 if (str == NULL) 91 if (str == NULL)
92 return UINT_MAX; 92 return UINT_MAX;
93 93
94 /* CPU and PID are mutually exclusive */ 94 /* UID and PID are mutually exclusive */
95 if (tid > 0 || pid > 0) { 95 if (tid || pid) {
96 ui__warning("PID/TID switch overriding UID\n"); 96 ui__warning("PID/TID switch overriding UID\n");
97 sleep(1); 97 sleep(1);
98 return UINT_MAX; 98 return UINT_MAX;
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index 232d17ef3e60..7917b09430bd 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -245,7 +245,7 @@ struct perf_event_attr;
245 245
246void event_attr_init(struct perf_event_attr *attr); 246void event_attr_init(struct perf_event_attr *attr);
247 247
248uid_t parse_target_uid(const char *str, pid_t tid, pid_t pid); 248uid_t parse_target_uid(const char *str, const char *tid, const char *pid);
249 249
250#define _STR(x) #x 250#define _STR(x) #x
251#define STR(x) _STR(x) 251#define STR(x) _STR(x)