aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf
diff options
context:
space:
mode:
authorArnaldo Carvalho de Melo <acme@redhat.com>2012-01-19 11:08:15 -0500
committerArnaldo Carvalho de Melo <acme@redhat.com>2012-01-24 16:47:37 -0500
commit0d37aa34f8806bb443dd3c8621fd9bdbb50c58bb (patch)
tree3e245385cdb75fec299f5e145243f062b70fd652 /tools/perf
parent9ae7d3351aac238eef9646479693105688fd9cc9 (diff)
perf tools: Introduce per user view
The new --uid command line option will show only the tasks for a given user, using the proc interface to figure out the existing tasks. Kernel work is needed to close races at startup, but this should already be useful in many use cases. Cc: David Ahern <dsahern@gmail.com> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Mike Galbraith <efault@gmx.de> Cc: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Stephane Eranian <eranian@google.com> Link: http://lkml.kernel.org/n/tip-bdnspm000gw2l984a2t53o8z@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf')
-rw-r--r--tools/perf/Documentation/perf-record.txt4
-rw-r--r--tools/perf/Documentation/perf-top.txt4
-rw-r--r--tools/perf/builtin-record.c12
-rw-r--r--tools/perf/builtin-stat.c2
-rw-r--r--tools/perf/builtin-test.c8
-rw-r--r--tools/perf/builtin-top.c22
-rw-r--r--tools/perf/perf.h1
-rw-r--r--tools/perf/util/evlist.c6
-rw-r--r--tools/perf/util/evlist.h2
-rw-r--r--tools/perf/util/hist.h1
-rw-r--r--tools/perf/util/python.c10
-rw-r--r--tools/perf/util/thread_map.c98
-rw-r--r--tools/perf/util/thread_map.h3
-rw-r--r--tools/perf/util/top.c3
-rw-r--r--tools/perf/util/top.h2
-rw-r--r--tools/perf/util/ui/browsers/hists.c3
-rw-r--r--tools/perf/util/usage.c39
-rw-r--r--tools/perf/util/util.h2
18 files changed, 200 insertions, 22 deletions
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
index 2937f7e14bb7..ff9a66e0d4e4 100644
--- a/tools/perf/Documentation/perf-record.txt
+++ b/tools/perf/Documentation/perf-record.txt
@@ -58,6 +58,10 @@ OPTIONS
58--tid=:: 58--tid=::
59 Record events on existing thread ID. 59 Record events on existing thread ID.
60 60
61-u::
62--uid=::
63 Record events in threads owned by uid. Name or number.
64
61-r:: 65-r::
62--realtime=:: 66--realtime=::
63 Collect data with this RT SCHED_FIFO priority. 67 Collect data with this RT SCHED_FIFO priority.
diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt
index b1a5bbbfebef..ab1454ed450f 100644
--- a/tools/perf/Documentation/perf-top.txt
+++ b/tools/perf/Documentation/perf-top.txt
@@ -78,6 +78,10 @@ Default is to monitor all CPUS.
78--tid=<tid>:: 78--tid=<tid>::
79 Profile events on existing thread ID. 79 Profile events on existing thread ID.
80 80
81-u::
82--uid=::
83 Record events in threads owned by uid. Name or number.
84
81-r <priority>:: 85-r <priority>::
82--realtime=<priority>:: 86--realtime=<priority>::
83 Collect data with this RT SCHED_FIFO priority. 87 Collect data with this RT SCHED_FIFO priority.
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 0abfb18b911f..32870eef952f 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -44,6 +44,7 @@ struct perf_record {
44 struct perf_evlist *evlist; 44 struct perf_evlist *evlist;
45 struct perf_session *session; 45 struct perf_session *session;
46 const char *progname; 46 const char *progname;
47 const char *uid_str;
47 int output; 48 int output;
48 unsigned int page_size; 49 unsigned int page_size;
49 int realtime_prio; 50 int realtime_prio;
@@ -727,6 +728,7 @@ const struct option record_options[] = {
727 OPT_CALLBACK('G', "cgroup", &record.evlist, "name", 728 OPT_CALLBACK('G', "cgroup", &record.evlist, "name",
728 "monitor event in cgroup name only", 729 "monitor event in cgroup name only",
729 parse_cgroups), 730 parse_cgroups),
731 OPT_STRING('u', "uid", &record.uid_str, "user", "user to profile"),
730 OPT_END() 732 OPT_END()
731}; 733};
732 734
@@ -748,7 +750,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
748 argc = parse_options(argc, argv, record_options, record_usage, 750 argc = parse_options(argc, argv, record_options, record_usage,
749 PARSE_OPT_STOP_AT_NON_OPTION); 751 PARSE_OPT_STOP_AT_NON_OPTION);
750 if (!argc && rec->opts.target_pid == -1 && rec->opts.target_tid == -1 && 752 if (!argc && rec->opts.target_pid == -1 && rec->opts.target_tid == -1 &&
751 !rec->opts.system_wide && !rec->opts.cpu_list) 753 !rec->opts.system_wide && !rec->opts.cpu_list && !rec->uid_str)
752 usage_with_options(record_usage, record_options); 754 usage_with_options(record_usage, record_options);
753 755
754 if (rec->force && rec->append_file) { 756 if (rec->force && rec->append_file) {
@@ -788,11 +790,17 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
788 goto out_symbol_exit; 790 goto out_symbol_exit;
789 } 791 }
790 792
793 rec->opts.uid = parse_target_uid(rec->uid_str, rec->opts.target_tid,
794 rec->opts.target_pid);
795 if (rec->uid_str != NULL && rec->opts.uid == UINT_MAX - 1)
796 goto out_free_fd;
797
791 if (rec->opts.target_pid != -1) 798 if (rec->opts.target_pid != -1)
792 rec->opts.target_tid = rec->opts.target_pid; 799 rec->opts.target_tid = rec->opts.target_pid;
793 800
794 if (perf_evlist__create_maps(evsel_list, rec->opts.target_pid, 801 if (perf_evlist__create_maps(evsel_list, rec->opts.target_pid,
795 rec->opts.target_tid, rec->opts.cpu_list) < 0) 802 rec->opts.target_tid, rec->opts.uid,
803 rec->opts.cpu_list) < 0)
796 usage_with_options(record_usage, record_options); 804 usage_with_options(record_usage, record_options);
797 805
798 list_for_each_entry(pos, &evsel_list->entries, node) { 806 list_for_each_entry(pos, &evsel_list->entries, node) {
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index f5d2a63eba66..459b8620a5d9 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -1201,7 +1201,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
1201 if (target_pid != -1) 1201 if (target_pid != -1)
1202 target_tid = target_pid; 1202 target_tid = target_pid;
1203 1203
1204 evsel_list->threads = thread_map__new(target_pid, target_tid); 1204 evsel_list->threads = thread_map__new(target_pid, target_tid, UINT_MAX);
1205 if (evsel_list->threads == NULL) { 1205 if (evsel_list->threads == NULL) {
1206 pr_err("Problems finding threads of monitor\n"); 1206 pr_err("Problems finding threads of monitor\n");
1207 usage_with_options(stat_usage, options); 1207 usage_with_options(stat_usage, options);
diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c
index 3854e869dce1..3ce709e97462 100644
--- a/tools/perf/builtin-test.c
+++ b/tools/perf/builtin-test.c
@@ -276,7 +276,7 @@ static int test__open_syscall_event(void)
276 return -1; 276 return -1;
277 } 277 }
278 278
279 threads = thread_map__new(-1, getpid()); 279 threads = thread_map__new(-1, getpid(), UINT_MAX);
280 if (threads == NULL) { 280 if (threads == NULL) {
281 pr_debug("thread_map__new\n"); 281 pr_debug("thread_map__new\n");
282 return -1; 282 return -1;
@@ -342,7 +342,7 @@ static int test__open_syscall_event_on_all_cpus(void)
342 return -1; 342 return -1;
343 } 343 }
344 344
345 threads = thread_map__new(-1, getpid()); 345 threads = thread_map__new(-1, getpid(), UINT_MAX);
346 if (threads == NULL) { 346 if (threads == NULL) {
347 pr_debug("thread_map__new\n"); 347 pr_debug("thread_map__new\n");
348 return -1; 348 return -1;
@@ -490,7 +490,7 @@ static int test__basic_mmap(void)
490 expected_nr_events[i] = random() % 257; 490 expected_nr_events[i] = random() % 257;
491 } 491 }
492 492
493 threads = thread_map__new(-1, getpid()); 493 threads = thread_map__new(-1, getpid(), UINT_MAX);
494 if (threads == NULL) { 494 if (threads == NULL) {
495 pr_debug("thread_map__new\n"); 495 pr_debug("thread_map__new\n");
496 return -1; 496 return -1;
@@ -1054,7 +1054,7 @@ static int test__PERF_RECORD(void)
1054 * we're monitoring, the one forked there. 1054 * we're monitoring, the one forked there.
1055 */ 1055 */
1056 err = perf_evlist__create_maps(evlist, opts.target_pid, 1056 err = perf_evlist__create_maps(evlist, opts.target_pid,
1057 opts.target_tid, opts.cpu_list); 1057 opts.target_tid, UINT_MAX, opts.cpu_list);
1058 if (err < 0) { 1058 if (err < 0) {
1059 pr_debug("Not enough memory to create thread/cpu maps\n"); 1059 pr_debug("Not enough memory to create thread/cpu maps\n");
1060 goto out_delete_evlist; 1060 goto out_delete_evlist;
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 8f80df896038..e8b033c074f9 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -64,7 +64,6 @@
64#include <linux/unistd.h> 64#include <linux/unistd.h>
65#include <linux/types.h> 65#include <linux/types.h>
66 66
67
68void get_term_dimensions(struct winsize *ws) 67void get_term_dimensions(struct winsize *ws)
69{ 68{
70 char *s = getenv("LINES"); 69 char *s = getenv("LINES");
@@ -537,10 +536,20 @@ static void perf_top__sort_new_samples(void *arg)
537 536
538static void *display_thread_tui(void *arg) 537static void *display_thread_tui(void *arg)
539{ 538{
539 struct perf_evsel *pos;
540 struct perf_top *top = arg; 540 struct perf_top *top = arg;
541 const char *help = "For a higher level overview, try: perf top --sort comm,dso"; 541 const char *help = "For a higher level overview, try: perf top --sort comm,dso";
542 542
543 perf_top__sort_new_samples(top); 543 perf_top__sort_new_samples(top);
544
545 /*
546 * Initialize the uid_filter_str, in the future the TUI will allow
547 * Zooming in/out UIDs. For now juse use whatever the user passed
548 * via --uid.
549 */
550 list_for_each_entry(pos, &top->evlist->entries, node)
551 pos->hists.uid_filter_str = top->uid_str;
552
544 perf_evlist__tui_browse_hists(top->evlist, help, 553 perf_evlist__tui_browse_hists(top->evlist, help,
545 perf_top__sort_new_samples, 554 perf_top__sort_new_samples,
546 top, top->delay_secs); 555 top, top->delay_secs);
@@ -949,7 +958,7 @@ static int __cmd_top(struct perf_top *top)
949 if (ret) 958 if (ret)
950 goto out_delete; 959 goto out_delete;
951 960
952 if (top->target_tid != -1) 961 if (top->target_tid != -1 || top->uid != UINT_MAX)
953 perf_event__synthesize_thread_map(&top->tool, top->evlist->threads, 962 perf_event__synthesize_thread_map(&top->tool, top->evlist->threads,
954 perf_event__process, 963 perf_event__process,
955 &top->session->host_machine); 964 &top->session->host_machine);
@@ -1089,6 +1098,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1089 .delay_secs = 2, 1098 .delay_secs = 2,
1090 .target_pid = -1, 1099 .target_pid = -1,
1091 .target_tid = -1, 1100 .target_tid = -1,
1101 .uid = UINT_MAX,
1092 .freq = 1000, /* 1 KHz */ 1102 .freq = 1000, /* 1 KHz */
1093 .sample_id_all_avail = true, 1103 .sample_id_all_avail = true,
1094 .mmap_pages = 128, 1104 .mmap_pages = 128,
@@ -1162,6 +1172,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1162 "Display raw encoding of assembly instructions (default)"), 1172 "Display raw encoding of assembly instructions (default)"),
1163 OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", 1173 OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
1164 "Specify disassembler style (e.g. -M intel for intel syntax)"), 1174 "Specify disassembler style (e.g. -M intel for intel syntax)"),
1175 OPT_STRING('u', "uid", &top.uid_str, "user", "user to profile"),
1165 OPT_END() 1176 OPT_END()
1166 }; 1177 };
1167 1178
@@ -1187,6 +1198,10 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1187 1198
1188 setup_browser(false); 1199 setup_browser(false);
1189 1200
1201 top.uid = parse_target_uid(top.uid_str, top.target_tid, top.target_pid);
1202 if (top.uid_str != NULL && top.uid == UINT_MAX - 1)
1203 goto out_delete_evlist;
1204
1190 /* CPU and PID are mutually exclusive */ 1205 /* CPU and PID are mutually exclusive */
1191 if (top.target_tid > 0 && top.cpu_list) { 1206 if (top.target_tid > 0 && top.cpu_list) {
1192 printf("WARNING: PID switch overriding CPU\n"); 1207 printf("WARNING: PID switch overriding CPU\n");
@@ -1198,7 +1213,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1198 top.target_tid = top.target_pid; 1213 top.target_tid = top.target_pid;
1199 1214
1200 if (perf_evlist__create_maps(top.evlist, top.target_pid, 1215 if (perf_evlist__create_maps(top.evlist, top.target_pid,
1201 top.target_tid, top.cpu_list) < 0) 1216 top.target_tid, top.uid, top.cpu_list) < 0)
1202 usage_with_options(top_usage, options); 1217 usage_with_options(top_usage, options);
1203 1218
1204 if (!top.evlist->nr_entries && 1219 if (!top.evlist->nr_entries &&
@@ -1262,6 +1277,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
1262 1277
1263 status = __cmd_top(&top); 1278 status = __cmd_top(&top);
1264 1279
1280out_delete_evlist:
1265 perf_evlist__delete(top.evlist); 1281 perf_evlist__delete(top.evlist);
1266 1282
1267 return status; 1283 return status;
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index 64f8bee31ced..92af1688bae4 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -188,6 +188,7 @@ void pthread__unblock_sigwinch(void);
188struct perf_record_opts { 188struct perf_record_opts {
189 pid_t target_pid; 189 pid_t target_pid;
190 pid_t target_tid; 190 pid_t target_tid;
191 uid_t uid;
191 bool call_graph; 192 bool call_graph;
192 bool group; 193 bool group;
193 bool inherit_stat; 194 bool inherit_stat;
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 3f16e08a5c8d..a6d50e376257 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -594,14 +594,14 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
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, pid_t target_pid,
597 pid_t target_tid, const char *cpu_list) 597 pid_t target_tid, uid_t uid, const char *cpu_list)
598{ 598{
599 evlist->threads = thread_map__new(target_pid, target_tid); 599 evlist->threads = thread_map__new(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 (cpu_list == NULL && target_tid != -1) 604 if (uid != UINT_MAX || (cpu_list == NULL && target_tid != -1))
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);
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index 8922aeed0467..9c516607ce20 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -107,7 +107,7 @@ static inline void perf_evlist__set_maps(struct perf_evlist *evlist,
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, pid_t target_pid,
110 pid_t target_tid, const char *cpu_list); 110 pid_t 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/hist.h b/tools/perf/util/hist.h
index f55f0a8d1f81..0d486135d10f 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -55,6 +55,7 @@ struct hists {
55 u64 nr_entries; 55 u64 nr_entries;
56 const struct thread *thread_filter; 56 const struct thread *thread_filter;
57 const struct dso *dso_filter; 57 const struct dso *dso_filter;
58 const char *uid_filter_str;
58 pthread_mutex_t lock; 59 pthread_mutex_t lock;
59 struct events_stats stats; 60 struct events_stats stats;
60 u64 event_stream; 61 u64 event_stream;
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c
index 9dd47a4f2596..e03b58a48424 100644
--- a/tools/perf/util/python.c
+++ b/tools/perf/util/python.c
@@ -425,14 +425,14 @@ struct pyrf_thread_map {
425static int pyrf_thread_map__init(struct pyrf_thread_map *pthreads, 425static int pyrf_thread_map__init(struct pyrf_thread_map *pthreads,
426 PyObject *args, PyObject *kwargs) 426 PyObject *args, PyObject *kwargs)
427{ 427{
428 static char *kwlist[] = { "pid", "tid", NULL }; 428 static char *kwlist[] = { "pid", "tid", "uid", NULL };
429 int pid = -1, tid = -1; 429 int pid = -1, tid = -1, uid = UINT_MAX;
430 430
431 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ii", 431 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|iii",
432 kwlist, &pid, &tid)) 432 kwlist, &pid, &tid, &uid))
433 return -1; 433 return -1;
434 434
435 pthreads->threads = thread_map__new(pid, tid); 435 pthreads->threads = thread_map__new(pid, tid, uid);
436 if (pthreads->threads == NULL) 436 if (pthreads->threads == NULL)
437 return -1; 437 return -1;
438 return 0; 438 return 0;
diff --git a/tools/perf/util/thread_map.c b/tools/perf/util/thread_map.c
index 894d52f65166..3d4b6c5931b9 100644
--- a/tools/perf/util/thread_map.c
+++ b/tools/perf/util/thread_map.c
@@ -1,6 +1,11 @@
1#include <dirent.h> 1#include <dirent.h>
2#include <limits.h>
3#include <stdbool.h>
2#include <stdlib.h> 4#include <stdlib.h>
3#include <stdio.h> 5#include <stdio.h>
6#include <sys/types.h>
7#include <sys/stat.h>
8#include <unistd.h>
4#include "thread_map.h" 9#include "thread_map.h"
5 10
6/* Skip "." and ".." directories */ 11/* Skip "." and ".." directories */
@@ -23,7 +28,7 @@ struct thread_map *thread_map__new_by_pid(pid_t pid)
23 sprintf(name, "/proc/%d/task", pid); 28 sprintf(name, "/proc/%d/task", pid);
24 items = scandir(name, &namelist, filter, NULL); 29 items = scandir(name, &namelist, filter, NULL);
25 if (items <= 0) 30 if (items <= 0)
26 return NULL; 31 return NULL;
27 32
28 threads = malloc(sizeof(*threads) + sizeof(pid_t) * items); 33 threads = malloc(sizeof(*threads) + sizeof(pid_t) * items);
29 if (threads != NULL) { 34 if (threads != NULL) {
@@ -51,10 +56,99 @@ struct thread_map *thread_map__new_by_tid(pid_t tid)
51 return threads; 56 return threads;
52} 57}
53 58
54struct thread_map *thread_map__new(pid_t pid, pid_t tid) 59struct thread_map *thread_map__new_by_uid(uid_t uid)
60{
61 DIR *proc;
62 int max_threads = 32, items, i;
63 char path[256];
64 struct dirent dirent, *next, **namelist = NULL;
65 struct thread_map *threads = malloc(sizeof(*threads) +
66 max_threads * sizeof(pid_t));
67 if (threads == NULL)
68 goto out;
69
70 proc = opendir("/proc");
71 if (proc == NULL)
72 goto out_free_threads;
73
74 threads->nr = 0;
75
76 while (!readdir_r(proc, &dirent, &next) && next) {
77 char *end;
78 bool grow = false;
79 struct stat st;
80 pid_t pid = strtol(dirent.d_name, &end, 10);
81
82 if (*end) /* only interested in proper numerical dirents */
83 continue;
84
85 snprintf(path, sizeof(path), "/proc/%s", dirent.d_name);
86
87 if (stat(path, &st) != 0)
88 continue;
89
90 if (st.st_uid != uid)
91 continue;
92
93 snprintf(path, sizeof(path), "/proc/%d/task", pid);
94 items = scandir(path, &namelist, filter, NULL);
95 if (items <= 0)
96 goto out_free_closedir;
97
98 while (threads->nr + items >= max_threads) {
99 max_threads *= 2;
100 grow = true;
101 }
102
103 if (grow) {
104 struct thread_map *tmp;
105
106 tmp = realloc(threads, (sizeof(*threads) +
107 max_threads * sizeof(pid_t)));
108 if (tmp == NULL)
109 goto out_free_namelist;
110
111 threads = tmp;
112 }
113
114 for (i = 0; i < items; i++)
115 threads->map[threads->nr + i] = atoi(namelist[i]->d_name);
116
117 for (i = 0; i < items; i++)
118 free(namelist[i]);
119 free(namelist);
120
121 threads->nr += items;
122 }
123
124out_closedir:
125 closedir(proc);
126out:
127 return threads;
128
129out_free_threads:
130 free(threads);
131 return NULL;
132
133out_free_namelist:
134 for (i = 0; i < items; i++)
135 free(namelist[i]);
136 free(namelist);
137
138out_free_closedir:
139 free(threads);
140 threads = NULL;
141 goto out_closedir;
142}
143
144struct thread_map *thread_map__new(pid_t pid, pid_t tid, uid_t uid)
55{ 145{
56 if (pid != -1) 146 if (pid != -1)
57 return thread_map__new_by_pid(pid); 147 return thread_map__new_by_pid(pid);
148
149 if (tid == -1 && uid != UINT_MAX)
150 return thread_map__new_by_uid(uid);
151
58 return thread_map__new_by_tid(tid); 152 return thread_map__new_by_tid(tid);
59} 153}
60 154
diff --git a/tools/perf/util/thread_map.h b/tools/perf/util/thread_map.h
index 736ab4a26210..c75ddbaba005 100644
--- a/tools/perf/util/thread_map.h
+++ b/tools/perf/util/thread_map.h
@@ -11,7 +11,8 @@ struct thread_map {
11 11
12struct thread_map *thread_map__new_by_pid(pid_t pid); 12struct 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(pid_t pid, pid_t tid); 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);
15void thread_map__delete(struct thread_map *threads); 16void thread_map__delete(struct thread_map *threads);
16 17
17size_t thread_map__fprintf(struct thread_map *threads, FILE *fp); 18size_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 500471dffa4f..e4370ca27193 100644
--- a/tools/perf/util/top.c
+++ b/tools/perf/util/top.c
@@ -75,6 +75,9 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size)
75 else if (top->target_tid != -1) 75 else if (top->target_tid != -1)
76 ret += SNPRINTF(bf + ret, size - ret, " (target_tid: %d", 76 ret += SNPRINTF(bf + ret, size - ret, " (target_tid: %d",
77 top->target_tid); 77 top->target_tid);
78 else if (top->uid_str != NULL)
79 ret += SNPRINTF(bf + ret, size - ret, " (uid: %s",
80 top->uid_str);
78 else 81 else
79 ret += SNPRINTF(bf + ret, size - ret, " (all"); 82 ret += SNPRINTF(bf + ret, size - ret, " (all");
80 83
diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h
index a248f3c2c60d..def3e53e0fe0 100644
--- a/tools/perf/util/top.h
+++ b/tools/perf/util/top.h
@@ -24,6 +24,7 @@ struct perf_top {
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 pid_t target_pid, target_tid;
27 uid_t uid;
27 bool hide_kernel_symbols, hide_user_symbols, zero; 28 bool hide_kernel_symbols, hide_user_symbols, zero;
28 bool system_wide; 29 bool system_wide;
29 bool use_tui, use_stdio; 30 bool use_tui, use_stdio;
@@ -45,6 +46,7 @@ struct perf_top {
45 int realtime_prio; 46 int realtime_prio;
46 int sym_pcnt_filter; 47 int sym_pcnt_filter;
47 const char *sym_filter; 48 const char *sym_filter;
49 const char *uid_str;
48}; 50};
49 51
50size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size); 52size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size);
diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c
index 1212a386a033..7b6669d1f11f 100644
--- a/tools/perf/util/ui/browsers/hists.c
+++ b/tools/perf/util/ui/browsers/hists.c
@@ -841,6 +841,9 @@ static int hists__browser_title(struct hists *self, char *bf, size_t size,
841 nr_events = convert_unit(nr_events, &unit); 841 nr_events = convert_unit(nr_events, &unit);
842 printed = snprintf(bf, size, "Events: %lu%c %s", nr_events, unit, ev_name); 842 printed = snprintf(bf, size, "Events: %lu%c %s", nr_events, unit, ev_name);
843 843
844 if (self->uid_filter_str)
845 printed += snprintf(bf + printed, size - printed,
846 ", UID: %s", self->uid_filter_str);
844 if (thread) 847 if (thread)
845 printed += snprintf(bf + printed, size - printed, 848 printed += snprintf(bf + printed, size - printed,
846 ", Thread: %s(%d)", 849 ", Thread: %s(%d)",
diff --git a/tools/perf/util/usage.c b/tools/perf/util/usage.c
index d76d1c0ff98f..d0c013934f30 100644
--- a/tools/perf/util/usage.c
+++ b/tools/perf/util/usage.c
@@ -7,6 +7,7 @@
7 * Copyright (C) Linus Torvalds, 2005 7 * Copyright (C) Linus Torvalds, 2005
8 */ 8 */
9#include "util.h" 9#include "util.h"
10#include "debug.h"
10 11
11static void report(const char *prefix, const char *err, va_list params) 12static void report(const char *prefix, const char *err, va_list params)
12{ 13{
@@ -81,3 +82,41 @@ void warning(const char *warn, ...)
81 warn_routine(warn, params); 82 warn_routine(warn, params);
82 va_end(params); 83 va_end(params);
83} 84}
85
86uid_t parse_target_uid(const char *str, pid_t tid, pid_t pid)
87{
88 struct passwd pwd, *result;
89 char buf[1024];
90
91 if (str == NULL)
92 return UINT_MAX;
93
94 /* CPU and PID are mutually exclusive */
95 if (tid > 0 || pid > 0) {
96 ui__warning("PID/TID switch overriding UID\n");
97 sleep(1);
98 return UINT_MAX;
99 }
100
101 getpwnam_r(str, &pwd, buf, sizeof(buf), &result);
102
103 if (result == NULL) {
104 char *endptr;
105 int uid = strtol(str, &endptr, 10);
106
107 if (*endptr != '\0') {
108 ui__error("Invalid user %s\n", str);
109 return UINT_MAX - 1;
110 }
111
112 getpwuid_r(uid, &pwd, buf, sizeof(buf), &result);
113
114 if (result == NULL) {
115 ui__error("Problems obtaining information for user %s\n",
116 str);
117 return UINT_MAX - 1;
118 }
119 }
120
121 return result->pw_uid;
122}
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index b9c530cce79a..061dbf8c038d 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -246,6 +246,8 @@ struct perf_event_attr;
246 246
247void event_attr_init(struct perf_event_attr *attr); 247void event_attr_init(struct perf_event_attr *attr);
248 248
249uid_t parse_target_uid(const char *str, pid_t tid, pid_t pid);
250
249#define _STR(x) #x 251#define _STR(x) #x
250#define STR(x) _STR(x) 252#define STR(x) _STR(x)
251 253