diff options
Diffstat (limited to 'tools/perf')
-rw-r--r-- | tools/perf/Documentation/perf-record.txt | 4 | ||||
-rw-r--r-- | tools/perf/Documentation/perf-top.txt | 4 | ||||
-rw-r--r-- | tools/perf/builtin-record.c | 12 | ||||
-rw-r--r-- | tools/perf/builtin-stat.c | 2 | ||||
-rw-r--r-- | tools/perf/builtin-test.c | 8 | ||||
-rw-r--r-- | tools/perf/builtin-top.c | 22 | ||||
-rw-r--r-- | tools/perf/perf.h | 1 | ||||
-rw-r--r-- | tools/perf/util/evlist.c | 6 | ||||
-rw-r--r-- | tools/perf/util/evlist.h | 2 | ||||
-rw-r--r-- | tools/perf/util/hist.h | 1 | ||||
-rw-r--r-- | tools/perf/util/python.c | 10 | ||||
-rw-r--r-- | tools/perf/util/thread_map.c | 98 | ||||
-rw-r--r-- | tools/perf/util/thread_map.h | 3 | ||||
-rw-r--r-- | tools/perf/util/top.c | 3 | ||||
-rw-r--r-- | tools/perf/util/top.h | 2 | ||||
-rw-r--r-- | tools/perf/util/ui/browsers/hists.c | 3 | ||||
-rw-r--r-- | tools/perf/util/usage.c | 39 | ||||
-rw-r--r-- | tools/perf/util/util.h | 2 |
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 | |||
68 | void get_term_dimensions(struct winsize *ws) | 67 | void 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 | ||
538 | static void *display_thread_tui(void *arg) | 537 | static 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 | ||
1280 | out_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); | |||
188 | struct perf_record_opts { | 188 | struct 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 | ||
596 | int perf_evlist__create_maps(struct perf_evlist *evlist, pid_t target_pid, | 596 | int 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 | ||
109 | int perf_evlist__create_maps(struct perf_evlist *evlist, pid_t target_pid, | 109 | int 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); |
111 | void perf_evlist__delete_maps(struct perf_evlist *evlist); | 111 | void perf_evlist__delete_maps(struct perf_evlist *evlist); |
112 | int perf_evlist__set_filters(struct perf_evlist *evlist); | 112 | int 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 { | |||
425 | static int pyrf_thread_map__init(struct pyrf_thread_map *pthreads, | 425 | static 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 | ||
54 | struct thread_map *thread_map__new(pid_t pid, pid_t tid) | 59 | struct 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 | |||
124 | out_closedir: | ||
125 | closedir(proc); | ||
126 | out: | ||
127 | return threads; | ||
128 | |||
129 | out_free_threads: | ||
130 | free(threads); | ||
131 | return NULL; | ||
132 | |||
133 | out_free_namelist: | ||
134 | for (i = 0; i < items; i++) | ||
135 | free(namelist[i]); | ||
136 | free(namelist); | ||
137 | |||
138 | out_free_closedir: | ||
139 | free(threads); | ||
140 | threads = NULL; | ||
141 | goto out_closedir; | ||
142 | } | ||
143 | |||
144 | struct 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 | ||
12 | struct thread_map *thread_map__new_by_pid(pid_t pid); | 12 | struct thread_map *thread_map__new_by_pid(pid_t pid); |
13 | struct thread_map *thread_map__new_by_tid(pid_t tid); | 13 | struct thread_map *thread_map__new_by_tid(pid_t tid); |
14 | struct thread_map *thread_map__new(pid_t pid, pid_t tid); | 14 | struct thread_map *thread_map__new_by_uid(uid_t uid); |
15 | struct thread_map *thread_map__new(pid_t pid, pid_t tid, uid_t uid); | ||
15 | void thread_map__delete(struct thread_map *threads); | 16 | void thread_map__delete(struct thread_map *threads); |
16 | 17 | ||
17 | size_t thread_map__fprintf(struct thread_map *threads, FILE *fp); | 18 | size_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 | ||
50 | size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size); | 52 | size_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 | ||
11 | static void report(const char *prefix, const char *err, va_list params) | 12 | static 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 | |||
86 | uid_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 | ||
247 | void event_attr_init(struct perf_event_attr *attr); | 247 | void event_attr_init(struct perf_event_attr *attr); |
248 | 248 | ||
249 | uid_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 | ||