* Specifying some processes to record using perf [not found] <CAL8zT=gX5=S9fd1MdYyYVYg+35anmK-aJwFj9fUiKNuMSb8n_w@mail.gmail.com> @ 2012-02-02 15:52 ` Jean-Michel Hautbois 2012-02-02 16:33 ` David Ahern 0 siblings, 1 reply; 5+ messages in thread From: Jean-Michel Hautbois @ 2012-02-02 15:52 UTC (permalink / raw) To: linux-kernel; +Cc: Jean-Michel Hautbois Hi all, I am using perf and I have several process and threads to record. I know that some threads in particular are interesting, and I don't find a way to specify multiple threads in perf record. The "-t" option takes only one thread IIUC. I don't know if the "--cgroup" is intended to do that, but I didn't succeed to use it... I would also like to exclude one specific process (or thread) when I do a system-wide record, and I think it is not possible either ? Thanks in advance ! Regards, JM ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: Specifying some processes to record using perf 2012-02-02 15:52 ` Specifying some processes to record using perf Jean-Michel Hautbois @ 2012-02-02 16:33 ` David Ahern 2012-02-04 23:19 ` David Ahern 0 siblings, 1 reply; 5+ messages in thread From: David Ahern @ 2012-02-02 16:33 UTC (permalink / raw) To: Jean-Michel Hautbois; +Cc: linux-kernel On 02/02/2012 08:52 AM, Jean-Michel Hautbois wrote: > Hi all, > > I am using perf and I have several process and threads to record. > I know that some threads in particular are interesting, and I don't > find a way to specify multiple threads in perf record. > The "-t" option takes only one thread IIUC. > I don't know if the "--cgroup" is intended to do that, but I didn't > succeed to use it... > > I would also like to exclude one specific process (or thread) when I > do a system-wide record, and I think it is not possible either ? > > Thanks in advance ! > Regards, > JM > -- > To unsubscribe from this list: send the line "unsubscribe linux-kernel" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html > Please read the FAQ at http://www.tux.org/lkml/ Right now pef-record can only do only 1 process or 1 thread. I started working on a patch to support multiple of both (e.g., allow multiple -t or -p arguments), but I have not finished it. Other options: Arnaldo recently added a uid option or you can record for all processes and filter the output to just your processes/threads of interest. David ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: Specifying some processes to record using perf 2012-02-02 16:33 ` David Ahern @ 2012-02-04 23:19 ` David Ahern 2012-02-05 14:23 ` Arnaldo Carvalho de Melo 0 siblings, 1 reply; 5+ messages in thread From: David Ahern @ 2012-02-04 23:19 UTC (permalink / raw) To: Jean-Michel Hautbois, Arnaldo Carvalho de Melo; +Cc: linux-kernel [-- Attachment #1: Type: text/plain, Size: 877 bytes --] On 02/02/2012 09:33 AM, David Ahern wrote: > > On 02/02/2012 08:52 AM, Jean-Michel Hautbois wrote: >> Hi all, >> >> I am using perf and I have several process and threads to record. >> I know that some threads in particular are interesting, and I don't >> find a way to specify multiple threads in perf record. >> The "-t" option takes only one thread IIUC. Found some time on the plane ride home to give this a shot. The attached applies on top of the perf/core branch in: git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git You can specify multiple threads or multiple processing using a comma-separated list. e.g., -t tid1,tid2,... or -p pid1,pid2,... (not both). It still needs more testing, but let me know how it works for what you need. Arnaldo: would you mind scanning this and see if there are any major problems/objections with the approach? David [-- Attachment #2: perf-allow-multiple-pid-tid.patch --] [-- Type: text/x-patch, Size: 21485 bytes --] diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index ff9a66e..a5766b4 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt @@ -52,11 +52,11 @@ OPTIONS -p:: --pid=:: - Record events on existing process ID. + Record events on existing process ID (comma separated list). -t:: --tid=:: - Record events on existing thread ID. + Record events on existing thread ID (comma separated list). -u:: --uid=:: diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt index 8966b9a..2fa173b 100644 --- a/tools/perf/Documentation/perf-stat.txt +++ b/tools/perf/Documentation/perf-stat.txt @@ -35,11 +35,11 @@ OPTIONS child tasks do not inherit counters -p:: --pid=<pid>:: - stat events on existing process id + stat events on existing process id (comma separated list) -t:: --tid=<tid>:: - stat events on existing thread id + stat events on existing thread id (comma separated list) -a:: diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt index ab1454e..4a5680c 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. -p <pid>:: --pid=<pid>:: - Profile events on existing Process ID. + Profile events on existing Process ID (comma separated list). -t <tid>:: --tid=<tid>:: - Profile events on existing thread ID. + Profile events on existing thread ID (comma separated list). -u:: --uid=:: diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 32870ee..3c1b6c7 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -655,8 +655,6 @@ static const char * const record_usage[] = { */ static struct perf_record record = { .opts = { - .target_pid = -1, - .target_tid = -1, .mmap_pages = UINT_MAX, .user_freq = UINT_MAX, .user_interval = ULLONG_MAX, @@ -680,9 +678,9 @@ const struct option record_options[] = { parse_events_option), OPT_CALLBACK(0, "filter", &record.evlist, "filter", "event filter", parse_filter), - OPT_INTEGER('p', "pid", &record.opts.target_pid, + OPT_STRING('p', "pid", &record.opts.target_pid, "pid", "record events on existing process id"), - OPT_INTEGER('t', "tid", &record.opts.target_tid, + OPT_STRING('t', "tid", &record.opts.target_tid, "tid", "record events on existing thread id"), OPT_INTEGER('r', "realtime", &record.realtime_prio, "collect data with this RT SCHED_FIFO priority"), @@ -749,7 +747,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 && + if (!argc && !rec->opts.target_pid && !rec->opts.target_tid && !rec->opts.system_wide && !rec->opts.cpu_list && !rec->uid_str) usage_with_options(record_usage, record_options); @@ -795,7 +793,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) if (rec->uid_str != NULL && rec->opts.uid == UINT_MAX - 1) goto out_free_fd; - if (rec->opts.target_pid != -1) + if (rec->opts.target_pid) rec->opts.target_tid = rec->opts.target_pid; 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 459b862..da9db2c 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -182,8 +182,8 @@ static int run_count = 1; static bool no_inherit = false; static bool scale = true; static bool no_aggr = false; -static pid_t target_pid = -1; -static pid_t target_tid = -1; +static const char *target_pid; +static const char *target_tid; static pid_t child_pid = -1; static bool null_run = false; static int detailed_run = 0; @@ -296,7 +296,7 @@ static int create_perf_stat_counter(struct perf_evsel *evsel, if (system_wide) return perf_evsel__open_per_cpu(evsel, evsel_list->cpus, group, group_fd); - if (target_pid == -1 && target_tid == -1) { + if (!target_pid && !target_tid) { attr->disabled = 1; attr->enable_on_exec = 1; } @@ -446,7 +446,7 @@ static int run_perf_stat(int argc __used, const char **argv) exit(-1); } - if (target_tid == -1 && target_pid == -1 && !system_wide) + if (!target_tid && !target_pid && !system_wide) evsel_list->threads->map[0] = child_pid; /* @@ -960,14 +960,14 @@ static void print_stat(int argc, const char **argv) if (!csv_output) { fprintf(output, "\n"); fprintf(output, " Performance counter stats for "); - if(target_pid == -1 && target_tid == -1) { + if (!target_pid && !target_tid) { fprintf(output, "\'%s", argv[0]); for (i = 1; i < argc; i++) fprintf(output, " %s", argv[i]); - } else if (target_pid != -1) - fprintf(output, "process id \'%d", target_pid); + } else if (target_pid) + fprintf(output, "process id \'%s", target_pid); else - fprintf(output, "thread id \'%d", target_tid); + fprintf(output, "thread id \'%s", target_tid); fprintf(output, "\'"); if (run_count > 1) @@ -1041,10 +1041,10 @@ static const struct option options[] = { "event filter", parse_filter), OPT_BOOLEAN('i', "no-inherit", &no_inherit, "child tasks do not inherit counters"), - OPT_INTEGER('p', "pid", &target_pid, - "stat events on existing process id"), - OPT_INTEGER('t', "tid", &target_tid, - "stat events on existing thread id"), + OPT_STRING('p', "pid", &target_pid, "pid", + "stat events on existing process id"), + OPT_STRING('t', "tid", &target_tid, "tid", + "stat events on existing thread id"), OPT_BOOLEAN('a', "all-cpus", &system_wide, "system-wide collection from all CPUs"), OPT_BOOLEAN('g', "group", &group, @@ -1182,7 +1182,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used) } else if (big_num_opt == 0) /* User passed --no-big-num */ big_num = false; - if (!argc && target_pid == -1 && target_tid == -1) + if (!argc && !target_pid && !target_tid) usage_with_options(stat_usage, options); if (run_count <= 0) usage_with_options(stat_usage, options); @@ -1198,7 +1198,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used) if (add_default_attributes()) goto out; - if (target_pid != -1) + if (target_pid) target_tid = target_pid; evsel_list->threads = thread_map__new(target_pid, target_tid, UINT_MAX); diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c index 70c4eb2..23ac482 100644 --- a/tools/perf/builtin-test.c +++ b/tools/perf/builtin-test.c @@ -264,6 +264,20 @@ static int trace_event__id(const char *evname) return err; } +static struct thread_map *test__thread_map(void) +{ + struct thread_map *threads; + char pidstr[16]; + + sprintf(pidstr, "%d", getpid()); + threads = thread_map__new(NULL, pidstr, UINT_MAX); + + if (threads == NULL) + pr_debug("thread_map__new\n"); + + return threads; +} + static int test__open_syscall_event(void) { int err = -1, fd; @@ -278,11 +292,9 @@ static int test__open_syscall_event(void) return -1; } - threads = thread_map__new(-1, getpid(), UINT_MAX); - if (threads == NULL) { - pr_debug("thread_map__new\n"); + threads = test__thread_map(); + if (threads == NULL) return -1; - } memset(&attr, 0, sizeof(attr)); attr.type = PERF_TYPE_TRACEPOINT; @@ -344,11 +356,9 @@ static int test__open_syscall_event_on_all_cpus(void) return -1; } - threads = thread_map__new(-1, getpid(), UINT_MAX); - if (threads == NULL) { - pr_debug("thread_map__new\n"); + threads = test__thread_map(); + if (threads == NULL) return -1; - } cpus = cpu_map__new(NULL); if (cpus == NULL) { @@ -492,11 +502,9 @@ static int test__basic_mmap(void) expected_nr_events[i] = random() % 257; } - threads = thread_map__new(-1, getpid(), UINT_MAX); - if (threads == NULL) { - pr_debug("thread_map__new\n"); + threads = test__thread_map(); + if (threads == NULL) return -1; - } cpus = cpu_map__new(NULL); if (cpus == NULL) { @@ -1010,8 +1018,6 @@ realloc: static int test__PERF_RECORD(void) { struct perf_record_opts opts = { - .target_pid = -1, - .target_tid = -1, .no_delay = true, .freq = 10, .mmap_pages = 256, diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index d869b21..94d55cb 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) if (ret) goto out_delete; - if (top->target_tid != -1 || top->uid != UINT_MAX) + if (top->target_tid || top->uid != UINT_MAX) perf_event__synthesize_thread_map(&top->tool, top->evlist->threads, perf_event__process, &top->session->host_machine); @@ -1103,8 +1103,6 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) struct perf_top top = { .count_filter = 5, .delay_secs = 2, - .target_pid = -1, - .target_tid = -1, .uid = UINT_MAX, .freq = 1000, /* 1 KHz */ .sample_id_all_avail = true, @@ -1118,9 +1116,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) parse_events_option), OPT_INTEGER('c', "count", &top.default_interval, "event period to sample"), - OPT_INTEGER('p', "pid", &top.target_pid, + OPT_STRING('p', "pid", &top.target_pid, "pid", "profile events on existing process id"), - OPT_INTEGER('t', "tid", &top.target_tid, + OPT_STRING('t', "tid", &top.target_tid, "tid", "profile events on existing thread id"), OPT_BOOLEAN('a', "all-cpus", &top.system_wide, "system-wide collection from all CPUs"), @@ -1210,13 +1208,13 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) goto out_delete_evlist; /* CPU and PID are mutually exclusive */ - if (top.target_tid > 0 && top.cpu_list) { + if (top.target_tid && top.cpu_list) { printf("WARNING: PID switch overriding CPU\n"); sleep(1); top.cpu_list = NULL; } - if (top.target_pid != -1) + if (top.target_pid) top.target_tid = top.target_pid; if (perf_evlist__create_maps(top.evlist, top.target_pid, diff --git a/tools/perf/perf.h b/tools/perf/perf.h index 92af168..deb17db 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h @@ -186,8 +186,8 @@ extern const char perf_version_string[]; void pthread__unblock_sigwinch(void); struct perf_record_opts { - pid_t target_pid; - pid_t target_tid; + const char *target_pid; + const char *target_tid; uid_t uid; bool call_graph; bool group; diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index a6d50e3..cfe273f 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, return perf_evlist__mmap_per_cpu(evlist, prot, mask); } -int perf_evlist__create_maps(struct perf_evlist *evlist, pid_t target_pid, - pid_t target_tid, uid_t uid, const char *cpu_list) +int perf_evlist__create_maps(struct perf_evlist *evlist, const char *target_pid, + const char *target_tid, uid_t uid, const char *cpu_list) { evlist->threads = thread_map__new(target_pid, target_tid, uid); if (evlist->threads == NULL) return -1; - if (uid != UINT_MAX || (cpu_list == NULL && target_tid != -1)) + if (uid != UINT_MAX || (cpu_list == NULL && target_tid)) evlist->cpus = cpu_map__dummy_new(); else evlist->cpus = cpu_map__new(cpu_list); @@ -820,7 +820,7 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist, exit(-1); } - if (!opts->system_wide && opts->target_tid == -1 && opts->target_pid == -1) + if (!opts->system_wide && !opts->target_tid && !opts->target_pid) evlist->threads->map[0] = evlist->workload.pid; close(child_ready_pipe[1]); diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index 9c51660..666745a 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, evlist->threads = threads; } -int perf_evlist__create_maps(struct perf_evlist *evlist, pid_t target_pid, - pid_t tid, uid_t uid, const char *cpu_list); +int perf_evlist__create_maps(struct perf_evlist *evlist, const char *target_pid, + const char *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); diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index dcfefab..6c568d2 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) attr->mmap = track; attr->comm = track; - if (opts->target_pid == -1 && opts->target_tid == -1 && !opts->system_wide) { + if (!opts->target_pid && !opts->target_tid && !opts->system_wide) { attr->disabled = 1; attr->enable_on_exec = 1; } diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index e03b58a..867948f 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c @@ -426,9 +426,10 @@ static int pyrf_thread_map__init(struct pyrf_thread_map *pthreads, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "pid", "tid", "uid", NULL }; - int pid = -1, tid = -1, uid = UINT_MAX; + char *pid = NULL, *tid = NULL; + int uid = UINT_MAX; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|iii", + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ssi", kwlist, &pid, &tid, &uid)) return -1; diff --git a/tools/perf/util/thread_map.c b/tools/perf/util/thread_map.c index 3d4b6c5..e629df2 100644 --- a/tools/perf/util/thread_map.c +++ b/tools/perf/util/thread_map.c @@ -6,7 +6,10 @@ #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> +#include <ctype.h> +#include <string.h> #include "thread_map.h" +#include "debug.h" /* Skip "." and ".." directories */ static int filter(const struct dirent *dir) @@ -17,46 +20,134 @@ static int filter(const struct dirent *dir) return 1; } -struct thread_map *thread_map__new_by_pid(pid_t pid) +static pid_t get_next_task_id(char **str) { - struct thread_map *threads; + char *p, *pend; + pid_t ret = -1; + + pend = p = *str; + + /* only expecting digits separated by commas */ + while (isdigit(*pend)) + ++pend; + + if (*pend == ',') { + *pend = '\0'; + pend++; + + /* catch strings ending in a comma - like '1234,' */ + if (*pend == '\0') { + ui__error("task id strings should not end in a comma\n"); + goto out; + } + } + + /* only convert if all characters are valid */ + if (*pend == '\0') { + ret = atoi(p); + *str = pend; + } + +out: + return ret; +} + +static struct thread_map *thread_map__new_by_pid(const char *pid_str) +{ + struct thread_map *threads = NULL; char name[256]; - int items; + int items, total_tasks = 0; struct dirent **namelist = NULL; - int i; + int i, j = 0; + char *ostr, *str; + pid_t pid; - sprintf(name, "/proc/%d/task", pid); - items = scandir(name, &namelist, filter, NULL); - if (items <= 0) + ostr = strdup(pid_str); + if (!ostr) return NULL; + str = ostr; + + while(*str) { + pid = get_next_task_id(&str); + if (pid < 0) { + free(threads); + threads = NULL; + break; + } - threads = malloc(sizeof(*threads) + sizeof(pid_t) * items); - if (threads != NULL) { - for (i = 0; i < items; i++) - threads->map[i] = atoi(namelist[i]->d_name); - threads->nr = items; + sprintf(name, "/proc/%d/task", pid); + items = scandir(name, &namelist, filter, NULL); + if (items <= 0) + break; + + total_tasks += items; + if (threads) + threads = realloc(threads, sizeof(*threads) + sizeof(pid_t) * total_tasks); + else + threads = malloc(sizeof(*threads) + sizeof(pid_t) * items); + + if (threads != NULL) { + for (i = 0; i < items; i++) + threads->map[j++] = atoi(namelist[i]->d_name); + threads->nr = total_tasks; + } + + for (i=0; i<items; i++) + free(namelist[i]); + free(namelist); + + if (!threads) + break; } - for (i=0; i<items; i++) - free(namelist[i]); - free(namelist); + free(ostr); return threads; } -struct thread_map *thread_map__new_by_tid(pid_t tid) +static struct thread_map *thread_map__new_by_tid(const char *tid_str) { - struct thread_map *threads = malloc(sizeof(*threads) + sizeof(pid_t)); - - if (threads != NULL) { - threads->map[0] = tid; + struct thread_map *threads = NULL; + char *str; + int ntasks = 0; + pid_t tid; + + if (!tid_str) { + threads = malloc(sizeof(*threads) + sizeof(pid_t)); + threads->map[1] = -1; threads->nr = 1; + return threads; + } + + str = strdup(tid_str); + if (!str) + return NULL; + + while(*str) { + tid = get_next_task_id(&str); + if (tid < 0) { + free(threads); + threads = NULL; + break; + } + + ntasks++; + if (threads) + threads = realloc(threads, sizeof(*threads) + sizeof(pid_t) * ntasks); + else + threads = malloc(sizeof(*threads) + sizeof(pid_t)); + + if (threads == NULL) + break; + + threads->map[ntasks-1] = tid; + threads->nr = ntasks; } return threads; } -struct thread_map *thread_map__new_by_uid(uid_t uid) +static struct thread_map *thread_map__new_by_uid(uid_t uid) { DIR *proc; int max_threads = 32, items, i; @@ -141,12 +232,12 @@ out_free_closedir: goto out_closedir; } -struct thread_map *thread_map__new(pid_t pid, pid_t tid, uid_t uid) +struct thread_map *thread_map__new(const char *pid, const char *tid, uid_t uid) { - if (pid != -1) + if (pid) return thread_map__new_by_pid(pid); - if (tid == -1 && uid != UINT_MAX) + if (!tid && uid != UINT_MAX) return thread_map__new_by_uid(uid); return thread_map__new_by_tid(tid); diff --git a/tools/perf/util/thread_map.h b/tools/perf/util/thread_map.h index c75ddba..b067114 100644 --- a/tools/perf/util/thread_map.h +++ b/tools/perf/util/thread_map.h @@ -9,10 +9,7 @@ struct thread_map { int 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_by_uid(uid_t uid); -struct thread_map *thread_map__new(pid_t pid, pid_t tid, uid_t uid); +struct thread_map *thread_map__new(const char *pid, const char *tid, uid_t uid); void thread_map__delete(struct thread_map *threads); 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 e4370ca..09fe579 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) ret += SNPRINTF(bf + ret, size - ret, "], "); - if (top->target_pid != -1) - ret += SNPRINTF(bf + ret, size - ret, " (target_pid: %d", + if (top->target_pid) + ret += SNPRINTF(bf + ret, size - ret, " (target_pid: %s", top->target_pid); - else if (top->target_tid != -1) - ret += SNPRINTF(bf + ret, size - ret, " (target_tid: %d", + else if (top->target_tid) + ret += SNPRINTF(bf + ret, size - ret, " (target_tid: %s", top->target_tid); else if (top->uid_str != NULL) 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) ret += SNPRINTF(bf + ret, size - ret, ", CPU%s: %s)", top->evlist->cpus->nr > 1 ? "s" : "", top->cpu_list); else { - if (top->target_tid != -1) + if (top->target_tid) ret += SNPRINTF(bf + ret, size - ret, ")"); else ret += SNPRINTF(bf + ret, size - ret, ", %d CPU%s)", diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h index def3e53..49eb848 100644 --- a/tools/perf/util/top.h +++ b/tools/perf/util/top.h @@ -23,7 +23,7 @@ struct perf_top { u64 guest_us_samples, guest_kernel_samples; int print_entries, count_filter, delay_secs; int freq; - pid_t target_pid, target_tid; + const char *target_pid, *target_tid; uid_t uid; bool hide_kernel_symbols, hide_user_symbols, zero; bool system_wide; diff --git a/tools/perf/util/usage.c b/tools/perf/util/usage.c index d0c0139..1240bd6 100644 --- a/tools/perf/util/usage.c +++ b/tools/perf/util/usage.c @@ -83,7 +83,7 @@ void warning(const char *warn, ...) va_end(params); } -uid_t parse_target_uid(const char *str, pid_t tid, pid_t pid) +uid_t parse_target_uid(const char *str, const char *tid, const char *pid) { struct passwd pwd, *result; char buf[1024]; @@ -91,8 +91,8 @@ uid_t parse_target_uid(const char *str, pid_t tid, pid_t pid) if (str == NULL) return UINT_MAX; - /* CPU and PID are mutually exclusive */ - if (tid > 0 || pid > 0) { + /* UUID and PID are mutually exclusive */ + if (tid || pid) { ui__warning("PID/TID switch overriding UID\n"); sleep(1); return UINT_MAX; diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 232d17e..7917b09 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h @@ -245,7 +245,7 @@ struct perf_event_attr; void event_attr_init(struct perf_event_attr *attr); -uid_t parse_target_uid(const char *str, pid_t tid, pid_t pid); +uid_t parse_target_uid(const char *str, const char *tid, const char *pid); #define _STR(x) #x #define STR(x) _STR(x) ^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: Specifying some processes to record using perf 2012-02-04 23:19 ` David Ahern @ 2012-02-05 14:23 ` Arnaldo Carvalho de Melo 2012-02-05 17:47 ` David Ahern 0 siblings, 1 reply; 5+ messages in thread From: Arnaldo Carvalho de Melo @ 2012-02-05 14:23 UTC (permalink / raw) To: David Ahern; +Cc: Jean-Michel Hautbois, linux-kernel Em Sat, Feb 04, 2012 at 04:19:59PM -0700, David Ahern escreveu: > On 02/02/2012 09:33 AM, David Ahern wrote: > > > > On 02/02/2012 08:52 AM, Jean-Michel Hautbois wrote: > >> Hi all, > >> > >> I am using perf and I have several process and threads to record. > >> I know that some threads in particular are interesting, and I don't > >> find a way to specify multiple threads in perf record. > >> The "-t" option takes only one thread IIUC. > > Found some time on the plane ride home to give this a shot. The attached > applies on top of the perf/core branch in: > > git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git > > You can specify multiple threads or multiple processing using a > comma-separated list. e.g., -t tid1,tid2,... or -p pid1,pid2,... (not both). > > It still needs more testing, but let me know how it works for what you need. > > Arnaldo: would you mind scanning this and see if there are any major > problems/objections with the approach? It looks ok, but I wouldn't remove the existing specialized thread_map constructors, i.e. no need to first transform getpid() into an string to then pass to a generic constructor that would then back convert it into a pid_t :-) Just add new constructors for CSV strings, like: struct thread_map *thread_map__new_by_pids(const char *pid_list); struct thread_map *thread_map__new_by_tids(const char *pid_list); with the expected results, i.e. they would just tokenize and call the more basic constructors, at least in the by_pids, then concatenating the results, etc. - Arnaldo > David > > > diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt > index ff9a66e..a5766b4 100644 > --- a/tools/perf/Documentation/perf-record.txt > +++ b/tools/perf/Documentation/perf-record.txt > @@ -52,11 +52,11 @@ OPTIONS > > -p:: > --pid=:: > - Record events on existing process ID. > + Record events on existing process ID (comma separated list). > > -t:: > --tid=:: > - Record events on existing thread ID. > + Record events on existing thread ID (comma separated list). > > -u:: > --uid=:: > diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt > index 8966b9a..2fa173b 100644 > --- a/tools/perf/Documentation/perf-stat.txt > +++ b/tools/perf/Documentation/perf-stat.txt > @@ -35,11 +35,11 @@ OPTIONS > child tasks do not inherit counters > -p:: > --pid=<pid>:: > - stat events on existing process id > + stat events on existing process id (comma separated list) > > -t:: > --tid=<tid>:: > - stat events on existing thread id > + stat events on existing thread id (comma separated list) > > > -a:: > diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt > index ab1454e..4a5680c 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. > > -p <pid>:: > --pid=<pid>:: > - Profile events on existing Process ID. > + Profile events on existing Process ID (comma separated list). > > -t <tid>:: > --tid=<tid>:: > - Profile events on existing thread ID. > + Profile events on existing thread ID (comma separated list). > > -u:: > --uid=:: > diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c > index 32870ee..3c1b6c7 100644 > --- a/tools/perf/builtin-record.c > +++ b/tools/perf/builtin-record.c > @@ -655,8 +655,6 @@ static const char * const record_usage[] = { > */ > static struct perf_record record = { > .opts = { > - .target_pid = -1, > - .target_tid = -1, > .mmap_pages = UINT_MAX, > .user_freq = UINT_MAX, > .user_interval = ULLONG_MAX, > @@ -680,9 +678,9 @@ const struct option record_options[] = { > parse_events_option), > OPT_CALLBACK(0, "filter", &record.evlist, "filter", > "event filter", parse_filter), > - OPT_INTEGER('p', "pid", &record.opts.target_pid, > + OPT_STRING('p', "pid", &record.opts.target_pid, "pid", > "record events on existing process id"), > - OPT_INTEGER('t', "tid", &record.opts.target_tid, > + OPT_STRING('t', "tid", &record.opts.target_tid, "tid", > "record events on existing thread id"), > OPT_INTEGER('r', "realtime", &record.realtime_prio, > "collect data with this RT SCHED_FIFO priority"), > @@ -749,7 +747,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 && > + if (!argc && !rec->opts.target_pid && !rec->opts.target_tid && > !rec->opts.system_wide && !rec->opts.cpu_list && !rec->uid_str) > usage_with_options(record_usage, record_options); > > @@ -795,7 +793,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __used) > if (rec->uid_str != NULL && rec->opts.uid == UINT_MAX - 1) > goto out_free_fd; > > - if (rec->opts.target_pid != -1) > + if (rec->opts.target_pid) > rec->opts.target_tid = rec->opts.target_pid; > > 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 459b862..da9db2c 100644 > --- a/tools/perf/builtin-stat.c > +++ b/tools/perf/builtin-stat.c > @@ -182,8 +182,8 @@ static int run_count = 1; > static bool no_inherit = false; > static bool scale = true; > static bool no_aggr = false; > -static pid_t target_pid = -1; > -static pid_t target_tid = -1; > +static const char *target_pid; > +static const char *target_tid; > static pid_t child_pid = -1; > static bool null_run = false; > static int detailed_run = 0; > @@ -296,7 +296,7 @@ static int create_perf_stat_counter(struct perf_evsel *evsel, > if (system_wide) > return perf_evsel__open_per_cpu(evsel, evsel_list->cpus, > group, group_fd); > - if (target_pid == -1 && target_tid == -1) { > + if (!target_pid && !target_tid) { > attr->disabled = 1; > attr->enable_on_exec = 1; > } > @@ -446,7 +446,7 @@ static int run_perf_stat(int argc __used, const char **argv) > exit(-1); > } > > - if (target_tid == -1 && target_pid == -1 && !system_wide) > + if (!target_tid && !target_pid && !system_wide) > evsel_list->threads->map[0] = child_pid; > > /* > @@ -960,14 +960,14 @@ static void print_stat(int argc, const char **argv) > if (!csv_output) { > fprintf(output, "\n"); > fprintf(output, " Performance counter stats for "); > - if(target_pid == -1 && target_tid == -1) { > + if (!target_pid && !target_tid) { > fprintf(output, "\'%s", argv[0]); > for (i = 1; i < argc; i++) > fprintf(output, " %s", argv[i]); > - } else if (target_pid != -1) > - fprintf(output, "process id \'%d", target_pid); > + } else if (target_pid) > + fprintf(output, "process id \'%s", target_pid); > else > - fprintf(output, "thread id \'%d", target_tid); > + fprintf(output, "thread id \'%s", target_tid); > > fprintf(output, "\'"); > if (run_count > 1) > @@ -1041,10 +1041,10 @@ static const struct option options[] = { > "event filter", parse_filter), > OPT_BOOLEAN('i', "no-inherit", &no_inherit, > "child tasks do not inherit counters"), > - OPT_INTEGER('p', "pid", &target_pid, > - "stat events on existing process id"), > - OPT_INTEGER('t', "tid", &target_tid, > - "stat events on existing thread id"), > + OPT_STRING('p', "pid", &target_pid, "pid", > + "stat events on existing process id"), > + OPT_STRING('t', "tid", &target_tid, "tid", > + "stat events on existing thread id"), > OPT_BOOLEAN('a', "all-cpus", &system_wide, > "system-wide collection from all CPUs"), > OPT_BOOLEAN('g', "group", &group, > @@ -1182,7 +1182,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used) > } else if (big_num_opt == 0) /* User passed --no-big-num */ > big_num = false; > > - if (!argc && target_pid == -1 && target_tid == -1) > + if (!argc && !target_pid && !target_tid) > usage_with_options(stat_usage, options); > if (run_count <= 0) > usage_with_options(stat_usage, options); > @@ -1198,7 +1198,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used) > if (add_default_attributes()) > goto out; > > - if (target_pid != -1) > + if (target_pid) > target_tid = target_pid; > > evsel_list->threads = thread_map__new(target_pid, target_tid, UINT_MAX); > diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c > index 70c4eb2..23ac482 100644 > --- a/tools/perf/builtin-test.c > +++ b/tools/perf/builtin-test.c > @@ -264,6 +264,20 @@ static int trace_event__id(const char *evname) > return err; > } > > +static struct thread_map *test__thread_map(void) > +{ > + struct thread_map *threads; > + char pidstr[16]; > + > + sprintf(pidstr, "%d", getpid()); > + threads = thread_map__new(NULL, pidstr, UINT_MAX); > + > + if (threads == NULL) > + pr_debug("thread_map__new\n"); > + > + return threads; > +} > + > static int test__open_syscall_event(void) > { > int err = -1, fd; > @@ -278,11 +292,9 @@ static int test__open_syscall_event(void) > return -1; > } > > - threads = thread_map__new(-1, getpid(), UINT_MAX); > - if (threads == NULL) { > - pr_debug("thread_map__new\n"); > + threads = test__thread_map(); > + if (threads == NULL) > return -1; > - } > > memset(&attr, 0, sizeof(attr)); > attr.type = PERF_TYPE_TRACEPOINT; > @@ -344,11 +356,9 @@ static int test__open_syscall_event_on_all_cpus(void) > return -1; > } > > - threads = thread_map__new(-1, getpid(), UINT_MAX); > - if (threads == NULL) { > - pr_debug("thread_map__new\n"); > + threads = test__thread_map(); > + if (threads == NULL) > return -1; > - } > > cpus = cpu_map__new(NULL); > if (cpus == NULL) { > @@ -492,11 +502,9 @@ static int test__basic_mmap(void) > expected_nr_events[i] = random() % 257; > } > > - threads = thread_map__new(-1, getpid(), UINT_MAX); > - if (threads == NULL) { > - pr_debug("thread_map__new\n"); > + threads = test__thread_map(); > + if (threads == NULL) > return -1; > - } > > cpus = cpu_map__new(NULL); > if (cpus == NULL) { > @@ -1010,8 +1018,6 @@ realloc: > static int test__PERF_RECORD(void) > { > struct perf_record_opts opts = { > - .target_pid = -1, > - .target_tid = -1, > .no_delay = true, > .freq = 10, > .mmap_pages = 256, > diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c > index d869b21..94d55cb 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) > if (ret) > goto out_delete; > > - if (top->target_tid != -1 || top->uid != UINT_MAX) > + if (top->target_tid || top->uid != UINT_MAX) > perf_event__synthesize_thread_map(&top->tool, top->evlist->threads, > perf_event__process, > &top->session->host_machine); > @@ -1103,8 +1103,6 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) > struct perf_top top = { > .count_filter = 5, > .delay_secs = 2, > - .target_pid = -1, > - .target_tid = -1, > .uid = UINT_MAX, > .freq = 1000, /* 1 KHz */ > .sample_id_all_avail = true, > @@ -1118,9 +1116,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) > parse_events_option), > OPT_INTEGER('c', "count", &top.default_interval, > "event period to sample"), > - OPT_INTEGER('p', "pid", &top.target_pid, > + OPT_STRING('p', "pid", &top.target_pid, "pid", > "profile events on existing process id"), > - OPT_INTEGER('t', "tid", &top.target_tid, > + OPT_STRING('t', "tid", &top.target_tid, "tid", > "profile events on existing thread id"), > OPT_BOOLEAN('a', "all-cpus", &top.system_wide, > "system-wide collection from all CPUs"), > @@ -1210,13 +1208,13 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) > goto out_delete_evlist; > > /* CPU and PID are mutually exclusive */ > - if (top.target_tid > 0 && top.cpu_list) { > + if (top.target_tid && top.cpu_list) { > printf("WARNING: PID switch overriding CPU\n"); > sleep(1); > top.cpu_list = NULL; > } > > - if (top.target_pid != -1) > + if (top.target_pid) > top.target_tid = top.target_pid; > > if (perf_evlist__create_maps(top.evlist, top.target_pid, > diff --git a/tools/perf/perf.h b/tools/perf/perf.h > index 92af168..deb17db 100644 > --- a/tools/perf/perf.h > +++ b/tools/perf/perf.h > @@ -186,8 +186,8 @@ extern const char perf_version_string[]; > void pthread__unblock_sigwinch(void); > > struct perf_record_opts { > - pid_t target_pid; > - pid_t target_tid; > + const char *target_pid; > + const char *target_tid; > uid_t uid; > bool call_graph; > bool group; > diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c > index a6d50e3..cfe273f 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, > return perf_evlist__mmap_per_cpu(evlist, prot, mask); > } > > -int perf_evlist__create_maps(struct perf_evlist *evlist, pid_t target_pid, > - pid_t target_tid, uid_t uid, const char *cpu_list) > +int perf_evlist__create_maps(struct perf_evlist *evlist, const char *target_pid, > + const char *target_tid, uid_t uid, const char *cpu_list) > { > evlist->threads = thread_map__new(target_pid, target_tid, uid); > > if (evlist->threads == NULL) > return -1; > > - if (uid != UINT_MAX || (cpu_list == NULL && target_tid != -1)) > + if (uid != UINT_MAX || (cpu_list == NULL && target_tid)) > evlist->cpus = cpu_map__dummy_new(); > else > evlist->cpus = cpu_map__new(cpu_list); > @@ -820,7 +820,7 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist, > exit(-1); > } > > - if (!opts->system_wide && opts->target_tid == -1 && opts->target_pid == -1) > + if (!opts->system_wide && !opts->target_tid && !opts->target_pid) > evlist->threads->map[0] = evlist->workload.pid; > > close(child_ready_pipe[1]); > diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h > index 9c51660..666745a 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, > evlist->threads = threads; > } > > -int perf_evlist__create_maps(struct perf_evlist *evlist, pid_t target_pid, > - pid_t tid, uid_t uid, const char *cpu_list); > +int perf_evlist__create_maps(struct perf_evlist *evlist, const char *target_pid, > + const char *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); > > diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c > index dcfefab..6c568d2 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) > attr->mmap = track; > attr->comm = track; > > - if (opts->target_pid == -1 && opts->target_tid == -1 && !opts->system_wide) { > + if (!opts->target_pid && !opts->target_tid && !opts->system_wide) { > attr->disabled = 1; > attr->enable_on_exec = 1; > } > diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c > index e03b58a..867948f 100644 > --- a/tools/perf/util/python.c > +++ b/tools/perf/util/python.c > @@ -426,9 +426,10 @@ static int pyrf_thread_map__init(struct pyrf_thread_map *pthreads, > PyObject *args, PyObject *kwargs) > { > static char *kwlist[] = { "pid", "tid", "uid", NULL }; > - int pid = -1, tid = -1, uid = UINT_MAX; > + char *pid = NULL, *tid = NULL; > + int uid = UINT_MAX; > > - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|iii", > + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ssi", > kwlist, &pid, &tid, &uid)) > return -1; > > diff --git a/tools/perf/util/thread_map.c b/tools/perf/util/thread_map.c > index 3d4b6c5..e629df2 100644 > --- a/tools/perf/util/thread_map.c > +++ b/tools/perf/util/thread_map.c > @@ -6,7 +6,10 @@ > #include <sys/types.h> > #include <sys/stat.h> > #include <unistd.h> > +#include <ctype.h> > +#include <string.h> > #include "thread_map.h" > +#include "debug.h" > > /* Skip "." and ".." directories */ > static int filter(const struct dirent *dir) > @@ -17,46 +20,134 @@ static int filter(const struct dirent *dir) > return 1; > } > > -struct thread_map *thread_map__new_by_pid(pid_t pid) > +static pid_t get_next_task_id(char **str) > { > - struct thread_map *threads; > + char *p, *pend; > + pid_t ret = -1; > + > + pend = p = *str; > + > + /* only expecting digits separated by commas */ > + while (isdigit(*pend)) > + ++pend; > + > + if (*pend == ',') { > + *pend = '\0'; > + pend++; > + > + /* catch strings ending in a comma - like '1234,' */ > + if (*pend == '\0') { > + ui__error("task id strings should not end in a comma\n"); > + goto out; > + } > + } > + > + /* only convert if all characters are valid */ > + if (*pend == '\0') { > + ret = atoi(p); > + *str = pend; > + } > + > +out: > + return ret; > +} > + > +static struct thread_map *thread_map__new_by_pid(const char *pid_str) > +{ > + struct thread_map *threads = NULL; > char name[256]; > - int items; > + int items, total_tasks = 0; > struct dirent **namelist = NULL; > - int i; > + int i, j = 0; > + char *ostr, *str; > + pid_t pid; > > - sprintf(name, "/proc/%d/task", pid); > - items = scandir(name, &namelist, filter, NULL); > - if (items <= 0) > + ostr = strdup(pid_str); > + if (!ostr) > return NULL; > + str = ostr; > + > + while(*str) { > + pid = get_next_task_id(&str); > + if (pid < 0) { > + free(threads); > + threads = NULL; > + break; > + } > > - threads = malloc(sizeof(*threads) + sizeof(pid_t) * items); > - if (threads != NULL) { > - for (i = 0; i < items; i++) > - threads->map[i] = atoi(namelist[i]->d_name); > - threads->nr = items; > + sprintf(name, "/proc/%d/task", pid); > + items = scandir(name, &namelist, filter, NULL); > + if (items <= 0) > + break; > + > + total_tasks += items; > + if (threads) > + threads = realloc(threads, sizeof(*threads) + sizeof(pid_t) * total_tasks); > + else > + threads = malloc(sizeof(*threads) + sizeof(pid_t) * items); > + > + if (threads != NULL) { > + for (i = 0; i < items; i++) > + threads->map[j++] = atoi(namelist[i]->d_name); > + threads->nr = total_tasks; > + } > + > + for (i=0; i<items; i++) > + free(namelist[i]); > + free(namelist); > + > + if (!threads) > + break; > } > > - for (i=0; i<items; i++) > - free(namelist[i]); > - free(namelist); > + free(ostr); > > return threads; > } > > -struct thread_map *thread_map__new_by_tid(pid_t tid) > +static struct thread_map *thread_map__new_by_tid(const char *tid_str) > { > - struct thread_map *threads = malloc(sizeof(*threads) + sizeof(pid_t)); > - > - if (threads != NULL) { > - threads->map[0] = tid; > + struct thread_map *threads = NULL; > + char *str; > + int ntasks = 0; > + pid_t tid; > + > + if (!tid_str) { > + threads = malloc(sizeof(*threads) + sizeof(pid_t)); > + threads->map[1] = -1; > threads->nr = 1; > + return threads; > + } > + > + str = strdup(tid_str); > + if (!str) > + return NULL; > + > + while(*str) { > + tid = get_next_task_id(&str); > + if (tid < 0) { > + free(threads); > + threads = NULL; > + break; > + } > + > + ntasks++; > + if (threads) > + threads = realloc(threads, sizeof(*threads) + sizeof(pid_t) * ntasks); > + else > + threads = malloc(sizeof(*threads) + sizeof(pid_t)); > + > + if (threads == NULL) > + break; > + > + threads->map[ntasks-1] = tid; > + threads->nr = ntasks; > } > > return threads; > } > > -struct thread_map *thread_map__new_by_uid(uid_t uid) > +static struct thread_map *thread_map__new_by_uid(uid_t uid) > { > DIR *proc; > int max_threads = 32, items, i; > @@ -141,12 +232,12 @@ out_free_closedir: > goto out_closedir; > } > > -struct thread_map *thread_map__new(pid_t pid, pid_t tid, uid_t uid) > +struct thread_map *thread_map__new(const char *pid, const char *tid, uid_t uid) > { > - if (pid != -1) > + if (pid) > return thread_map__new_by_pid(pid); > > - if (tid == -1 && uid != UINT_MAX) > + if (!tid && uid != UINT_MAX) > return thread_map__new_by_uid(uid); > > return thread_map__new_by_tid(tid); > diff --git a/tools/perf/util/thread_map.h b/tools/perf/util/thread_map.h > index c75ddba..b067114 100644 > --- a/tools/perf/util/thread_map.h > +++ b/tools/perf/util/thread_map.h > @@ -9,10 +9,7 @@ struct thread_map { > int 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_by_uid(uid_t uid); > -struct thread_map *thread_map__new(pid_t pid, pid_t tid, uid_t uid); > +struct thread_map *thread_map__new(const char *pid, const char *tid, uid_t uid); > void thread_map__delete(struct thread_map *threads); > > 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 e4370ca..09fe579 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) > > ret += SNPRINTF(bf + ret, size - ret, "], "); > > - if (top->target_pid != -1) > - ret += SNPRINTF(bf + ret, size - ret, " (target_pid: %d", > + if (top->target_pid) > + ret += SNPRINTF(bf + ret, size - ret, " (target_pid: %s", > top->target_pid); > - else if (top->target_tid != -1) > - ret += SNPRINTF(bf + ret, size - ret, " (target_tid: %d", > + else if (top->target_tid) > + ret += SNPRINTF(bf + ret, size - ret, " (target_tid: %s", > top->target_tid); > else if (top->uid_str != NULL) > 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) > ret += SNPRINTF(bf + ret, size - ret, ", CPU%s: %s)", > top->evlist->cpus->nr > 1 ? "s" : "", top->cpu_list); > else { > - if (top->target_tid != -1) > + if (top->target_tid) > ret += SNPRINTF(bf + ret, size - ret, ")"); > else > ret += SNPRINTF(bf + ret, size - ret, ", %d CPU%s)", > diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h > index def3e53..49eb848 100644 > --- a/tools/perf/util/top.h > +++ b/tools/perf/util/top.h > @@ -23,7 +23,7 @@ struct perf_top { > u64 guest_us_samples, guest_kernel_samples; > int print_entries, count_filter, delay_secs; > int freq; > - pid_t target_pid, target_tid; > + const char *target_pid, *target_tid; > uid_t uid; > bool hide_kernel_symbols, hide_user_symbols, zero; > bool system_wide; > diff --git a/tools/perf/util/usage.c b/tools/perf/util/usage.c > index d0c0139..1240bd6 100644 > --- a/tools/perf/util/usage.c > +++ b/tools/perf/util/usage.c > @@ -83,7 +83,7 @@ void warning(const char *warn, ...) > va_end(params); > } > > -uid_t parse_target_uid(const char *str, pid_t tid, pid_t pid) > +uid_t parse_target_uid(const char *str, const char *tid, const char *pid) > { > struct passwd pwd, *result; > char buf[1024]; > @@ -91,8 +91,8 @@ uid_t parse_target_uid(const char *str, pid_t tid, pid_t pid) > if (str == NULL) > return UINT_MAX; > > - /* CPU and PID are mutually exclusive */ > - if (tid > 0 || pid > 0) { > + /* UUID and PID are mutually exclusive */ > + if (tid || pid) { > ui__warning("PID/TID switch overriding UID\n"); > sleep(1); > return UINT_MAX; > diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h > index 232d17e..7917b09 100644 > --- a/tools/perf/util/util.h > +++ b/tools/perf/util/util.h > @@ -245,7 +245,7 @@ struct perf_event_attr; > > void event_attr_init(struct perf_event_attr *attr); > > -uid_t parse_target_uid(const char *str, pid_t tid, pid_t pid); > +uid_t parse_target_uid(const char *str, const char *tid, const char *pid); > > #define _STR(x) #x > #define STR(x) _STR(x) ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: Specifying some processes to record using perf 2012-02-05 14:23 ` Arnaldo Carvalho de Melo @ 2012-02-05 17:47 ` David Ahern 0 siblings, 0 replies; 5+ messages in thread From: David Ahern @ 2012-02-05 17:47 UTC (permalink / raw) To: Arnaldo Carvalho de Melo; +Cc: linux-kernel On 02/05/2012 07:23 AM, Arnaldo Carvalho de Melo wrote: > Em Sat, Feb 04, 2012 at 04:19:59PM -0700, David Ahern escreveu: >> On 02/02/2012 09:33 AM, David Ahern wrote: >>> >>> On 02/02/2012 08:52 AM, Jean-Michel Hautbois wrote: >>>> Hi all, >>>> >>>> I am using perf and I have several process and threads to record. >>>> I know that some threads in particular are interesting, and I don't >>>> find a way to specify multiple threads in perf record. >>>> The "-t" option takes only one thread IIUC. >> >> Found some time on the plane ride home to give this a shot. The attached >> applies on top of the perf/core branch in: >> >> git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git >> >> You can specify multiple threads or multiple processing using a >> comma-separated list. e.g., -t tid1,tid2,... or -p pid1,pid2,... (not both). >> >> It still needs more testing, but let me know how it works for what you need. >> >> Arnaldo: would you mind scanning this and see if there are any major >> problems/objections with the approach? > > It looks ok, but I wouldn't remove the existing specialized thread_map > constructors, i.e. no need to first transform getpid() into an string to > then pass to a generic constructor that would then back convert it into > a pid_t :-) Only perf-test does that; all the rest take pid/tid from the user. > > Just add new constructors for CSV strings, like: > > struct thread_map *thread_map__new_by_pids(const char *pid_list); > > struct thread_map *thread_map__new_by_tids(const char *pid_list); > > with the expected results, i.e. they would just tokenize and call the > more basic constructors, at least in the by_pids, then concatenating the > results, etc. Ok. I can leave the existing ones. I did not want that interface to get too complicated; with this change it will be easy to remove the 'or' and allow a user to specify multiple thread ids and multiple process ids. David ^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2012-02-05 17:47 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <CAL8zT=gX5=S9fd1MdYyYVYg+35anmK-aJwFj9fUiKNuMSb8n_w@mail.gmail.com>
2012-02-02 15:52 ` Specifying some processes to record using perf Jean-Michel Hautbois
2012-02-02 16:33 ` David Ahern
2012-02-04 23:19 ` David Ahern
2012-02-05 14:23 ` Arnaldo Carvalho de Melo
2012-02-05 17:47 ` David Ahern
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).