Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 288605
b: refs/heads/master
c: 0d37aa3
h: refs/heads/master
i:
  288603: 9943d7f
v: v3
  • Loading branch information
Arnaldo Carvalho de Melo committed Jan 24, 2012
1 parent 21658d3 commit 5ce7f0d
Show file tree
Hide file tree
Showing 19 changed files with 201 additions and 23 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 9ae7d3351aac238eef9646479693105688fd9cc9
refs/heads/master: 0d37aa34f8806bb443dd3c8621fd9bdbb50c58bb
4 changes: 4 additions & 0 deletions trunk/tools/perf/Documentation/perf-record.txt
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ OPTIONS
--tid=::
Record events on existing thread ID.

-u::
--uid=::
Record events in threads owned by uid. Name or number.

-r::
--realtime=::
Collect data with this RT SCHED_FIFO priority.
Expand Down
4 changes: 4 additions & 0 deletions trunk/tools/perf/Documentation/perf-top.txt
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ Default is to monitor all CPUS.
--tid=<tid>::
Profile events on existing thread ID.

-u::
--uid=::
Record events in threads owned by uid. Name or number.

-r <priority>::
--realtime=<priority>::
Collect data with this RT SCHED_FIFO priority.
Expand Down
12 changes: 10 additions & 2 deletions trunk/tools/perf/builtin-record.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ struct perf_record {
struct perf_evlist *evlist;
struct perf_session *session;
const char *progname;
const char *uid_str;
int output;
unsigned int page_size;
int realtime_prio;
Expand Down Expand Up @@ -727,6 +728,7 @@ const struct option record_options[] = {
OPT_CALLBACK('G', "cgroup", &record.evlist, "name",
"monitor event in cgroup name only",
parse_cgroups),
OPT_STRING('u', "uid", &record.uid_str, "user", "user to profile"),
OPT_END()
};

Expand All @@ -748,7 +750,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
argc = parse_options(argc, argv, record_options, record_usage,
PARSE_OPT_STOP_AT_NON_OPTION);
if (!argc && rec->opts.target_pid == -1 && rec->opts.target_tid == -1 &&
!rec->opts.system_wide && !rec->opts.cpu_list)
!rec->opts.system_wide && !rec->opts.cpu_list && !rec->uid_str)
usage_with_options(record_usage, record_options);

if (rec->force && rec->append_file) {
Expand Down Expand Up @@ -788,11 +790,17 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
goto out_symbol_exit;
}

rec->opts.uid = parse_target_uid(rec->uid_str, rec->opts.target_tid,
rec->opts.target_pid);
if (rec->uid_str != NULL && rec->opts.uid == UINT_MAX - 1)
goto out_free_fd;

if (rec->opts.target_pid != -1)
rec->opts.target_tid = rec->opts.target_pid;

if (perf_evlist__create_maps(evsel_list, rec->opts.target_pid,
rec->opts.target_tid, rec->opts.cpu_list) < 0)
rec->opts.target_tid, rec->opts.uid,
rec->opts.cpu_list) < 0)
usage_with_options(record_usage, record_options);

list_for_each_entry(pos, &evsel_list->entries, node) {
Expand Down
2 changes: 1 addition & 1 deletion trunk/tools/perf/builtin-stat.c
Original file line number Diff line number Diff line change
Expand Up @@ -1201,7 +1201,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
if (target_pid != -1)
target_tid = target_pid;

evsel_list->threads = thread_map__new(target_pid, target_tid);
evsel_list->threads = thread_map__new(target_pid, target_tid, UINT_MAX);
if (evsel_list->threads == NULL) {
pr_err("Problems finding threads of monitor\n");
usage_with_options(stat_usage, options);
Expand Down
8 changes: 4 additions & 4 deletions trunk/tools/perf/builtin-test.c
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ static int test__open_syscall_event(void)
return -1;
}

threads = thread_map__new(-1, getpid());
threads = thread_map__new(-1, getpid(), UINT_MAX);
if (threads == NULL) {
pr_debug("thread_map__new\n");
return -1;
Expand Down Expand Up @@ -342,7 +342,7 @@ static int test__open_syscall_event_on_all_cpus(void)
return -1;
}

threads = thread_map__new(-1, getpid());
threads = thread_map__new(-1, getpid(), UINT_MAX);
if (threads == NULL) {
pr_debug("thread_map__new\n");
return -1;
Expand Down Expand Up @@ -490,7 +490,7 @@ static int test__basic_mmap(void)
expected_nr_events[i] = random() % 257;
}

threads = thread_map__new(-1, getpid());
threads = thread_map__new(-1, getpid(), UINT_MAX);
if (threads == NULL) {
pr_debug("thread_map__new\n");
return -1;
Expand Down Expand Up @@ -1054,7 +1054,7 @@ static int test__PERF_RECORD(void)
* we're monitoring, the one forked there.
*/
err = perf_evlist__create_maps(evlist, opts.target_pid,
opts.target_tid, opts.cpu_list);
opts.target_tid, UINT_MAX, opts.cpu_list);
if (err < 0) {
pr_debug("Not enough memory to create thread/cpu maps\n");
goto out_delete_evlist;
Expand Down
22 changes: 19 additions & 3 deletions trunk/tools/perf/builtin-top.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@
#include <linux/unistd.h>
#include <linux/types.h>


void get_term_dimensions(struct winsize *ws)
{
char *s = getenv("LINES");
Expand Down Expand Up @@ -537,10 +536,20 @@ static void perf_top__sort_new_samples(void *arg)

static void *display_thread_tui(void *arg)
{
struct perf_evsel *pos;
struct perf_top *top = arg;
const char *help = "For a higher level overview, try: perf top --sort comm,dso";

perf_top__sort_new_samples(top);

/*
* Initialize the uid_filter_str, in the future the TUI will allow
* Zooming in/out UIDs. For now juse use whatever the user passed
* via --uid.
*/
list_for_each_entry(pos, &top->evlist->entries, node)
pos->hists.uid_filter_str = top->uid_str;

perf_evlist__tui_browse_hists(top->evlist, help,
perf_top__sort_new_samples,
top, top->delay_secs);
Expand Down Expand Up @@ -949,7 +958,7 @@ static int __cmd_top(struct perf_top *top)
if (ret)
goto out_delete;

if (top->target_tid != -1)
if (top->target_tid != -1 || top->uid != UINT_MAX)
perf_event__synthesize_thread_map(&top->tool, top->evlist->threads,
perf_event__process,
&top->session->host_machine);
Expand Down Expand Up @@ -1089,6 +1098,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
.delay_secs = 2,
.target_pid = -1,
.target_tid = -1,
.uid = UINT_MAX,
.freq = 1000, /* 1 KHz */
.sample_id_all_avail = true,
.mmap_pages = 128,
Expand Down Expand Up @@ -1162,6 +1172,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
"Display raw encoding of assembly instructions (default)"),
OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
"Specify disassembler style (e.g. -M intel for intel syntax)"),
OPT_STRING('u', "uid", &top.uid_str, "user", "user to profile"),
OPT_END()
};

Expand All @@ -1187,6 +1198,10 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)

setup_browser(false);

top.uid = parse_target_uid(top.uid_str, top.target_tid, top.target_pid);
if (top.uid_str != NULL && top.uid == UINT_MAX - 1)
goto out_delete_evlist;

/* CPU and PID are mutually exclusive */
if (top.target_tid > 0 && top.cpu_list) {
printf("WARNING: PID switch overriding CPU\n");
Expand All @@ -1198,7 +1213,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
top.target_tid = top.target_pid;

if (perf_evlist__create_maps(top.evlist, top.target_pid,
top.target_tid, top.cpu_list) < 0)
top.target_tid, top.uid, top.cpu_list) < 0)
usage_with_options(top_usage, options);

if (!top.evlist->nr_entries &&
Expand Down Expand Up @@ -1262,6 +1277,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)

status = __cmd_top(&top);

out_delete_evlist:
perf_evlist__delete(top.evlist);

return status;
Expand Down
1 change: 1 addition & 0 deletions trunk/tools/perf/perf.h
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ void pthread__unblock_sigwinch(void);
struct perf_record_opts {
pid_t target_pid;
pid_t target_tid;
uid_t uid;
bool call_graph;
bool group;
bool inherit_stat;
Expand Down
6 changes: 3 additions & 3 deletions trunk/tools/perf/util/evlist.c
Original file line number Diff line number Diff line change
Expand Up @@ -594,14 +594,14 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
}

int perf_evlist__create_maps(struct perf_evlist *evlist, pid_t target_pid,
pid_t target_tid, const char *cpu_list)
pid_t target_tid, uid_t uid, const char *cpu_list)
{
evlist->threads = thread_map__new(target_pid, target_tid);
evlist->threads = thread_map__new(target_pid, target_tid, uid);

if (evlist->threads == NULL)
return -1;

if (cpu_list == NULL && target_tid != -1)
if (uid != UINT_MAX || (cpu_list == NULL && target_tid != -1))
evlist->cpus = cpu_map__dummy_new();
else
evlist->cpus = cpu_map__new(cpu_list);
Expand Down
2 changes: 1 addition & 1 deletion trunk/tools/perf/util/evlist.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ static inline void perf_evlist__set_maps(struct perf_evlist *evlist,
}

int perf_evlist__create_maps(struct perf_evlist *evlist, pid_t target_pid,
pid_t target_tid, const char *cpu_list);
pid_t tid, uid_t uid, const char *cpu_list);
void perf_evlist__delete_maps(struct perf_evlist *evlist);
int perf_evlist__set_filters(struct perf_evlist *evlist);

Expand Down
1 change: 1 addition & 0 deletions trunk/tools/perf/util/hist.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ struct hists {
u64 nr_entries;
const struct thread *thread_filter;
const struct dso *dso_filter;
const char *uid_filter_str;
pthread_mutex_t lock;
struct events_stats stats;
u64 event_stream;
Expand Down
10 changes: 5 additions & 5 deletions trunk/tools/perf/util/python.c
Original file line number Diff line number Diff line change
Expand Up @@ -425,14 +425,14 @@ struct pyrf_thread_map {
static int pyrf_thread_map__init(struct pyrf_thread_map *pthreads,
PyObject *args, PyObject *kwargs)
{
static char *kwlist[] = { "pid", "tid", NULL };
int pid = -1, tid = -1;
static char *kwlist[] = { "pid", "tid", "uid", NULL };
int pid = -1, tid = -1, uid = UINT_MAX;

if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ii",
kwlist, &pid, &tid))
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|iii",
kwlist, &pid, &tid, &uid))
return -1;

pthreads->threads = thread_map__new(pid, tid);
pthreads->threads = thread_map__new(pid, tid, uid);
if (pthreads->threads == NULL)
return -1;
return 0;
Expand Down
98 changes: 96 additions & 2 deletions trunk/tools/perf/util/thread_map.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
#include <dirent.h>
#include <limits.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include "thread_map.h"

/* Skip "." and ".." directories */
Expand All @@ -23,7 +28,7 @@ struct thread_map *thread_map__new_by_pid(pid_t pid)
sprintf(name, "/proc/%d/task", pid);
items = scandir(name, &namelist, filter, NULL);
if (items <= 0)
return NULL;
return NULL;

threads = malloc(sizeof(*threads) + sizeof(pid_t) * items);
if (threads != NULL) {
Expand Down Expand Up @@ -51,10 +56,99 @@ struct thread_map *thread_map__new_by_tid(pid_t tid)
return threads;
}

struct thread_map *thread_map__new(pid_t pid, pid_t tid)
struct thread_map *thread_map__new_by_uid(uid_t uid)
{
DIR *proc;
int max_threads = 32, items, i;
char path[256];
struct dirent dirent, *next, **namelist = NULL;
struct thread_map *threads = malloc(sizeof(*threads) +
max_threads * sizeof(pid_t));
if (threads == NULL)
goto out;

proc = opendir("/proc");
if (proc == NULL)
goto out_free_threads;

threads->nr = 0;

while (!readdir_r(proc, &dirent, &next) && next) {
char *end;
bool grow = false;
struct stat st;
pid_t pid = strtol(dirent.d_name, &end, 10);

if (*end) /* only interested in proper numerical dirents */
continue;

snprintf(path, sizeof(path), "/proc/%s", dirent.d_name);

if (stat(path, &st) != 0)
continue;

if (st.st_uid != uid)
continue;

snprintf(path, sizeof(path), "/proc/%d/task", pid);
items = scandir(path, &namelist, filter, NULL);
if (items <= 0)
goto out_free_closedir;

while (threads->nr + items >= max_threads) {
max_threads *= 2;
grow = true;
}

if (grow) {
struct thread_map *tmp;

tmp = realloc(threads, (sizeof(*threads) +
max_threads * sizeof(pid_t)));
if (tmp == NULL)
goto out_free_namelist;

threads = tmp;
}

for (i = 0; i < items; i++)
threads->map[threads->nr + i] = atoi(namelist[i]->d_name);

for (i = 0; i < items; i++)
free(namelist[i]);
free(namelist);

threads->nr += items;
}

out_closedir:
closedir(proc);
out:
return threads;

out_free_threads:
free(threads);
return NULL;

out_free_namelist:
for (i = 0; i < items; i++)
free(namelist[i]);
free(namelist);

out_free_closedir:
free(threads);
threads = NULL;
goto out_closedir;
}

struct thread_map *thread_map__new(pid_t pid, pid_t tid, uid_t uid)
{
if (pid != -1)
return thread_map__new_by_pid(pid);

if (tid == -1 && uid != UINT_MAX)
return thread_map__new_by_uid(uid);

return thread_map__new_by_tid(tid);
}

Expand Down
3 changes: 2 additions & 1 deletion trunk/tools/perf/util/thread_map.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ struct thread_map {

struct thread_map *thread_map__new_by_pid(pid_t pid);
struct thread_map *thread_map__new_by_tid(pid_t tid);
struct thread_map *thread_map__new(pid_t pid, pid_t tid);
struct thread_map *thread_map__new_by_uid(uid_t uid);
struct thread_map *thread_map__new(pid_t pid, pid_t tid, uid_t uid);
void thread_map__delete(struct thread_map *threads);

size_t thread_map__fprintf(struct thread_map *threads, FILE *fp);
Expand Down
Loading

0 comments on commit 5ce7f0d

Please sign in to comment.