Fixes and improvements for perf/core:

. perf_target: abstraction for --uid, --pid, --tid, --cpu, --all-cpus handling,
   eliminating code duplicated in the tools, having constraints that apply to
   all of them, from Namhyung Kim
 
 . Fixes for handling fallback to cpu-clock on PPC, from David Ahern
 
 . Fix for processing events with unknown size, from Jiri Olsa
 
 . Compilation fix on 32-bit, from Jiri Olsa
 
 Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2.0.14 (GNU/Linux)
 
 iQIcBAABAgAGBQJPq+zRAAoJENZQFvNTUqpAe9YP/2VuVQ8OcIS6h9NjdfdAc3y/
 RX2KDvnCaqa8YFIAl9OOWwy6G35mu8NEr3Lpzw2kkKvdUE0HYFUa91kF4DDLvG/w
 6gpWUtH+9jtnydkX4z11qi1a+Pfq0irc83oaDgfFNArZKdf080OxoCfzaxOjZ3fH
 zs4JR2L8TYYxIiWWWl0vMFic9+hTIM3dyFYJswHGy/ppqDX6DWfq4XndTi1gjo99
 dxT+hKUvIMDI6Ztdyafkvfvge47ooI3OCuPlvdQzPQlh5ZY/BSZMDhUVHPaBBAV3
 qQY6tCGPgk6sEIoNGf3juRSQyaGoo5V5zKgNFsAG5rsZqIpmlErJTeGMSGeOW3ww
 TIAOXBVij98c8iwuGPAKR3ZUuNxXHBTAo4Sq/DjRGJ8RKILVaYe6Sp5DOjaFA+3U
 374XGvEIqqYViNZm3gq1JfVAjJ4179hk7K+zUK55IeSgsEnwQ9s379dIpwaxCtL4
 4Sb0FqyVbx7joo8NfLokXqblcBa/MRECrtVbHHEWuygzuV2Au437mOLOiTSGyyZr
 N6FsDNFUcx044QZAYsAcbAXIxE+DssOcEERiFD1gG8MoUohW/DnpbMMaQi9bfUSi
 b8SgFIpy9q9LlADRFYUZ+rVs4B9RCJNMtaa2UpcaRuUcXHrqZEWzxbPbSDjCbl4G
 /yoSHxH5QJu6bkYz5deW
 =ZZUs
 -----END PGP SIGNATURE-----

Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core

Fixes and improvements for perf/core:

- perf_target: abstraction for --uid, --pid, --tid, --cpu, --all-cpus handling,
  eliminating code duplicated in the tools, having constraints that apply to
  all of them, from Namhyung Kim

- Fixes for handling fallback to cpu-clock on PPC, from David Ahern

- Fix for processing events with unknown size, from Jiri Olsa

- Compilation fix on 32-bit, from Jiri Olsa

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
Ingo Molnar 2012-05-11 08:13:55 +02:00
commit 5dcefda0fd
27 changed files with 584 additions and 370 deletions

View File

@ -300,6 +300,7 @@ LIB_H += util/cpumap.h
LIB_H += util/top.h LIB_H += util/top.h
LIB_H += $(ARCH_INCLUDE) LIB_H += $(ARCH_INCLUDE)
LIB_H += util/cgroup.h LIB_H += util/cgroup.h
LIB_H += util/target.h
LIB_OBJS += $(OUTPUT)util/abspath.o LIB_OBJS += $(OUTPUT)util/abspath.o
LIB_OBJS += $(OUTPUT)util/alias.o LIB_OBJS += $(OUTPUT)util/alias.o
@ -361,6 +362,7 @@ LIB_OBJS += $(OUTPUT)util/util.o
LIB_OBJS += $(OUTPUT)util/xyarray.o LIB_OBJS += $(OUTPUT)util/xyarray.o
LIB_OBJS += $(OUTPUT)util/cpumap.o LIB_OBJS += $(OUTPUT)util/cpumap.o
LIB_OBJS += $(OUTPUT)util/cgroup.o LIB_OBJS += $(OUTPUT)util/cgroup.o
LIB_OBJS += $(OUTPUT)util/target.o
BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o
@ -481,6 +483,7 @@ else
LIB_OBJS += $(OUTPUT)ui/helpline.o LIB_OBJS += $(OUTPUT)ui/helpline.o
LIB_OBJS += $(OUTPUT)ui/progress.o LIB_OBJS += $(OUTPUT)ui/progress.o
LIB_OBJS += $(OUTPUT)ui/util.o LIB_OBJS += $(OUTPUT)ui/util.o
LIB_OBJS += $(OUTPUT)ui/tui/setup.o
LIB_H += ui/browser.h LIB_H += ui/browser.h
LIB_H += ui/browsers/map.h LIB_H += ui/browsers/map.h
LIB_H += ui/helpline.h LIB_H += ui/helpline.h
@ -503,6 +506,11 @@ else
BASIC_CFLAGS += $(shell pkg-config --cflags gtk+-2.0) BASIC_CFLAGS += $(shell pkg-config --cflags gtk+-2.0)
EXTLIBS += $(shell pkg-config --libs gtk+-2.0) EXTLIBS += $(shell pkg-config --libs gtk+-2.0)
LIB_OBJS += $(OUTPUT)ui/gtk/browser.o LIB_OBJS += $(OUTPUT)ui/gtk/browser.o
LIB_OBJS += $(OUTPUT)ui/gtk/setup.o
# Make sure that it'd be included only once.
ifneq ($(findstring -DNO_NEWT_SUPPORT,$(BASIC_CFLAGS)),)
LIB_OBJS += $(OUTPUT)ui/setup.o
endif
endif endif
endif endif

View File

@ -44,7 +44,6 @@ struct perf_record {
struct perf_evlist *evlist; struct perf_evlist *evlist;
struct perf_session *session; struct perf_session *session;
const char *progname; const char *progname;
const char *uid_str;
int output; int output;
unsigned int page_size; unsigned int page_size;
int realtime_prio; int realtime_prio;
@ -218,7 +217,7 @@ try_again:
if (err == EPERM || err == EACCES) { if (err == EPERM || err == EACCES) {
ui__error_paranoid(); ui__error_paranoid();
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} else if (err == ENODEV && opts->cpu_list) { } else if (err == ENODEV && opts->target.cpu_list) {
die("No such device - did you specify" die("No such device - did you specify"
" an out-of-range profile CPU?\n"); " an out-of-range profile CPU?\n");
} else if (err == EINVAL) { } else if (err == EINVAL) {
@ -243,9 +242,13 @@ try_again:
/* /*
* If it's cycles then fall back to hrtimer * If it's cycles then fall back to hrtimer
* based cpu-clock-tick sw counter, which * based cpu-clock-tick sw counter, which
* is always available even if no PMU support: * is always available even if no PMU support.
*
* PPC returns ENXIO until 2.6.37 (behavior changed
* with commit b0a873e).
*/ */
if (err == ENOENT && attr->type == PERF_TYPE_HARDWARE if ((err == ENOENT || err == ENXIO)
&& attr->type == PERF_TYPE_HARDWARE
&& attr->config == PERF_COUNT_HW_CPU_CYCLES) { && attr->config == PERF_COUNT_HW_CPU_CYCLES) {
if (verbose) if (verbose)
@ -253,6 +256,10 @@ try_again:
"trying to fall back to cpu-clock-ticks\n"); "trying to fall back to cpu-clock-ticks\n");
attr->type = PERF_TYPE_SOFTWARE; attr->type = PERF_TYPE_SOFTWARE;
attr->config = PERF_COUNT_SW_CPU_CLOCK; attr->config = PERF_COUNT_SW_CPU_CLOCK;
if (pos->name) {
free(pos->name);
pos->name = NULL;
}
goto try_again; goto try_again;
} }
@ -578,7 +585,7 @@ static int __cmd_record(struct perf_record *rec, int argc, const char **argv)
perf_session__process_machines(session, tool, perf_session__process_machines(session, tool,
perf_event__synthesize_guest_os); perf_event__synthesize_guest_os);
if (!opts->system_wide) if (!opts->target.system_wide)
perf_event__synthesize_thread_map(tool, evsel_list->threads, perf_event__synthesize_thread_map(tool, evsel_list->threads,
process_synthesized_event, process_synthesized_event,
machine); machine);
@ -765,9 +772,9 @@ const struct option record_options[] = {
parse_events_option), parse_events_option),
OPT_CALLBACK(0, "filter", &record.evlist, "filter", OPT_CALLBACK(0, "filter", &record.evlist, "filter",
"event filter", parse_filter), "event filter", parse_filter),
OPT_STRING('p', "pid", &record.opts.target_pid, "pid", OPT_STRING('p', "pid", &record.opts.target.pid, "pid",
"record events on existing process id"), "record events on existing process id"),
OPT_STRING('t', "tid", &record.opts.target_tid, "tid", OPT_STRING('t', "tid", &record.opts.target.tid, "tid",
"record events on existing thread id"), "record events on existing thread id"),
OPT_INTEGER('r', "realtime", &record.realtime_prio, OPT_INTEGER('r', "realtime", &record.realtime_prio,
"collect data with this RT SCHED_FIFO priority"), "collect data with this RT SCHED_FIFO priority"),
@ -775,11 +782,11 @@ const struct option record_options[] = {
"collect data without buffering"), "collect data without buffering"),
OPT_BOOLEAN('R', "raw-samples", &record.opts.raw_samples, OPT_BOOLEAN('R', "raw-samples", &record.opts.raw_samples,
"collect raw sample records from all opened counters"), "collect raw sample records from all opened counters"),
OPT_BOOLEAN('a', "all-cpus", &record.opts.system_wide, OPT_BOOLEAN('a', "all-cpus", &record.opts.target.system_wide,
"system-wide collection from all CPUs"), "system-wide collection from all CPUs"),
OPT_BOOLEAN('A', "append", &record.append_file, OPT_BOOLEAN('A', "append", &record.append_file,
"append to the output file to do incremental profiling"), "append to the output file to do incremental profiling"),
OPT_STRING('C', "cpu", &record.opts.cpu_list, "cpu", OPT_STRING('C', "cpu", &record.opts.target.cpu_list, "cpu",
"list of cpus to monitor"), "list of cpus to monitor"),
OPT_BOOLEAN('f', "force", &record.force, OPT_BOOLEAN('f', "force", &record.force,
"overwrite existing data file (deprecated)"), "overwrite existing data file (deprecated)"),
@ -813,7 +820,8 @@ const struct option record_options[] = {
OPT_CALLBACK('G', "cgroup", &record.evlist, "name", OPT_CALLBACK('G', "cgroup", &record.evlist, "name",
"monitor event in cgroup name only", "monitor event in cgroup name only",
parse_cgroups), parse_cgroups),
OPT_STRING('u', "uid", &record.uid_str, "user", "user to profile"), OPT_STRING('u', "uid", &record.opts.target.uid_str, "user",
"user to profile"),
OPT_CALLBACK_NOOPT('b', "branch-any", &record.opts.branch_stack, OPT_CALLBACK_NOOPT('b', "branch-any", &record.opts.branch_stack,
"branch any", "sample any taken branches", "branch any", "sample any taken branches",
@ -831,6 +839,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
struct perf_evsel *pos; struct perf_evsel *pos;
struct perf_evlist *evsel_list; struct perf_evlist *evsel_list;
struct perf_record *rec = &record; struct perf_record *rec = &record;
char errbuf[BUFSIZ];
perf_header__set_cmdline(argc, argv); perf_header__set_cmdline(argc, argv);
@ -842,8 +851,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
argc = parse_options(argc, argv, record_options, record_usage, argc = parse_options(argc, argv, record_options, record_usage,
PARSE_OPT_STOP_AT_NON_OPTION); PARSE_OPT_STOP_AT_NON_OPTION);
if (!argc && !rec->opts.target_pid && !rec->opts.target_tid && if (!argc && perf_target__none(&rec->opts.target))
!rec->opts.system_wide && !rec->opts.cpu_list && !rec->uid_str)
usage_with_options(record_usage, record_options); usage_with_options(record_usage, record_options);
if (rec->force && rec->append_file) { if (rec->force && rec->append_file) {
@ -856,7 +864,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
rec->write_mode = WRITE_FORCE; rec->write_mode = WRITE_FORCE;
} }
if (nr_cgroups && !rec->opts.system_wide) { if (nr_cgroups && !rec->opts.target.system_wide) {
fprintf(stderr, "cgroup monitoring only available in" fprintf(stderr, "cgroup monitoring only available in"
" system-wide mode\n"); " system-wide mode\n");
usage_with_options(record_usage, record_options); usage_with_options(record_usage, record_options);
@ -883,17 +891,25 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
goto out_symbol_exit; goto out_symbol_exit;
} }
rec->opts.uid = parse_target_uid(rec->uid_str, rec->opts.target_tid, err = perf_target__validate(&rec->opts.target);
rec->opts.target_pid); if (err) {
if (rec->uid_str != NULL && rec->opts.uid == UINT_MAX - 1) perf_target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
ui__warning("%s", errbuf);
}
err = perf_target__parse_uid(&rec->opts.target);
if (err) {
int saved_errno = errno;
perf_target__strerror(&rec->opts.target, err, errbuf, BUFSIZ);
ui__warning("%s", errbuf);
err = -saved_errno;
goto out_free_fd; goto out_free_fd;
}
if (rec->opts.target_pid) err = -ENOMEM;
rec->opts.target_tid = rec->opts.target_pid; if (perf_evlist__create_maps(evsel_list, &rec->opts.target) < 0)
if (perf_evlist__create_maps(evsel_list, rec->opts.target_pid,
rec->opts.target_tid, rec->opts.uid,
rec->opts.cpu_list) < 0)
usage_with_options(record_usage, record_options); usage_with_options(record_usage, record_options);
list_for_each_entry(pos, &evsel_list->entries, node) { list_for_each_entry(pos, &evsel_list->entries, node) {

View File

@ -304,7 +304,7 @@ static size_t hists__fprintf_nr_sample_events(struct hists *self,
if (evname != NULL) if (evname != NULL)
ret += fprintf(fp, " of event '%s'", evname); ret += fprintf(fp, " of event '%s'", evname);
ret += fprintf(fp, "\n# Event count (approx.): %lu", nr_events); ret += fprintf(fp, "\n# Event count (approx.): %" PRIu64, nr_events);
return ret + fprintf(fp, "\n#\n"); return ret + fprintf(fp, "\n#\n");
} }
@ -676,14 +676,10 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
} }
if (strcmp(report.input_name, "-") != 0) { if (strcmp(report.input_name, "-") != 0)
if (report.use_gtk) setup_browser(true);
perf_gtk_setup_browser(argc, argv, true); else
else
setup_browser(true);
} else {
use_browser = 0; use_browser = 0;
}
/* /*
* Only in the newt browser we are doing integrated annotation, * Only in the newt browser we are doing integrated annotation,

View File

@ -175,22 +175,21 @@ static struct perf_event_attr very_very_detailed_attrs[] = {
static struct perf_evlist *evsel_list; static struct perf_evlist *evsel_list;
static bool system_wide = false; static struct perf_target target = {
static int run_idx = 0; .uid = UINT_MAX,
};
static int run_idx = 0;
static int run_count = 1; static int run_count = 1;
static bool no_inherit = false; static bool no_inherit = false;
static bool scale = true; static bool scale = true;
static bool no_aggr = false; static bool no_aggr = false;
static const char *target_pid;
static const char *target_tid;
static pid_t child_pid = -1; static pid_t child_pid = -1;
static bool null_run = false; static bool null_run = false;
static int detailed_run = 0; static int detailed_run = 0;
static bool sync_run = false; static bool sync_run = false;
static bool big_num = true; static bool big_num = true;
static int big_num_opt = -1; static int big_num_opt = -1;
static const char *cpu_list;
static const char *csv_sep = NULL; static const char *csv_sep = NULL;
static bool csv_output = false; static bool csv_output = false;
static bool group = false; static bool group = false;
@ -293,10 +292,10 @@ static int create_perf_stat_counter(struct perf_evsel *evsel,
attr->inherit = !no_inherit; attr->inherit = !no_inherit;
if (system_wide) if (!perf_target__no_cpu(&target))
return perf_evsel__open_per_cpu(evsel, evsel_list->cpus, return perf_evsel__open_per_cpu(evsel, evsel_list->cpus,
group, group_fd); group, group_fd);
if (!target_pid && !target_tid && (!group || evsel == first)) { if (perf_target__no_task(&target) && (!group || evsel == first)) {
attr->disabled = 1; attr->disabled = 1;
attr->enable_on_exec = 1; attr->enable_on_exec = 1;
} }
@ -446,7 +445,7 @@ static int run_perf_stat(int argc __used, const char **argv)
exit(-1); exit(-1);
} }
if (!target_tid && !target_pid && !system_wide) if (perf_target__none(&target))
evsel_list->threads->map[0] = child_pid; evsel_list->threads->map[0] = child_pid;
/* /*
@ -463,8 +462,13 @@ static int run_perf_stat(int argc __used, const char **argv)
list_for_each_entry(counter, &evsel_list->entries, node) { list_for_each_entry(counter, &evsel_list->entries, node) {
if (create_perf_stat_counter(counter, first) < 0) { if (create_perf_stat_counter(counter, first) < 0) {
/*
* PPC returns ENXIO for HW counters until 2.6.37
* (behavior changed with commit b0a873e).
*/
if (errno == EINVAL || errno == ENOSYS || if (errno == EINVAL || errno == ENOSYS ||
errno == ENOENT || errno == EOPNOTSUPP) { errno == ENOENT || errno == EOPNOTSUPP ||
errno == ENXIO) {
if (verbose) if (verbose)
ui__warning("%s event is not supported by the kernel.\n", ui__warning("%s event is not supported by the kernel.\n",
event_name(counter)); event_name(counter));
@ -476,7 +480,7 @@ static int run_perf_stat(int argc __used, const char **argv)
error("You may not have permission to collect %sstats.\n" error("You may not have permission to collect %sstats.\n"
"\t Consider tweaking" "\t Consider tweaking"
" /proc/sys/kernel/perf_event_paranoid or running as root.", " /proc/sys/kernel/perf_event_paranoid or running as root.",
system_wide ? "system-wide " : ""); target.system_wide ? "system-wide " : "");
} else { } else {
error("open_counter returned with %d (%s). " error("open_counter returned with %d (%s). "
"/bin/dmesg may provide additional information.\n", "/bin/dmesg may provide additional information.\n",
@ -968,14 +972,14 @@ static void print_stat(int argc, const char **argv)
if (!csv_output) { if (!csv_output) {
fprintf(output, "\n"); fprintf(output, "\n");
fprintf(output, " Performance counter stats for "); fprintf(output, " Performance counter stats for ");
if (!target_pid && !target_tid) { if (perf_target__no_task(&target)) {
fprintf(output, "\'%s", argv[0]); fprintf(output, "\'%s", argv[0]);
for (i = 1; i < argc; i++) for (i = 1; i < argc; i++)
fprintf(output, " %s", argv[i]); fprintf(output, " %s", argv[i]);
} else if (target_pid) } else if (target.pid)
fprintf(output, "process id \'%s", target_pid); fprintf(output, "process id \'%s", target.pid);
else else
fprintf(output, "thread id \'%s", target_tid); fprintf(output, "thread id \'%s", target.tid);
fprintf(output, "\'"); fprintf(output, "\'");
if (run_count > 1) if (run_count > 1)
@ -1049,11 +1053,11 @@ static const struct option options[] = {
"event filter", parse_filter), "event filter", parse_filter),
OPT_BOOLEAN('i', "no-inherit", &no_inherit, OPT_BOOLEAN('i', "no-inherit", &no_inherit,
"child tasks do not inherit counters"), "child tasks do not inherit counters"),
OPT_STRING('p', "pid", &target_pid, "pid", OPT_STRING('p', "pid", &target.pid, "pid",
"stat events on existing process id"), "stat events on existing process id"),
OPT_STRING('t', "tid", &target_tid, "tid", OPT_STRING('t', "tid", &target.tid, "tid",
"stat events on existing thread id"), "stat events on existing thread id"),
OPT_BOOLEAN('a', "all-cpus", &system_wide, OPT_BOOLEAN('a', "all-cpus", &target.system_wide,
"system-wide collection from all CPUs"), "system-wide collection from all CPUs"),
OPT_BOOLEAN('g', "group", &group, OPT_BOOLEAN('g', "group", &group,
"put the counters into a counter group"), "put the counters into a counter group"),
@ -1072,7 +1076,7 @@ static const struct option options[] = {
OPT_CALLBACK_NOOPT('B', "big-num", NULL, NULL, OPT_CALLBACK_NOOPT('B', "big-num", NULL, NULL,
"print large numbers with thousands\' separators", "print large numbers with thousands\' separators",
stat__set_big_num), stat__set_big_num),
OPT_STRING('C', "cpu", &cpu_list, "cpu", OPT_STRING('C', "cpu", &target.cpu_list, "cpu",
"list of cpus to monitor in system-wide"), "list of cpus to monitor in system-wide"),
OPT_BOOLEAN('A', "no-aggr", &no_aggr, OPT_BOOLEAN('A', "no-aggr", &no_aggr,
"disable CPU count aggregation"), "disable CPU count aggregation"),
@ -1190,13 +1194,13 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
} else if (big_num_opt == 0) /* User passed --no-big-num */ } else if (big_num_opt == 0) /* User passed --no-big-num */
big_num = false; big_num = false;
if (!argc && !target_pid && !target_tid) if (!argc && perf_target__no_task(&target))
usage_with_options(stat_usage, options); usage_with_options(stat_usage, options);
if (run_count <= 0) if (run_count <= 0)
usage_with_options(stat_usage, options); usage_with_options(stat_usage, options);
/* no_aggr, cgroup are for system-wide only */ /* no_aggr, cgroup are for system-wide only */
if ((no_aggr || nr_cgroups) && !system_wide) { if ((no_aggr || nr_cgroups) && perf_target__no_cpu(&target)) {
fprintf(stderr, "both cgroup and no-aggregation " fprintf(stderr, "both cgroup and no-aggregation "
"modes only available in system-wide mode\n"); "modes only available in system-wide mode\n");
@ -1206,23 +1210,14 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
if (add_default_attributes()) if (add_default_attributes())
goto out; goto out;
if (target_pid) perf_target__validate(&target);
target_tid = target_pid;
evsel_list->threads = thread_map__new_str(target_pid, if (perf_evlist__create_maps(evsel_list, &target) < 0) {
target_tid, UINT_MAX); if (!perf_target__no_task(&target))
if (evsel_list->threads == NULL) { pr_err("Problems finding threads of monitor\n");
pr_err("Problems finding threads of monitor\n"); if (!perf_target__no_cpu(&target))
usage_with_options(stat_usage, options); perror("failed to parse CPUs map");
}
if (system_wide)
evsel_list->cpus = cpu_map__new(cpu_list);
else
evsel_list->cpus = cpu_map__dummy_new();
if (evsel_list->cpus == NULL) {
perror("failed to parse CPUs map");
usage_with_options(stat_usage, options); usage_with_options(stat_usage, options);
return -1; return -1;
} }

View File

@ -1165,6 +1165,9 @@ realloc:
static int test__PERF_RECORD(void) static int test__PERF_RECORD(void)
{ {
struct perf_record_opts opts = { struct perf_record_opts opts = {
.target = {
.uid = UINT_MAX,
},
.no_delay = true, .no_delay = true,
.freq = 10, .freq = 10,
.mmap_pages = 256, .mmap_pages = 256,
@ -1207,8 +1210,7 @@ static int test__PERF_RECORD(void)
* perf_evlist__prepare_workload we'll fill in the only thread * perf_evlist__prepare_workload we'll fill in the only thread
* we're monitoring, the one forked there. * we're monitoring, the one forked there.
*/ */
err = perf_evlist__create_maps(evlist, opts.target_pid, err = perf_evlist__create_maps(evlist, &opts.target);
opts.target_tid, UINT_MAX, opts.cpu_list);
if (err < 0) { if (err < 0) {
pr_debug("Not enough memory to create thread/cpu maps\n"); pr_debug("Not enough memory to create thread/cpu maps\n");
goto out_delete_evlist; goto out_delete_evlist;
@ -1549,8 +1551,6 @@ static int __test__rdpmc(void)
sa.sa_sigaction = segfault_handler; sa.sa_sigaction = segfault_handler;
sigaction(SIGSEGV, &sa, NULL); sigaction(SIGSEGV, &sa, NULL);
fprintf(stderr, "\n\n");
fd = sys_perf_event_open(&attr, 0, -1, -1, 0); fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
if (fd < 0) { if (fd < 0) {
die("Error: sys_perf_event_open() syscall returned " die("Error: sys_perf_event_open() syscall returned "
@ -1575,7 +1575,7 @@ static int __test__rdpmc(void)
loops *= 10; loops *= 10;
delta = now - stamp; delta = now - stamp;
fprintf(stderr, "%14d: %14Lu\n", n, (long long)delta); pr_debug("%14d: %14Lu\n", n, (long long)delta);
delta_sum += delta; delta_sum += delta;
} }
@ -1583,7 +1583,7 @@ static int __test__rdpmc(void)
munmap(addr, page_size); munmap(addr, page_size);
close(fd); close(fd);
fprintf(stderr, " "); pr_debug(" ");
if (!delta_sum) if (!delta_sum)
return -1; return -1;

View File

@ -588,7 +588,7 @@ static void *display_thread_tui(void *arg)
* via --uid. * via --uid.
*/ */
list_for_each_entry(pos, &top->evlist->entries, node) list_for_each_entry(pos, &top->evlist->entries, node)
pos->hists.uid_filter_str = top->uid_str; pos->hists.uid_filter_str = top->target.uid_str;
perf_evlist__tui_browse_hists(top->evlist, help, perf_evlist__tui_browse_hists(top->evlist, help,
perf_top__sort_new_samples, perf_top__sort_new_samples,
@ -948,6 +948,10 @@ try_again:
attr->type = PERF_TYPE_SOFTWARE; attr->type = PERF_TYPE_SOFTWARE;
attr->config = PERF_COUNT_SW_CPU_CLOCK; attr->config = PERF_COUNT_SW_CPU_CLOCK;
if (counter->name) {
free(counter->name);
counter->name = strdup(event_name(counter));
}
goto try_again; goto try_again;
} }
@ -1016,7 +1020,7 @@ static int __cmd_top(struct perf_top *top)
if (ret) if (ret)
goto out_delete; goto out_delete;
if (top->target_tid || top->uid != UINT_MAX) if (!perf_target__no_task(&top->target))
perf_event__synthesize_thread_map(&top->tool, top->evlist->threads, perf_event__synthesize_thread_map(&top->tool, top->evlist->threads,
perf_event__process, perf_event__process,
&top->session->host_machine); &top->session->host_machine);
@ -1150,11 +1154,11 @@ static const char * const top_usage[] = {
int cmd_top(int argc, const char **argv, const char *prefix __used) int cmd_top(int argc, const char **argv, const char *prefix __used)
{ {
struct perf_evsel *pos; struct perf_evsel *pos;
int status = -ENOMEM; int status;
char errbuf[BUFSIZ];
struct perf_top top = { struct perf_top top = {
.count_filter = 5, .count_filter = 5,
.delay_secs = 2, .delay_secs = 2,
.uid = UINT_MAX,
.freq = 1000, /* 1 KHz */ .freq = 1000, /* 1 KHz */
.mmap_pages = 128, .mmap_pages = 128,
.sym_pcnt_filter = 5, .sym_pcnt_filter = 5,
@ -1166,13 +1170,13 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
parse_events_option), parse_events_option),
OPT_INTEGER('c', "count", &top.default_interval, OPT_INTEGER('c', "count", &top.default_interval,
"event period to sample"), "event period to sample"),
OPT_STRING('p', "pid", &top.target_pid, "pid", OPT_STRING('p', "pid", &top.target.pid, "pid",
"profile events on existing process id"), "profile events on existing process id"),
OPT_STRING('t', "tid", &top.target_tid, "tid", OPT_STRING('t', "tid", &top.target.tid, "tid",
"profile events on existing thread id"), "profile events on existing thread id"),
OPT_BOOLEAN('a', "all-cpus", &top.system_wide, OPT_BOOLEAN('a', "all-cpus", &top.target.system_wide,
"system-wide collection from all CPUs"), "system-wide collection from all CPUs"),
OPT_STRING('C', "cpu", &top.cpu_list, "cpu", OPT_STRING('C', "cpu", &top.target.cpu_list, "cpu",
"list of cpus to monitor"), "list of cpus to monitor"),
OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
"file", "vmlinux pathname"), "file", "vmlinux pathname"),
@ -1227,7 +1231,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
"Display raw encoding of assembly instructions (default)"), "Display raw encoding of assembly instructions (default)"),
OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
"Specify disassembler style (e.g. -M intel for intel syntax)"), "Specify disassembler style (e.g. -M intel for intel syntax)"),
OPT_STRING('u', "uid", &top.uid_str, "user", "user to profile"), OPT_STRING('u', "uid", &top.target.uid_str, "user", "user to profile"),
OPT_END() OPT_END()
}; };
@ -1253,22 +1257,27 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
setup_browser(false); setup_browser(false);
top.uid = parse_target_uid(top.uid_str, top.target_tid, top.target_pid); status = perf_target__validate(&top.target);
if (top.uid_str != NULL && top.uid == UINT_MAX - 1) if (status) {
goto out_delete_evlist; perf_target__strerror(&top.target, status, errbuf, BUFSIZ);
ui__warning("%s", errbuf);
/* CPU and PID are mutually exclusive */
if (top.target_tid && top.cpu_list) {
printf("WARNING: PID switch overriding CPU\n");
sleep(1);
top.cpu_list = NULL;
} }
if (top.target_pid) status = perf_target__parse_uid(&top.target);
top.target_tid = top.target_pid; if (status) {
int saved_errno = errno;
if (perf_evlist__create_maps(top.evlist, top.target_pid, perf_target__strerror(&top.target, status, errbuf, BUFSIZ);
top.target_tid, top.uid, top.cpu_list) < 0) ui__warning("%s", errbuf);
status = -saved_errno;
goto out_delete_evlist;
}
if (perf_target__none(&top.target))
top.target.system_wide = true;
if (perf_evlist__create_maps(top.evlist, &top.target) < 0)
usage_with_options(top_usage, options); usage_with_options(top_usage, options);
if (!top.evlist->nr_entries && if (!top.evlist->nr_entries &&

View File

@ -207,10 +207,10 @@ extern const char perf_version_string[];
void pthread__unblock_sigwinch(void); void pthread__unblock_sigwinch(void);
#include "util/target.h"
struct perf_record_opts { struct perf_record_opts {
const char *target_pid; struct perf_target target;
const char *target_tid;
uid_t uid;
bool call_graph; bool call_graph;
bool group; bool group;
bool inherit_stat; bool inherit_stat;
@ -223,7 +223,6 @@ struct perf_record_opts {
bool sample_time; bool sample_time;
bool sample_id_all_missing; bool sample_id_all_missing;
bool exclude_guest_missing; bool exclude_guest_missing;
bool system_wide;
bool period; bool period;
unsigned int freq; unsigned int freq;
unsigned int mmap_pages; unsigned int mmap_pages;
@ -231,7 +230,6 @@ struct perf_record_opts {
int branch_stack; int branch_stack;
u64 default_interval; u64 default_interval;
u64 user_interval; u64 user_interval;
const char *cpu_list;
}; };
#endif #endif

View File

@ -547,9 +547,9 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx,
struct map_symbol *ms = self->b.priv; struct map_symbol *ms = self->b.priv;
struct symbol *sym = ms->sym; struct symbol *sym = ms->sym;
const char *help = "<-/ESC: Exit, TAB/shift+TAB: Cycle hot lines, " const char *help = "<-/ESC: Exit, TAB/shift+TAB: Cycle hot lines, "
"H: Go to hottest line, ->/ENTER: Line action, " "H: Hottest line, ->/ENTER: Line action, "
"O: Toggle offset view, " "O: Offset view, "
"S: Toggle source code view"; "S: Source view";
int key; int key;
if (ui_browser__show(&self->b, sym->name, help) < 0) if (ui_browser__show(&self->b, sym->name, help) < 0)

View File

@ -941,7 +941,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
goto zoom_dso; goto zoom_dso;
case 't': case 't':
goto zoom_thread; goto zoom_thread;
case 's': case '/':
if (ui_browser__input_window("Symbol to show", if (ui_browser__input_window("Symbol to show",
"Please enter the name of symbol you want to see", "Please enter the name of symbol you want to see",
buf, "ENTER: OK, ESC: Cancel", buf, "ENTER: OK, ESC: Cancel",
@ -969,7 +969,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
"E Expand all callchains\n" "E Expand all callchains\n"
"d Zoom into current DSO\n" "d Zoom into current DSO\n"
"t Zoom into current Thread\n" "t Zoom into current Thread\n"
"s Filter symbol by name"); "/ Filter symbol by name");
continue; continue;
case K_ENTER: case K_ENTER:
case K_RIGHT: case K_RIGHT:

View File

@ -9,24 +9,13 @@
#define MAX_COLUMNS 32 #define MAX_COLUMNS 32
void perf_gtk_setup_browser(int argc, const char *argv[], static void perf_gtk__signal(int sig)
bool fallback_to_pager __used)
{
gtk_init(&argc, (char ***)&argv);
}
void perf_gtk_exit_browser(bool wait_for_ok __used)
{
gtk_main_quit();
}
static void perf_gtk_signal(int sig)
{ {
psignal(sig, "perf"); psignal(sig, "perf");
gtk_main_quit(); gtk_main_quit();
} }
static void perf_gtk_resize_window(GtkWidget *window) static void perf_gtk__resize_window(GtkWidget *window)
{ {
GdkRectangle rect; GdkRectangle rect;
GdkScreen *screen; GdkScreen *screen;
@ -46,7 +35,7 @@ static void perf_gtk_resize_window(GtkWidget *window)
gtk_window_resize(GTK_WINDOW(window), width, height); gtk_window_resize(GTK_WINDOW(window), width, height);
} }
static void perf_gtk_show_hists(GtkWidget *window, struct hists *hists) static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists)
{ {
GType col_types[MAX_COLUMNS]; GType col_types[MAX_COLUMNS];
GtkCellRenderer *renderer; GtkCellRenderer *renderer;
@ -142,11 +131,11 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
GtkWidget *notebook; GtkWidget *notebook;
GtkWidget *window; GtkWidget *window;
signal(SIGSEGV, perf_gtk_signal); signal(SIGSEGV, perf_gtk__signal);
signal(SIGFPE, perf_gtk_signal); signal(SIGFPE, perf_gtk__signal);
signal(SIGINT, perf_gtk_signal); signal(SIGINT, perf_gtk__signal);
signal(SIGQUIT, perf_gtk_signal); signal(SIGQUIT, perf_gtk__signal);
signal(SIGTERM, perf_gtk_signal); signal(SIGTERM, perf_gtk__signal);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL); window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
@ -168,7 +157,7 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC); GTK_POLICY_AUTOMATIC);
perf_gtk_show_hists(scrolled_window, hists); perf_gtk__show_hists(scrolled_window, hists);
tab_label = gtk_label_new(evname); tab_label = gtk_label_new(evname);
@ -179,7 +168,7 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
gtk_widget_show_all(window); gtk_widget_show_all(window);
perf_gtk_resize_window(window); perf_gtk__resize_window(window);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);

12
tools/perf/ui/gtk/setup.c Normal file
View File

@ -0,0 +1,12 @@
#include "gtk.h"
#include "../../util/cache.h"
int perf_gtk__init(void)
{
return gtk_init_check(NULL, NULL) ? 0 : -1;
}
void perf_gtk__exit(bool wait_for_ok __used)
{
gtk_main_quit();
}

View File

@ -1,155 +1,45 @@
#include <newt.h>
#include <signal.h>
#include <stdbool.h>
#include "../cache.h" #include "../cache.h"
#include "../debug.h" #include "../debug.h"
#include "browser.h"
#include "helpline.h"
#include "ui.h"
#include "util.h"
#include "libslang.h"
#include "keysyms.h"
pthread_mutex_t ui__lock = PTHREAD_MUTEX_INITIALIZER;
static volatile int ui__need_resize;
void ui__refresh_dimensions(bool force)
{
if (force || ui__need_resize) {
ui__need_resize = 0;
pthread_mutex_lock(&ui__lock);
SLtt_get_screen_size();
SLsmg_reinit_smg();
pthread_mutex_unlock(&ui__lock);
}
}
static void ui__sigwinch(int sig __used)
{
ui__need_resize = 1;
}
static void ui__setup_sigwinch(void)
{
static bool done;
if (done)
return;
done = true;
pthread__unblock_sigwinch();
signal(SIGWINCH, ui__sigwinch);
}
int ui__getch(int delay_secs)
{
struct timeval timeout, *ptimeout = delay_secs ? &timeout : NULL;
fd_set read_set;
int err, key;
ui__setup_sigwinch();
FD_ZERO(&read_set);
FD_SET(0, &read_set);
if (delay_secs) {
timeout.tv_sec = delay_secs;
timeout.tv_usec = 0;
}
err = select(1, &read_set, NULL, NULL, ptimeout);
if (err == 0)
return K_TIMER;
if (err == -1) {
if (errno == EINTR)
return K_RESIZE;
return K_ERROR;
}
key = SLang_getkey();
if (key != K_ESC)
return key;
FD_ZERO(&read_set);
FD_SET(0, &read_set);
timeout.tv_sec = 0;
timeout.tv_usec = 20;
err = select(1, &read_set, NULL, NULL, &timeout);
if (err == 0)
return K_ESC;
SLang_ungetkey(key);
return SLkp_getkey();
}
static void newt_suspend(void *d __used)
{
newtSuspend();
raise(SIGTSTP);
newtResume();
}
static int ui__init(void)
{
int err = SLkp_init();
if (err < 0)
goto out;
SLkp_define_keysym((char *)"^(kB)", SL_KEY_UNTAB);
out:
return err;
}
static void ui__exit(void)
{
SLtt_set_cursor_visibility(1);
SLsmg_refresh();
SLsmg_reset_smg();
SLang_reset_tty();
}
static void ui__signal(int sig)
{
ui__exit();
psignal(sig, "perf");
exit(0);
}
void setup_browser(bool fallback_to_pager) void setup_browser(bool fallback_to_pager)
{ {
if (!isatty(1) || !use_browser || dump_trace) { if (!isatty(1) || dump_trace)
use_browser = 0; use_browser = 0;
/* default to TUI */
if (use_browser < 0)
use_browser = 1;
switch (use_browser) {
case 2:
if (perf_gtk__init() == 0)
break;
/* fall through */
case 1:
use_browser = 1;
if (ui__init() == 0)
break;
/* fall through */
default:
if (fallback_to_pager) if (fallback_to_pager)
setup_pager(); setup_pager();
return; break;
} }
use_browser = 1;
newtInit();
ui__init();
newtSetSuspendCallback(newt_suspend, NULL);
ui_helpline__init();
ui_browser__init();
signal(SIGSEGV, ui__signal);
signal(SIGFPE, ui__signal);
signal(SIGINT, ui__signal);
signal(SIGQUIT, ui__signal);
signal(SIGTERM, ui__signal);
} }
void exit_browser(bool wait_for_ok) void exit_browser(bool wait_for_ok)
{ {
if (use_browser > 0) { switch (use_browser) {
if (wait_for_ok) case 2:
ui__question_window("Fatal Error", perf_gtk__exit(wait_for_ok);
ui_helpline__last_msg, break;
"Press any key...", 0);
ui__exit(); case 1:
ui__exit(wait_for_ok);
break;
default:
break;
} }
} }

140
tools/perf/ui/tui/setup.c Normal file
View File

@ -0,0 +1,140 @@
#include <newt.h>
#include <signal.h>
#include <stdbool.h>
#include "../../util/cache.h"
#include "../../util/debug.h"
#include "../browser.h"
#include "../helpline.h"
#include "../ui.h"
#include "../util.h"
#include "../libslang.h"
#include "../keysyms.h"
pthread_mutex_t ui__lock = PTHREAD_MUTEX_INITIALIZER;
static volatile int ui__need_resize;
void ui__refresh_dimensions(bool force)
{
if (force || ui__need_resize) {
ui__need_resize = 0;
pthread_mutex_lock(&ui__lock);
SLtt_get_screen_size();
SLsmg_reinit_smg();
pthread_mutex_unlock(&ui__lock);
}
}
static void ui__sigwinch(int sig __used)
{
ui__need_resize = 1;
}
static void ui__setup_sigwinch(void)
{
static bool done;
if (done)
return;
done = true;
pthread__unblock_sigwinch();
signal(SIGWINCH, ui__sigwinch);
}
int ui__getch(int delay_secs)
{
struct timeval timeout, *ptimeout = delay_secs ? &timeout : NULL;
fd_set read_set;
int err, key;
ui__setup_sigwinch();
FD_ZERO(&read_set);
FD_SET(0, &read_set);
if (delay_secs) {
timeout.tv_sec = delay_secs;
timeout.tv_usec = 0;
}
err = select(1, &read_set, NULL, NULL, ptimeout);
if (err == 0)
return K_TIMER;
if (err == -1) {
if (errno == EINTR)
return K_RESIZE;
return K_ERROR;
}
key = SLang_getkey();
if (key != K_ESC)
return key;
FD_ZERO(&read_set);
FD_SET(0, &read_set);
timeout.tv_sec = 0;
timeout.tv_usec = 20;
err = select(1, &read_set, NULL, NULL, &timeout);
if (err == 0)
return K_ESC;
SLang_ungetkey(key);
return SLkp_getkey();
}
static void newt_suspend(void *d __used)
{
newtSuspend();
raise(SIGTSTP);
newtResume();
}
static void ui__signal(int sig)
{
ui__exit(false);
psignal(sig, "perf");
exit(0);
}
int ui__init(void)
{
int err;
newtInit();
err = SLkp_init();
if (err < 0) {
pr_err("TUI initialization failed.\n");
goto out;
}
SLkp_define_keysym((char *)"^(kB)", SL_KEY_UNTAB);
newtSetSuspendCallback(newt_suspend, NULL);
ui_helpline__init();
ui_browser__init();
signal(SIGSEGV, ui__signal);
signal(SIGFPE, ui__signal);
signal(SIGINT, ui__signal);
signal(SIGQUIT, ui__signal);
signal(SIGTERM, ui__signal);
out:
return err;
}
void ui__exit(bool wait_for_ok)
{
if (wait_for_ok)
ui__question_window("Fatal Error",
ui_helpline__last_msg,
"Press any key...", 0);
SLtt_set_cursor_visibility(1);
SLsmg_refresh();
SLsmg_reset_smg();
SLang_reset_tty();
}

View File

@ -33,7 +33,7 @@ extern int pager_use_color;
extern int use_browser; extern int use_browser;
#ifdef NO_NEWT_SUPPORT #if defined(NO_NEWT_SUPPORT) && defined(NO_GTK2_SUPPORT)
static inline void setup_browser(bool fallback_to_pager) static inline void setup_browser(bool fallback_to_pager)
{ {
if (fallback_to_pager) if (fallback_to_pager)
@ -43,19 +43,29 @@ static inline void exit_browser(bool wait_for_ok __used) {}
#else #else
void setup_browser(bool fallback_to_pager); void setup_browser(bool fallback_to_pager);
void exit_browser(bool wait_for_ok); void exit_browser(bool wait_for_ok);
#ifdef NO_NEWT_SUPPORT
static inline int ui__init(void)
{
return -1;
}
static inline void ui__exit(bool wait_for_ok __used) {}
#else
int ui__init(void);
void ui__exit(bool wait_for_ok);
#endif #endif
#ifdef NO_GTK2_SUPPORT #ifdef NO_GTK2_SUPPORT
static inline void perf_gtk_setup_browser(int argc __used, const char *argv[] __used, bool fallback_to_pager) static inline int perf_gtk__init(void)
{ {
if (fallback_to_pager) return -1;
setup_pager();
} }
static inline void perf_gtk_exit_browser(bool wait_for_ok __used) {} static inline void perf_gtk__exit(bool wait_for_ok __used) {}
#else #else
void perf_gtk_setup_browser(int argc, const char *argv[], bool fallback_to_pager); int perf_gtk__init(void);
void perf_gtk_exit_browser(bool wait_for_ok); void perf_gtk__exit(bool wait_for_ok);
#endif #endif
#endif /* NO_NEWT_SUPPORT && NO_GTK2_SUPPORT */
char *alias_lookup(const char *alias); char *alias_lookup(const char *alias);
int split_cmdline(char *cmdline, const char ***argv); int split_cmdline(char *cmdline, const char ***argv);

View File

@ -11,6 +11,7 @@
#include "event.h" #include "event.h"
#include "debug.h" #include "debug.h"
#include "util.h" #include "util.h"
#include "target.h"
int verbose; int verbose;
bool dump_trace = false, quiet = false; bool dump_trace = false, quiet = false;

View File

@ -11,6 +11,7 @@
#include <poll.h> #include <poll.h>
#include "cpumap.h" #include "cpumap.h"
#include "thread_map.h" #include "thread_map.h"
#include "target.h"
#include "evlist.h" #include "evlist.h"
#include "evsel.h" #include "evsel.h"
#include <unistd.h> #include <unistd.h>
@ -599,18 +600,19 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
return perf_evlist__mmap_per_cpu(evlist, prot, mask); return perf_evlist__mmap_per_cpu(evlist, prot, mask);
} }
int perf_evlist__create_maps(struct perf_evlist *evlist, const char *target_pid, int perf_evlist__create_maps(struct perf_evlist *evlist,
const char *target_tid, uid_t uid, const char *cpu_list) struct perf_target *target)
{ {
evlist->threads = thread_map__new_str(target_pid, target_tid, uid); evlist->threads = thread_map__new_str(target->pid, target->tid,
target->uid);
if (evlist->threads == NULL) if (evlist->threads == NULL)
return -1; return -1;
if (uid != UINT_MAX || (cpu_list == NULL && target_tid)) if (!perf_target__no_cpu(target))
evlist->cpus = cpu_map__dummy_new(); evlist->cpus = cpu_map__new(target->cpu_list);
else else
evlist->cpus = cpu_map__new(cpu_list); evlist->cpus = cpu_map__dummy_new();
if (evlist->cpus == NULL) if (evlist->cpus == NULL)
goto out_delete_threads; goto out_delete_threads;
@ -827,7 +829,7 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist,
exit(-1); exit(-1);
} }
if (!opts->system_wide && !opts->target_tid && !opts->target_pid) if (perf_target__none(&opts->target))
evlist->threads->map[0] = evlist->workload.pid; evlist->threads->map[0] = evlist->workload.pid;
close(child_ready_pipe[1]); close(child_ready_pipe[1]);

View File

@ -106,8 +106,8 @@ static inline void perf_evlist__set_maps(struct perf_evlist *evlist,
evlist->threads = threads; evlist->threads = threads;
} }
int perf_evlist__create_maps(struct perf_evlist *evlist, const char *target_pid, int perf_evlist__create_maps(struct perf_evlist *evlist,
const char *tid, uid_t uid, const char *cpu_list); struct perf_target *target);
void perf_evlist__delete_maps(struct perf_evlist *evlist); void perf_evlist__delete_maps(struct perf_evlist *evlist);
int perf_evlist__set_filters(struct perf_evlist *evlist); int perf_evlist__set_filters(struct perf_evlist *evlist);

View File

@ -14,6 +14,7 @@
#include "util.h" #include "util.h"
#include "cpumap.h" #include "cpumap.h"
#include "thread_map.h" #include "thread_map.h"
#include "target.h"
#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y)) #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
#define GROUP_FD(group_fd, cpu) (*(int *)xyarray__entry(group_fd, cpu, 0)) #define GROUP_FD(group_fd, cpu) (*(int *)xyarray__entry(group_fd, cpu, 0))
@ -106,15 +107,15 @@ void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts,
if (opts->call_graph) if (opts->call_graph)
attr->sample_type |= PERF_SAMPLE_CALLCHAIN; attr->sample_type |= PERF_SAMPLE_CALLCHAIN;
if (opts->system_wide) if (opts->target.system_wide)
attr->sample_type |= PERF_SAMPLE_CPU; attr->sample_type |= PERF_SAMPLE_CPU;
if (opts->period) if (opts->period)
attr->sample_type |= PERF_SAMPLE_PERIOD; attr->sample_type |= PERF_SAMPLE_PERIOD;
if (!opts->sample_id_all_missing && if (!opts->sample_id_all_missing &&
(opts->sample_time || opts->system_wide || (opts->sample_time || !opts->no_inherit ||
!opts->no_inherit || opts->cpu_list)) !perf_target__no_cpu(&opts->target)))
attr->sample_type |= PERF_SAMPLE_TIME; attr->sample_type |= PERF_SAMPLE_TIME;
if (opts->raw_samples) { if (opts->raw_samples) {
@ -135,7 +136,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts,
attr->mmap = track; attr->mmap = track;
attr->comm = track; attr->comm = track;
if (!opts->target_pid && !opts->target_tid && !opts->system_wide && if (perf_target__none(&opts->target) &&
(!opts->group || evsel == first)) { (!opts->group || evsel == first)) {
attr->disabled = 1; attr->disabled = 1;
attr->enable_on_exec = 1; attr->enable_on_exec = 1;

View File

@ -31,21 +31,16 @@ static const char **header_argv;
int perf_header__push_event(u64 id, const char *name) int perf_header__push_event(u64 id, const char *name)
{ {
struct perf_trace_event_type *nevents;
if (strlen(name) > MAX_EVENT_NAME) if (strlen(name) > MAX_EVENT_NAME)
pr_warning("Event %s will be truncated\n", name); pr_warning("Event %s will be truncated\n", name);
if (!events) { nevents = realloc(events, (event_count + 1) * sizeof(*events));
events = malloc(sizeof(struct perf_trace_event_type)); if (nevents == NULL)
if (events == NULL) return -ENOMEM;
return -ENOMEM; events = nevents;
} else {
struct perf_trace_event_type *nevents;
nevents = realloc(events, (event_count + 1) * sizeof(*events));
if (nevents == NULL)
return -ENOMEM;
events = nevents;
}
memset(&events[event_count], 0, sizeof(struct perf_trace_event_type)); memset(&events[event_count], 0, sizeof(struct perf_trace_event_type));
events[event_count].event_id = id; events[event_count].event_id = id;
strncpy(events[event_count].name, name, MAX_EVENT_NAME - 1); strncpy(events[event_count].name, name, MAX_EVENT_NAME - 1);

View File

@ -4,7 +4,9 @@
* Parse symbolic events/counts passed in as options: * Parse symbolic events/counts passed in as options:
*/ */
#include <stdbool.h>
#include "../../../include/linux/perf_event.h" #include "../../../include/linux/perf_event.h"
#include "types.h"
struct list_head; struct list_head;
struct perf_evsel; struct perf_evsel;

View File

@ -1108,16 +1108,10 @@ more:
} }
if ((skip = perf_session__process_event(self, &event, tool, head)) < 0) { if ((skip = perf_session__process_event(self, &event, tool, head)) < 0) {
dump_printf("%#" PRIx64 " [%#x]: skipping unknown header type: %d\n", pr_err("%#" PRIx64 " [%#x]: failed to process type: %d\n",
head, event.header.size, event.header.type); head, event.header.size, event.header.type);
/* err = -EINVAL;
* assume we lost track of the stream, check alignment, and goto out_err;
* increment a single u64 in the hope to catch on again 'soon'.
*/
if (unlikely(head & 7))
head &= ~7ULL;
size = 8;
} }
head += size; head += size;
@ -1226,17 +1220,11 @@ more:
if (size == 0 || if (size == 0 ||
perf_session__process_event(session, event, tool, file_pos) < 0) { perf_session__process_event(session, event, tool, file_pos) < 0) {
dump_printf("%#" PRIx64 " [%#x]: skipping unknown header type: %d\n", pr_err("%#" PRIx64 " [%#x]: failed to process type: %d\n",
file_offset + head, event->header.size, file_offset + head, event->header.size,
event->header.type); event->header.type);
/* err = -EINVAL;
* assume we lost track of the stream, check alignment, and goto out_err;
* increment a single u64 in the hope to catch on again 'soon'.
*/
if (unlikely(head & 7))
head &= ~7ULL;
size = 8;
} }
head += size; head += size;

142
tools/perf/util/target.c Normal file
View File

@ -0,0 +1,142 @@
/*
* Helper functions for handling target threads/cpus
*
* Copyright (C) 2012, LG Electronics, Namhyung Kim <namhyung.kim@lge.com>
*
* Released under the GPL v2.
*/
#include "target.h"
#include "debug.h"
#include <pwd.h>
#include <string.h>
enum perf_target_errno perf_target__validate(struct perf_target *target)
{
enum perf_target_errno ret = PERF_ERRNO_TARGET__SUCCESS;
if (target->pid)
target->tid = target->pid;
/* CPU and PID are mutually exclusive */
if (target->tid && target->cpu_list) {
target->cpu_list = NULL;
if (ret == PERF_ERRNO_TARGET__SUCCESS)
ret = PERF_ERRNO_TARGET__PID_OVERRIDE_CPU;
}
/* UID and PID are mutually exclusive */
if (target->tid && target->uid_str) {
target->uid_str = NULL;
if (ret == PERF_ERRNO_TARGET__SUCCESS)
ret = PERF_ERRNO_TARGET__PID_OVERRIDE_UID;
}
/* UID and CPU are mutually exclusive */
if (target->uid_str && target->cpu_list) {
target->cpu_list = NULL;
if (ret == PERF_ERRNO_TARGET__SUCCESS)
ret = PERF_ERRNO_TARGET__UID_OVERRIDE_CPU;
}
/* PID and SYSTEM are mutually exclusive */
if (target->tid && target->system_wide) {
target->system_wide = false;
if (ret == PERF_ERRNO_TARGET__SUCCESS)
ret = PERF_ERRNO_TARGET__PID_OVERRIDE_SYSTEM;
}
/* UID and SYSTEM are mutually exclusive */
if (target->uid_str && target->system_wide) {
target->system_wide = false;
if (ret == PERF_ERRNO_TARGET__SUCCESS)
ret = PERF_ERRNO_TARGET__UID_OVERRIDE_SYSTEM;
}
return ret;
}
enum perf_target_errno perf_target__parse_uid(struct perf_target *target)
{
struct passwd pwd, *result;
char buf[1024];
const char *str = target->uid_str;
target->uid = UINT_MAX;
if (str == NULL)
return PERF_ERRNO_TARGET__SUCCESS;
/* Try user name first */
getpwnam_r(str, &pwd, buf, sizeof(buf), &result);
if (result == NULL) {
/*
* The user name not found. Maybe it's a UID number.
*/
char *endptr;
int uid = strtol(str, &endptr, 10);
if (*endptr != '\0')
return PERF_ERRNO_TARGET__INVALID_UID;
getpwuid_r(uid, &pwd, buf, sizeof(buf), &result);
if (result == NULL)
return PERF_ERRNO_TARGET__USER_NOT_FOUND;
}
target->uid = result->pw_uid;
return PERF_ERRNO_TARGET__SUCCESS;
}
/*
* This must have a same ordering as the enum perf_target_errno.
*/
static const char *perf_target__error_str[] = {
"PID/TID switch overriding CPU",
"PID/TID switch overriding UID",
"UID switch overriding CPU",
"PID/TID switch overriding SYSTEM",
"UID switch overriding SYSTEM",
"Invalid User: %s",
"Problems obtaining information for user %s",
};
int perf_target__strerror(struct perf_target *target, int errnum,
char *buf, size_t buflen)
{
int idx;
const char *msg;
if (errnum >= 0) {
strerror_r(errnum, buf, buflen);
return 0;
}
if (errnum < __PERF_ERRNO_TARGET__START ||
errnum >= __PERF_ERRNO_TARGET__END)
return -1;
idx = errnum - __PERF_ERRNO_TARGET__START;
msg = perf_target__error_str[idx];
switch (errnum) {
case PERF_ERRNO_TARGET__PID_OVERRIDE_CPU
... PERF_ERRNO_TARGET__UID_OVERRIDE_SYSTEM:
snprintf(buf, buflen, "%s", msg);
break;
case PERF_ERRNO_TARGET__INVALID_UID:
case PERF_ERRNO_TARGET__USER_NOT_FOUND:
snprintf(buf, buflen, msg, target->uid_str);
break;
default:
/* cannot reach here */
break;
}
return 0;
}

64
tools/perf/util/target.h Normal file
View File

@ -0,0 +1,64 @@
#ifndef _PERF_TARGET_H
#define _PERF_TARGET_H
#include <stdbool.h>
#include <sys/types.h>
struct perf_target {
const char *pid;
const char *tid;
const char *cpu_list;
const char *uid_str;
uid_t uid;
bool system_wide;
};
enum perf_target_errno {
PERF_ERRNO_TARGET__SUCCESS = 0,
/*
* Choose an arbitrary negative big number not to clash with standard
* errno since SUS requires the errno has distinct positive values.
* See 'Issue 6' in the link below.
*
* http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/errno.h.html
*/
__PERF_ERRNO_TARGET__START = -10000,
/* for perf_target__validate() */
PERF_ERRNO_TARGET__PID_OVERRIDE_CPU = __PERF_ERRNO_TARGET__START,
PERF_ERRNO_TARGET__PID_OVERRIDE_UID,
PERF_ERRNO_TARGET__UID_OVERRIDE_CPU,
PERF_ERRNO_TARGET__PID_OVERRIDE_SYSTEM,
PERF_ERRNO_TARGET__UID_OVERRIDE_SYSTEM,
/* for perf_target__parse_uid() */
PERF_ERRNO_TARGET__INVALID_UID,
PERF_ERRNO_TARGET__USER_NOT_FOUND,
__PERF_ERRNO_TARGET__END,
};
enum perf_target_errno perf_target__validate(struct perf_target *target);
enum perf_target_errno perf_target__parse_uid(struct perf_target *target);
int perf_target__strerror(struct perf_target *target, int errnum, char *buf,
size_t buflen);
static inline bool perf_target__no_task(struct perf_target *target)
{
return !target->pid && !target->tid && !target->uid_str;
}
static inline bool perf_target__no_cpu(struct perf_target *target)
{
return !target->system_wide && !target->cpu_list;
}
static inline bool perf_target__none(struct perf_target *target)
{
return perf_target__no_task(target) && perf_target__no_cpu(target);
}
#endif /* _PERF_TARGET_H */

View File

@ -69,23 +69,24 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size)
ret += SNPRINTF(bf + ret, size - ret, "], "); ret += SNPRINTF(bf + ret, size - ret, "], ");
if (top->target_pid) if (top->target.pid)
ret += SNPRINTF(bf + ret, size - ret, " (target_pid: %s", ret += SNPRINTF(bf + ret, size - ret, " (target_pid: %s",
top->target_pid); top->target.pid);
else if (top->target_tid) else if (top->target.tid)
ret += SNPRINTF(bf + ret, size - ret, " (target_tid: %s", ret += SNPRINTF(bf + ret, size - ret, " (target_tid: %s",
top->target_tid); top->target.tid);
else if (top->uid_str != NULL) else if (top->target.uid_str != NULL)
ret += SNPRINTF(bf + ret, size - ret, " (uid: %s", ret += SNPRINTF(bf + ret, size - ret, " (uid: %s",
top->uid_str); top->target.uid_str);
else else
ret += SNPRINTF(bf + ret, size - ret, " (all"); ret += SNPRINTF(bf + ret, size - ret, " (all");
if (top->cpu_list) if (top->target.cpu_list)
ret += SNPRINTF(bf + ret, size - ret, ", CPU%s: %s)", ret += SNPRINTF(bf + ret, size - ret, ", CPU%s: %s)",
top->evlist->cpus->nr > 1 ? "s" : "", top->cpu_list); top->evlist->cpus->nr > 1 ? "s" : "",
top->target.cpu_list);
else { else {
if (top->target_tid) if (top->target.tid)
ret += SNPRINTF(bf + ret, size - ret, ")"); ret += SNPRINTF(bf + ret, size - ret, ")");
else else
ret += SNPRINTF(bf + ret, size - ret, ", %d CPU%s)", ret += SNPRINTF(bf + ret, size - ret, ", %d CPU%s)",

View File

@ -13,6 +13,7 @@ struct perf_session;
struct perf_top { struct perf_top {
struct perf_tool tool; struct perf_tool tool;
struct perf_evlist *evlist; struct perf_evlist *evlist;
struct perf_target target;
/* /*
* Symbols will be added here in perf_event__process_sample and will * Symbols will be added here in perf_event__process_sample and will
* get out after decayed. * get out after decayed.
@ -23,10 +24,7 @@ struct perf_top {
u64 guest_us_samples, guest_kernel_samples; u64 guest_us_samples, guest_kernel_samples;
int print_entries, count_filter, delay_secs; int print_entries, count_filter, delay_secs;
int freq; int freq;
const char *target_pid, *target_tid;
uid_t uid;
bool hide_kernel_symbols, hide_user_symbols, zero; bool hide_kernel_symbols, hide_user_symbols, zero;
bool system_wide;
bool use_tui, use_stdio; bool use_tui, use_stdio;
bool sort_has_symbols; bool sort_has_symbols;
bool dont_use_callchains; bool dont_use_callchains;
@ -37,7 +35,6 @@ struct perf_top {
bool sample_id_all_missing; bool sample_id_all_missing;
bool exclude_guest_missing; bool exclude_guest_missing;
bool dump_symtab; bool dump_symtab;
const char *cpu_list;
struct hist_entry *sym_filter_entry; struct hist_entry *sym_filter_entry;
struct perf_evsel *sym_evsel; struct perf_evsel *sym_evsel;
struct perf_session *session; struct perf_session *session;
@ -47,7 +44,6 @@ struct perf_top {
int realtime_prio; int realtime_prio;
int sym_pcnt_filter; int sym_pcnt_filter;
const char *sym_filter; const char *sym_filter;
const char *uid_str;
}; };
size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size); size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size);

View File

@ -82,41 +82,3 @@ void warning(const char *warn, ...)
warn_routine(warn, params); warn_routine(warn, params);
va_end(params); va_end(params);
} }
uid_t parse_target_uid(const char *str, const char *tid, const char *pid)
{
struct passwd pwd, *result;
char buf[1024];
if (str == NULL)
return UINT_MAX;
/* UID and PID are mutually exclusive */
if (tid || pid) {
ui__warning("PID/TID switch overriding UID\n");
sleep(1);
return UINT_MAX;
}
getpwnam_r(str, &pwd, buf, sizeof(buf), &result);
if (result == NULL) {
char *endptr;
int uid = strtol(str, &endptr, 10);
if (*endptr != '\0') {
ui__error("Invalid user %s\n", str);
return UINT_MAX - 1;
}
getpwuid_r(uid, &pwd, buf, sizeof(buf), &result);
if (result == NULL) {
ui__error("Problems obtaining information for user %s\n",
str);
return UINT_MAX - 1;
}
}
return result->pw_uid;
}

View File

@ -74,7 +74,6 @@
#include <netinet/tcp.h> #include <netinet/tcp.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <netdb.h> #include <netdb.h>
#include <pwd.h>
#include <inttypes.h> #include <inttypes.h>
#include "../../../include/linux/magic.h" #include "../../../include/linux/magic.h"
#include "types.h" #include "types.h"
@ -249,8 +248,6 @@ struct perf_event_attr;
void event_attr_init(struct perf_event_attr *attr); void event_attr_init(struct perf_event_attr *attr);
uid_t parse_target_uid(const char *str, const char *tid, const char *pid);
#define _STR(x) #x #define _STR(x) #x
#define STR(x) _STR(x) #define STR(x) _STR(x)