Commit 5dcefda0 authored by Ingo Molnar's avatar Ingo Molnar

Merge tag 'perf-core-for-mingo' of...

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: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parents c4f400e8 5a5626b1
...@@ -300,6 +300,7 @@ LIB_H += util/cpumap.h ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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
......
...@@ -44,7 +44,6 @@ struct perf_record { ...@@ -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 @@ static void perf_record__open(struct perf_record *rec) ...@@ -218,7 +217,7 @@ static void perf_record__open(struct perf_record *rec)
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 @@ static void perf_record__open(struct perf_record *rec) ...@@ -243,9 +242,13 @@ static void perf_record__open(struct perf_record *rec)
/* /*
* 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 @@ static void perf_record__open(struct perf_record *rec) ...@@ -253,6 +256,10 @@ static void perf_record__open(struct perf_record *rec)
"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) ...@@ -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[] = { ...@@ -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[] = { ...@@ -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[] = { ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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);
goto out_free_fd; ui__warning("%s", errbuf);
}
if (rec->opts.target_pid) err = perf_target__parse_uid(&rec->opts.target);
rec->opts.target_tid = rec->opts.target_pid; 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;
}
if (perf_evlist__create_maps(evsel_list, rec->opts.target_pid, err = -ENOMEM;
rec->opts.target_tid, rec->opts.uid, if (perf_evlist__create_maps(evsel_list, &rec->opts.target) < 0)
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) {
......
...@@ -304,7 +304,7 @@ static size_t hists__fprintf_nr_sample_events(struct hists *self, ...@@ -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) ...@@ -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)
perf_gtk_setup_browser(argc, argv, true);
else
setup_browser(true); setup_browser(true);
} else { 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,
......
...@@ -175,22 +175,21 @@ static struct perf_event_attr very_very_detailed_attrs[] = { ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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[] = { ...@@ -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[] = { ...@@ -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) ...@@ -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) ...@@ -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");
usage_with_options(stat_usage, options); if (!perf_target__no_cpu(&target))
}
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"); perror("failed to parse CPUs map");
usage_with_options(stat_usage, options); usage_with_options(stat_usage, options);
return -1; return -1;
} }
......
...@@ -1165,6 +1165,9 @@ static int sched__get_first_possible_cpu(pid_t pid, cpu_set_t **maskp, ...@@ -1165,6 +1165,9 @@ static int sched__get_first_possible_cpu(pid_t pid, cpu_set_t **maskp,
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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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;
......
...@@ -588,7 +588,7 @@ static void *display_thread_tui(void *arg) ...@@ -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 @@ static void perf_top__start_counters(struct perf_top *top) ...@@ -948,6 +948,10 @@ static void perf_top__start_counters(struct perf_top *top)
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) ...@@ -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[] = { ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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 */ status = perf_target__parse_uid(&top.target);
if (top.target_tid && top.cpu_list) { if (status) {
printf("WARNING: PID switch overriding CPU\n"); int saved_errno = errno;
sleep(1);
top.cpu_list = NULL; perf_target__strerror(&top.target, status, errbuf, BUFSIZ);
ui__warning("%s", errbuf);
status = -saved_errno;
goto out_delete_evlist;
} }
if (top.target_pid) if (perf_target__none(&top.target))
top.target_tid = top.target_pid; top.target.system_wide = true;
if (perf_evlist__create_maps(top.evlist, top.target_pid, if (perf_evlist__create_maps(top.evlist, &top.target) < 0)
top.target_tid, top.uid, top.cpu_list) < 0)
usage_with_options(top_usage, options); usage_with_options(top_usage, options);
if (!top.evlist->nr_entries && if (!top.evlist->nr_entries &&
......
...@@ -207,10 +207,10 @@ extern const char perf_version_string[]; ...@@ -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 { ...@@ -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 { ...@@ -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
...@@ -547,9 +547,9 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx, ...@@ -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)
......
...@@ -941,7 +941,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, ...@@ -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, ...@@ -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:
......
...@@ -9,24 +9,13 @@ ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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);
......
#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();
}
#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;
if (fallback_to_pager)
setup_pager();
return;
}
/* default to TUI */
if (use_browser < 0)
use_browser = 1; use_browser = 1;
newtInit();
ui__init();
newtSetSuspendCallback(newt_suspend, NULL);
ui_helpline__init();
ui_browser__init();
signal(SIGSEGV, ui__signal); switch (use_browser) {
signal(SIGFPE, ui__signal); case 2:
signal(SIGINT, ui__signal); if (perf_gtk__init() == 0)
signal(SIGQUIT, ui__signal); break;
signal(SIGTERM, ui__signal); /* fall through */
case 1:
use_browser = 1;
if (ui__init() == 0)
break;
/* fall through */
default:
if (fallback_to_pager)
setup_pager();
break;
}
} }
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;
} }
} }
#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();
}
...@@ -33,7 +33,7 @@ extern int pager_use_color; ...@@ -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) {} ...@@ -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);
......
...@@ -11,6 +11,7 @@ ...@@ -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;
......
...@@ -11,6 +11,7 @@ ...@@ -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, ...@@ -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, ...@@ -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]);
......
...@@ -106,8 +106,8 @@ static inline void perf_evlist__set_maps(struct perf_evlist *evlist, ...@@ -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);
......
...@@ -14,6 +14,7 @@ ...@@ -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, ...@@ -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, ...@@ -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;
......
...@@ -31,21 +31,16 @@ static const char **header_argv; ...@@ -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) {
events = malloc(sizeof(struct perf_trace_event_type));
if (events == NULL)
return -ENOMEM;
} else {
struct perf_trace_event_type *nevents;
nevents = realloc(events, (event_count + 1) * sizeof(*events)); nevents = realloc(events, (event_count + 1) * sizeof(*events));
if (nevents == NULL) if (nevents == NULL)
return -ENOMEM; return -ENOMEM;
events = nevents; 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);
......
...@@ -4,7 +4,9 @@ ...@@ -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;
......
...@@ -1108,16 +1108,10 @@ static int __perf_session__process_pipe_events(struct perf_session *self, ...@@ -1108,16 +1108,10 @@ static int __perf_session__process_pipe_events(struct perf_session *self,
} }
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 @@ int __perf_session__process_events(struct perf_session *session, ...@@ -1226,17 +1220,11 @@ int __perf_session__process_events(struct perf_session *session,
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;
......
/*
* 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;
}
#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 */
...@@ -69,23 +69,24 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size) ...@@ -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)",
......
...@@ -13,6 +13,7 @@ struct perf_session; ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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);
......
...@@ -82,41 +82,3 @@ void warning(const char *warn, ...) ...@@ -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;
}
...@@ -74,7 +74,6 @@ ...@@ -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; ...@@ -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)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment