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:
commit
5dcefda0fd
27 changed files with 584 additions and 370 deletions
|
@ -300,6 +300,7 @@ LIB_H += util/cpumap.h
|
|||
LIB_H += util/top.h
|
||||
LIB_H += $(ARCH_INCLUDE)
|
||||
LIB_H += util/cgroup.h
|
||||
LIB_H += util/target.h
|
||||
|
||||
LIB_OBJS += $(OUTPUT)util/abspath.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/cpumap.o
|
||||
LIB_OBJS += $(OUTPUT)util/cgroup.o
|
||||
LIB_OBJS += $(OUTPUT)util/target.o
|
||||
|
||||
BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o
|
||||
|
||||
|
@ -481,6 +483,7 @@ else
|
|||
LIB_OBJS += $(OUTPUT)ui/helpline.o
|
||||
LIB_OBJS += $(OUTPUT)ui/progress.o
|
||||
LIB_OBJS += $(OUTPUT)ui/util.o
|
||||
LIB_OBJS += $(OUTPUT)ui/tui/setup.o
|
||||
LIB_H += ui/browser.h
|
||||
LIB_H += ui/browsers/map.h
|
||||
LIB_H += ui/helpline.h
|
||||
|
@ -503,6 +506,11 @@ else
|
|||
BASIC_CFLAGS += $(shell pkg-config --cflags gtk+-2.0)
|
||||
EXTLIBS += $(shell pkg-config --libs gtk+-2.0)
|
||||
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
|
||||
|
||||
|
|
|
@ -44,7 +44,6 @@ struct perf_record {
|
|||
struct perf_evlist *evlist;
|
||||
struct perf_session *session;
|
||||
const char *progname;
|
||||
const char *uid_str;
|
||||
int output;
|
||||
unsigned int page_size;
|
||||
int realtime_prio;
|
||||
|
@ -218,7 +217,7 @@ static void perf_record__open(struct perf_record *rec)
|
|||
if (err == EPERM || err == EACCES) {
|
||||
ui__error_paranoid();
|
||||
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"
|
||||
" an out-of-range profile CPU?\n");
|
||||
} else if (err == EINVAL) {
|
||||
|
@ -243,9 +242,13 @@ static void perf_record__open(struct perf_record *rec)
|
|||
/*
|
||||
* If it's cycles then fall back to hrtimer
|
||||
* 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) {
|
||||
|
||||
if (verbose)
|
||||
|
@ -253,6 +256,10 @@ static void perf_record__open(struct perf_record *rec)
|
|||
"trying to fall back to cpu-clock-ticks\n");
|
||||
attr->type = PERF_TYPE_SOFTWARE;
|
||||
attr->config = PERF_COUNT_SW_CPU_CLOCK;
|
||||
if (pos->name) {
|
||||
free(pos->name);
|
||||
pos->name = NULL;
|
||||
}
|
||||
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_event__synthesize_guest_os);
|
||||
|
||||
if (!opts->system_wide)
|
||||
if (!opts->target.system_wide)
|
||||
perf_event__synthesize_thread_map(tool, evsel_list->threads,
|
||||
process_synthesized_event,
|
||||
machine);
|
||||
|
@ -765,9 +772,9 @@ const struct option record_options[] = {
|
|||
parse_events_option),
|
||||
OPT_CALLBACK(0, "filter", &record.evlist, "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"),
|
||||
OPT_STRING('t', "tid", &record.opts.target_tid, "tid",
|
||||
OPT_STRING('t', "tid", &record.opts.target.tid, "tid",
|
||||
"record events on existing thread id"),
|
||||
OPT_INTEGER('r', "realtime", &record.realtime_prio,
|
||||
"collect data with this RT SCHED_FIFO priority"),
|
||||
|
@ -775,11 +782,11 @@ const struct option record_options[] = {
|
|||
"collect data without buffering"),
|
||||
OPT_BOOLEAN('R', "raw-samples", &record.opts.raw_samples,
|
||||
"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"),
|
||||
OPT_BOOLEAN('A', "append", &record.append_file,
|
||||
"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"),
|
||||
OPT_BOOLEAN('f', "force", &record.force,
|
||||
"overwrite existing data file (deprecated)"),
|
||||
|
@ -813,7 +820,8 @@ const struct option record_options[] = {
|
|||
OPT_CALLBACK('G', "cgroup", &record.evlist, "name",
|
||||
"monitor event in cgroup name only",
|
||||
parse_cgroups),
|
||||
OPT_STRING('u', "uid", &record.uid_str, "user", "user to profile"),
|
||||
OPT_STRING('u', "uid", &record.opts.target.uid_str, "user",
|
||||
"user to profile"),
|
||||
|
||||
OPT_CALLBACK_NOOPT('b', "branch-any", &record.opts.branch_stack,
|
||||
"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_evlist *evsel_list;
|
||||
struct perf_record *rec = &record;
|
||||
char errbuf[BUFSIZ];
|
||||
|
||||
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,
|
||||
PARSE_OPT_STOP_AT_NON_OPTION);
|
||||
if (!argc && !rec->opts.target_pid && !rec->opts.target_tid &&
|
||||
!rec->opts.system_wide && !rec->opts.cpu_list && !rec->uid_str)
|
||||
if (!argc && perf_target__none(&rec->opts.target))
|
||||
usage_with_options(record_usage, record_options);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (nr_cgroups && !rec->opts.system_wide) {
|
||||
if (nr_cgroups && !rec->opts.target.system_wide) {
|
||||
fprintf(stderr, "cgroup monitoring only available in"
|
||||
" system-wide mode\n");
|
||||
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;
|
||||
}
|
||||
|
||||
rec->opts.uid = parse_target_uid(rec->uid_str, rec->opts.target_tid,
|
||||
rec->opts.target_pid);
|
||||
if (rec->uid_str != NULL && rec->opts.uid == UINT_MAX - 1)
|
||||
err = perf_target__validate(&rec->opts.target);
|
||||
if (err) {
|
||||
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;
|
||||
}
|
||||
|
||||
if (rec->opts.target_pid)
|
||||
rec->opts.target_tid = rec->opts.target_pid;
|
||||
|
||||
if (perf_evlist__create_maps(evsel_list, rec->opts.target_pid,
|
||||
rec->opts.target_tid, rec->opts.uid,
|
||||
rec->opts.cpu_list) < 0)
|
||||
err = -ENOMEM;
|
||||
if (perf_evlist__create_maps(evsel_list, &rec->opts.target) < 0)
|
||||
usage_with_options(record_usage, record_options);
|
||||
|
||||
list_for_each_entry(pos, &evsel_list->entries, node) {
|
||||
|
|
|
@ -304,7 +304,7 @@ static size_t hists__fprintf_nr_sample_events(struct hists *self,
|
|||
if (evname != NULL)
|
||||
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");
|
||||
}
|
||||
|
||||
|
@ -676,14 +676,10 @@ int cmd_report(int argc, const char **argv, const char *prefix __used)
|
|||
|
||||
}
|
||||
|
||||
if (strcmp(report.input_name, "-") != 0) {
|
||||
if (report.use_gtk)
|
||||
perf_gtk_setup_browser(argc, argv, true);
|
||||
else
|
||||
setup_browser(true);
|
||||
} else {
|
||||
if (strcmp(report.input_name, "-") != 0)
|
||||
setup_browser(true);
|
||||
else
|
||||
use_browser = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Only in the newt browser we are doing integrated annotation,
|
||||
|
|
|
@ -175,22 +175,21 @@ static struct perf_event_attr very_very_detailed_attrs[] = {
|
|||
|
||||
static struct perf_evlist *evsel_list;
|
||||
|
||||
static bool system_wide = false;
|
||||
static int run_idx = 0;
|
||||
static struct perf_target target = {
|
||||
.uid = UINT_MAX,
|
||||
};
|
||||
|
||||
static int run_idx = 0;
|
||||
static int run_count = 1;
|
||||
static bool no_inherit = false;
|
||||
static bool scale = true;
|
||||
static bool no_aggr = false;
|
||||
static const char *target_pid;
|
||||
static const char *target_tid;
|
||||
static pid_t child_pid = -1;
|
||||
static bool null_run = false;
|
||||
static int detailed_run = 0;
|
||||
static bool sync_run = false;
|
||||
static bool big_num = true;
|
||||
static int big_num_opt = -1;
|
||||
static const char *cpu_list;
|
||||
static const char *csv_sep = NULL;
|
||||
static bool csv_output = false;
|
||||
static bool group = false;
|
||||
|
@ -293,10 +292,10 @@ static int create_perf_stat_counter(struct perf_evsel *evsel,
|
|||
|
||||
attr->inherit = !no_inherit;
|
||||
|
||||
if (system_wide)
|
||||
if (!perf_target__no_cpu(&target))
|
||||
return perf_evsel__open_per_cpu(evsel, evsel_list->cpus,
|
||||
group, group_fd);
|
||||
if (!target_pid && !target_tid && (!group || evsel == first)) {
|
||||
if (perf_target__no_task(&target) && (!group || evsel == first)) {
|
||||
attr->disabled = 1;
|
||||
attr->enable_on_exec = 1;
|
||||
}
|
||||
|
@ -446,7 +445,7 @@ static int run_perf_stat(int argc __used, const char **argv)
|
|||
exit(-1);
|
||||
}
|
||||
|
||||
if (!target_tid && !target_pid && !system_wide)
|
||||
if (perf_target__none(&target))
|
||||
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) {
|
||||
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 ||
|
||||
errno == ENOENT || errno == EOPNOTSUPP) {
|
||||
errno == ENOENT || errno == EOPNOTSUPP ||
|
||||
errno == ENXIO) {
|
||||
if (verbose)
|
||||
ui__warning("%s event is not supported by the kernel.\n",
|
||||
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"
|
||||
"\t Consider tweaking"
|
||||
" /proc/sys/kernel/perf_event_paranoid or running as root.",
|
||||
system_wide ? "system-wide " : "");
|
||||
target.system_wide ? "system-wide " : "");
|
||||
} else {
|
||||
error("open_counter returned with %d (%s). "
|
||||
"/bin/dmesg may provide additional information.\n",
|
||||
|
@ -968,14 +972,14 @@ static void print_stat(int argc, const char **argv)
|
|||
if (!csv_output) {
|
||||
fprintf(output, "\n");
|
||||
fprintf(output, " Performance counter stats for ");
|
||||
if (!target_pid && !target_tid) {
|
||||
if (perf_target__no_task(&target)) {
|
||||
fprintf(output, "\'%s", argv[0]);
|
||||
for (i = 1; i < argc; i++)
|
||||
fprintf(output, " %s", argv[i]);
|
||||
} else if (target_pid)
|
||||
fprintf(output, "process id \'%s", target_pid);
|
||||
} else if (target.pid)
|
||||
fprintf(output, "process id \'%s", target.pid);
|
||||
else
|
||||
fprintf(output, "thread id \'%s", target_tid);
|
||||
fprintf(output, "thread id \'%s", target.tid);
|
||||
|
||||
fprintf(output, "\'");
|
||||
if (run_count > 1)
|
||||
|
@ -1049,11 +1053,11 @@ static const struct option options[] = {
|
|||
"event filter", parse_filter),
|
||||
OPT_BOOLEAN('i', "no-inherit", &no_inherit,
|
||||
"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"),
|
||||
OPT_STRING('t', "tid", &target_tid, "tid",
|
||||
OPT_STRING('t', "tid", &target.tid, "tid",
|
||||
"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"),
|
||||
OPT_BOOLEAN('g', "group", &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,
|
||||
"print large numbers with thousands\' separators",
|
||||
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"),
|
||||
OPT_BOOLEAN('A', "no-aggr", &no_aggr,
|
||||
"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 */
|
||||
big_num = false;
|
||||
|
||||
if (!argc && !target_pid && !target_tid)
|
||||
if (!argc && perf_target__no_task(&target))
|
||||
usage_with_options(stat_usage, options);
|
||||
if (run_count <= 0)
|
||||
usage_with_options(stat_usage, options);
|
||||
|
||||
/* 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 "
|
||||
"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())
|
||||
goto out;
|
||||
|
||||
if (target_pid)
|
||||
target_tid = target_pid;
|
||||
perf_target__validate(&target);
|
||||
|
||||
evsel_list->threads = thread_map__new_str(target_pid,
|
||||
target_tid, UINT_MAX);
|
||||
if (evsel_list->threads == NULL) {
|
||||
pr_err("Problems finding threads of monitor\n");
|
||||
usage_with_options(stat_usage, options);
|
||||
}
|
||||
if (perf_evlist__create_maps(evsel_list, &target) < 0) {
|
||||
if (!perf_target__no_task(&target))
|
||||
pr_err("Problems finding threads of monitor\n");
|
||||
if (!perf_target__no_cpu(&target))
|
||||
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);
|
||||
return -1;
|
||||
}
|
||||
|
|
|
@ -1165,6 +1165,9 @@ static int sched__get_first_possible_cpu(pid_t pid, cpu_set_t **maskp,
|
|||
static int test__PERF_RECORD(void)
|
||||
{
|
||||
struct perf_record_opts opts = {
|
||||
.target = {
|
||||
.uid = UINT_MAX,
|
||||
},
|
||||
.no_delay = true,
|
||||
.freq = 10,
|
||||
.mmap_pages = 256,
|
||||
|
@ -1207,8 +1210,7 @@ static int test__PERF_RECORD(void)
|
|||
* perf_evlist__prepare_workload we'll fill in the only thread
|
||||
* we're monitoring, the one forked there.
|
||||
*/
|
||||
err = perf_evlist__create_maps(evlist, opts.target_pid,
|
||||
opts.target_tid, UINT_MAX, opts.cpu_list);
|
||||
err = perf_evlist__create_maps(evlist, &opts.target);
|
||||
if (err < 0) {
|
||||
pr_debug("Not enough memory to create thread/cpu maps\n");
|
||||
goto out_delete_evlist;
|
||||
|
@ -1549,8 +1551,6 @@ static int __test__rdpmc(void)
|
|||
sa.sa_sigaction = segfault_handler;
|
||||
sigaction(SIGSEGV, &sa, NULL);
|
||||
|
||||
fprintf(stderr, "\n\n");
|
||||
|
||||
fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
|
||||
if (fd < 0) {
|
||||
die("Error: sys_perf_event_open() syscall returned "
|
||||
|
@ -1575,7 +1575,7 @@ static int __test__rdpmc(void)
|
|||
loops *= 10;
|
||||
|
||||
delta = now - stamp;
|
||||
fprintf(stderr, "%14d: %14Lu\n", n, (long long)delta);
|
||||
pr_debug("%14d: %14Lu\n", n, (long long)delta);
|
||||
|
||||
delta_sum += delta;
|
||||
}
|
||||
|
@ -1583,7 +1583,7 @@ static int __test__rdpmc(void)
|
|||
munmap(addr, page_size);
|
||||
close(fd);
|
||||
|
||||
fprintf(stderr, " ");
|
||||
pr_debug(" ");
|
||||
|
||||
if (!delta_sum)
|
||||
return -1;
|
||||
|
|
|
@ -588,7 +588,7 @@ static void *display_thread_tui(void *arg)
|
|||
* via --uid.
|
||||
*/
|
||||
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_top__sort_new_samples,
|
||||
|
@ -948,6 +948,10 @@ static void perf_top__start_counters(struct perf_top *top)
|
|||
|
||||
attr->type = PERF_TYPE_SOFTWARE;
|
||||
attr->config = PERF_COUNT_SW_CPU_CLOCK;
|
||||
if (counter->name) {
|
||||
free(counter->name);
|
||||
counter->name = strdup(event_name(counter));
|
||||
}
|
||||
goto try_again;
|
||||
}
|
||||
|
||||
|
@ -1016,7 +1020,7 @@ static int __cmd_top(struct perf_top *top)
|
|||
if (ret)
|
||||
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__process,
|
||||
&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)
|
||||
{
|
||||
struct perf_evsel *pos;
|
||||
int status = -ENOMEM;
|
||||
int status;
|
||||
char errbuf[BUFSIZ];
|
||||
struct perf_top top = {
|
||||
.count_filter = 5,
|
||||
.delay_secs = 2,
|
||||
.uid = UINT_MAX,
|
||||
.freq = 1000, /* 1 KHz */
|
||||
.mmap_pages = 128,
|
||||
.sym_pcnt_filter = 5,
|
||||
|
@ -1166,13 +1170,13 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
|
|||
parse_events_option),
|
||||
OPT_INTEGER('c', "count", &top.default_interval,
|
||||
"event period to sample"),
|
||||
OPT_STRING('p', "pid", &top.target_pid, "pid",
|
||||
OPT_STRING('p', "pid", &top.target.pid, "pid",
|
||||
"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"),
|
||||
OPT_BOOLEAN('a', "all-cpus", &top.system_wide,
|
||||
OPT_BOOLEAN('a', "all-cpus", &top.target.system_wide,
|
||||
"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"),
|
||||
OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
|
||||
"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)"),
|
||||
OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
|
||||
"Specify disassembler style (e.g. -M intel for intel syntax)"),
|
||||
OPT_STRING('u', "uid", &top.uid_str, "user", "user to profile"),
|
||||
OPT_STRING('u', "uid", &top.target.uid_str, "user", "user to profile"),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
|
@ -1253,22 +1257,27 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
|
|||
|
||||
setup_browser(false);
|
||||
|
||||
top.uid = parse_target_uid(top.uid_str, top.target_tid, top.target_pid);
|
||||
if (top.uid_str != NULL && top.uid == UINT_MAX - 1)
|
||||
goto out_delete_evlist;
|
||||
|
||||
/* CPU and PID are mutually exclusive */
|
||||
if (top.target_tid && top.cpu_list) {
|
||||
printf("WARNING: PID switch overriding CPU\n");
|
||||
sleep(1);
|
||||
top.cpu_list = NULL;
|
||||
status = perf_target__validate(&top.target);
|
||||
if (status) {
|
||||
perf_target__strerror(&top.target, status, errbuf, BUFSIZ);
|
||||
ui__warning("%s", errbuf);
|
||||
}
|
||||
|
||||
if (top.target_pid)
|
||||
top.target_tid = top.target_pid;
|
||||
status = perf_target__parse_uid(&top.target);
|
||||
if (status) {
|
||||
int saved_errno = errno;
|
||||
|
||||
if (perf_evlist__create_maps(top.evlist, top.target_pid,
|
||||
top.target_tid, top.uid, top.cpu_list) < 0)
|
||||
perf_target__strerror(&top.target, status, errbuf, BUFSIZ);
|
||||
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);
|
||||
|
||||
if (!top.evlist->nr_entries &&
|
||||
|
|
|
@ -207,10 +207,10 @@ extern const char perf_version_string[];
|
|||
|
||||
void pthread__unblock_sigwinch(void);
|
||||
|
||||
#include "util/target.h"
|
||||
|
||||
struct perf_record_opts {
|
||||
const char *target_pid;
|
||||
const char *target_tid;
|
||||
uid_t uid;
|
||||
struct perf_target target;
|
||||
bool call_graph;
|
||||
bool group;
|
||||
bool inherit_stat;
|
||||
|
@ -223,7 +223,6 @@ struct perf_record_opts {
|
|||
bool sample_time;
|
||||
bool sample_id_all_missing;
|
||||
bool exclude_guest_missing;
|
||||
bool system_wide;
|
||||
bool period;
|
||||
unsigned int freq;
|
||||
unsigned int mmap_pages;
|
||||
|
@ -231,7 +230,6 @@ struct perf_record_opts {
|
|||
int branch_stack;
|
||||
u64 default_interval;
|
||||
u64 user_interval;
|
||||
const char *cpu_list;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -547,9 +547,9 @@ static int annotate_browser__run(struct annotate_browser *self, int evidx,
|
|||
struct map_symbol *ms = self->b.priv;
|
||||
struct symbol *sym = ms->sym;
|
||||
const char *help = "<-/ESC: Exit, TAB/shift+TAB: Cycle hot lines, "
|
||||
"H: Go to hottest line, ->/ENTER: Line action, "
|
||||
"O: Toggle offset view, "
|
||||
"S: Toggle source code view";
|
||||
"H: Hottest line, ->/ENTER: Line action, "
|
||||
"O: Offset view, "
|
||||
"S: Source view";
|
||||
int key;
|
||||
|
||||
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,
|
|||
goto zoom_dso;
|
||||
case 't':
|
||||
goto zoom_thread;
|
||||
case 's':
|
||||
case '/':
|
||||
if (ui_browser__input_window("Symbol to show",
|
||||
"Please enter the name of symbol you want to see",
|
||||
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"
|
||||
"d Zoom into current DSO\n"
|
||||
"t Zoom into current Thread\n"
|
||||
"s Filter symbol by name");
|
||||
"/ Filter symbol by name");
|
||||
continue;
|
||||
case K_ENTER:
|
||||
case K_RIGHT:
|
||||
|
|
|
@ -9,24 +9,13 @@
|
|||
|
||||
#define MAX_COLUMNS 32
|
||||
|
||||
void perf_gtk_setup_browser(int argc, const char *argv[],
|
||||
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)
|
||||
static void perf_gtk__signal(int sig)
|
||||
{
|
||||
psignal(sig, "perf");
|
||||
gtk_main_quit();
|
||||
}
|
||||
|
||||
static void perf_gtk_resize_window(GtkWidget *window)
|
||||
static void perf_gtk__resize_window(GtkWidget *window)
|
||||
{
|
||||
GdkRectangle rect;
|
||||
GdkScreen *screen;
|
||||
|
@ -46,7 +35,7 @@ static void perf_gtk_resize_window(GtkWidget *window)
|
|||
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];
|
||||
GtkCellRenderer *renderer;
|
||||
|
@ -142,11 +131,11 @@ int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist,
|
|||
GtkWidget *notebook;
|
||||
GtkWidget *window;
|
||||
|
||||
signal(SIGSEGV, perf_gtk_signal);
|
||||
signal(SIGFPE, perf_gtk_signal);
|
||||
signal(SIGINT, perf_gtk_signal);
|
||||
signal(SIGQUIT, perf_gtk_signal);
|
||||
signal(SIGTERM, perf_gtk_signal);
|
||||
signal(SIGSEGV, perf_gtk__signal);
|
||||
signal(SIGFPE, perf_gtk__signal);
|
||||
signal(SIGINT, perf_gtk__signal);
|
||||
signal(SIGQUIT, perf_gtk__signal);
|
||||
signal(SIGTERM, perf_gtk__signal);
|
||||
|
||||
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);
|
||||
|
||||
perf_gtk_show_hists(scrolled_window, hists);
|
||||
perf_gtk__show_hists(scrolled_window, hists);
|
||||
|
||||
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);
|
||||
|
||||
perf_gtk_resize_window(window);
|
||||
perf_gtk__resize_window(window);
|
||||
|
||||
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
|
||||
|
||||
|
|
12
tools/perf/ui/gtk/setup.c
Normal file
12
tools/perf/ui/gtk/setup.c
Normal 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();
|
||||
}
|
|
@ -1,155 +1,45 @@
|
|||
#include <newt.h>
|
||||
#include <signal.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "../cache.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)
|
||||
{
|
||||
if (!isatty(1) || !use_browser || dump_trace) {
|
||||
if (!isatty(1) || dump_trace)
|
||||
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)
|
||||
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)
|
||||
{
|
||||
if (use_browser > 0) {
|
||||
if (wait_for_ok)
|
||||
ui__question_window("Fatal Error",
|
||||
ui_helpline__last_msg,
|
||||
"Press any key...", 0);
|
||||
ui__exit();
|
||||
switch (use_browser) {
|
||||
case 2:
|
||||
perf_gtk__exit(wait_for_ok);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
ui__exit(wait_for_ok);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
140
tools/perf/ui/tui/setup.c
Normal file
140
tools/perf/ui/tui/setup.c
Normal 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();
|
||||
}
|
|
@ -33,7 +33,7 @@ extern int pager_use_color;
|
|||
|
||||
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)
|
||||
{
|
||||
if (fallback_to_pager)
|
||||
|
@ -43,19 +43,29 @@ static inline void exit_browser(bool wait_for_ok __used) {}
|
|||
#else
|
||||
void setup_browser(bool fallback_to_pager);
|
||||
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
|
||||
|
||||
#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)
|
||||
setup_pager();
|
||||
return -1;
|
||||
}
|
||||
static inline void perf_gtk_exit_browser(bool wait_for_ok __used) {}
|
||||
static inline void perf_gtk__exit(bool wait_for_ok __used) {}
|
||||
#else
|
||||
void perf_gtk_setup_browser(int argc, const char *argv[], bool fallback_to_pager);
|
||||
void perf_gtk_exit_browser(bool wait_for_ok);
|
||||
int perf_gtk__init(void);
|
||||
void perf_gtk__exit(bool wait_for_ok);
|
||||
#endif
|
||||
#endif /* NO_NEWT_SUPPORT && NO_GTK2_SUPPORT */
|
||||
|
||||
char *alias_lookup(const char *alias);
|
||||
int split_cmdline(char *cmdline, const char ***argv);
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "event.h"
|
||||
#include "debug.h"
|
||||
#include "util.h"
|
||||
#include "target.h"
|
||||
|
||||
int verbose;
|
||||
bool dump_trace = false, quiet = false;
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <poll.h>
|
||||
#include "cpumap.h"
|
||||
#include "thread_map.h"
|
||||
#include "target.h"
|
||||
#include "evlist.h"
|
||||
#include "evsel.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);
|
||||
}
|
||||
|
||||
int perf_evlist__create_maps(struct perf_evlist *evlist, const char *target_pid,
|
||||
const char *target_tid, uid_t uid, const char *cpu_list)
|
||||
int perf_evlist__create_maps(struct perf_evlist *evlist,
|
||||
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)
|
||||
return -1;
|
||||
|
||||
if (uid != UINT_MAX || (cpu_list == NULL && target_tid))
|
||||
evlist->cpus = cpu_map__dummy_new();
|
||||
if (!perf_target__no_cpu(target))
|
||||
evlist->cpus = cpu_map__new(target->cpu_list);
|
||||
else
|
||||
evlist->cpus = cpu_map__new(cpu_list);
|
||||
evlist->cpus = cpu_map__dummy_new();
|
||||
|
||||
if (evlist->cpus == NULL)
|
||||
goto out_delete_threads;
|
||||
|
@ -827,7 +829,7 @@ int perf_evlist__prepare_workload(struct perf_evlist *evlist,
|
|||
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;
|
||||
|
||||
close(child_ready_pipe[1]);
|
||||
|
|
|
@ -106,8 +106,8 @@ static inline void perf_evlist__set_maps(struct perf_evlist *evlist,
|
|||
evlist->threads = threads;
|
||||
}
|
||||
|
||||
int perf_evlist__create_maps(struct perf_evlist *evlist, const char *target_pid,
|
||||
const char *tid, uid_t uid, const char *cpu_list);
|
||||
int perf_evlist__create_maps(struct perf_evlist *evlist,
|
||||
struct perf_target *target);
|
||||
void perf_evlist__delete_maps(struct perf_evlist *evlist);
|
||||
int perf_evlist__set_filters(struct perf_evlist *evlist);
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "util.h"
|
||||
#include "cpumap.h"
|
||||
#include "thread_map.h"
|
||||
#include "target.h"
|
||||
|
||||
#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))
|
||||
|
@ -106,15 +107,15 @@ void perf_evsel__config(struct perf_evsel *evsel, struct perf_record_opts *opts,
|
|||
if (opts->call_graph)
|
||||
attr->sample_type |= PERF_SAMPLE_CALLCHAIN;
|
||||
|
||||
if (opts->system_wide)
|
||||
if (opts->target.system_wide)
|
||||
attr->sample_type |= PERF_SAMPLE_CPU;
|
||||
|
||||
if (opts->period)
|
||||
attr->sample_type |= PERF_SAMPLE_PERIOD;
|
||||
|
||||
if (!opts->sample_id_all_missing &&
|
||||
(opts->sample_time || opts->system_wide ||
|
||||
!opts->no_inherit || opts->cpu_list))
|
||||
(opts->sample_time || !opts->no_inherit ||
|
||||
!perf_target__no_cpu(&opts->target)))
|
||||
attr->sample_type |= PERF_SAMPLE_TIME;
|
||||
|
||||
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->comm = track;
|
||||
|
||||
if (!opts->target_pid && !opts->target_tid && !opts->system_wide &&
|
||||
if (perf_target__none(&opts->target) &&
|
||||
(!opts->group || evsel == first)) {
|
||||
attr->disabled = 1;
|
||||
attr->enable_on_exec = 1;
|
||||
|
|
|
@ -31,21 +31,16 @@ static const char **header_argv;
|
|||
|
||||
int perf_header__push_event(u64 id, const char *name)
|
||||
{
|
||||
struct perf_trace_event_type *nevents;
|
||||
|
||||
if (strlen(name) > MAX_EVENT_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));
|
||||
if (nevents == NULL)
|
||||
return -ENOMEM;
|
||||
events = 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));
|
||||
events[event_count].event_id = id;
|
||||
strncpy(events[event_count].name, name, MAX_EVENT_NAME - 1);
|
||||
|
|
|
@ -4,7 +4,9 @@
|
|||
* Parse symbolic events/counts passed in as options:
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "../../../include/linux/perf_event.h"
|
||||
#include "types.h"
|
||||
|
||||
struct list_head;
|
||||
struct perf_evsel;
|
||||
|
|
|
@ -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) {
|
||||
dump_printf("%#" PRIx64 " [%#x]: skipping unknown header type: %d\n",
|
||||
head, event.header.size, event.header.type);
|
||||
/*
|
||||
* assume we lost track of the stream, check alignment, and
|
||||
* increment a single u64 in the hope to catch on again 'soon'.
|
||||
*/
|
||||
if (unlikely(head & 7))
|
||||
head &= ~7ULL;
|
||||
|
||||
size = 8;
|
||||
pr_err("%#" PRIx64 " [%#x]: failed to process type: %d\n",
|
||||
head, event.header.size, event.header.type);
|
||||
err = -EINVAL;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
head += size;
|
||||
|
@ -1226,17 +1220,11 @@ int __perf_session__process_events(struct perf_session *session,
|
|||
|
||||
if (size == 0 ||
|
||||
perf_session__process_event(session, event, tool, file_pos) < 0) {
|
||||
dump_printf("%#" PRIx64 " [%#x]: skipping unknown header type: %d\n",
|
||||
file_offset + head, event->header.size,
|
||||
event->header.type);
|
||||
/*
|
||||
* assume we lost track of the stream, check alignment, and
|
||||
* increment a single u64 in the hope to catch on again 'soon'.
|
||||
*/
|
||||
if (unlikely(head & 7))
|
||||
head &= ~7ULL;
|
||||
|
||||
size = 8;
|
||||
pr_err("%#" PRIx64 " [%#x]: failed to process type: %d\n",
|
||||
file_offset + head, event->header.size,
|
||||
event->header.type);
|
||||
err = -EINVAL;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
head += size;
|
||||
|
|
142
tools/perf/util/target.c
Normal file
142
tools/perf/util/target.c
Normal 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
64
tools/perf/util/target.h
Normal 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 */
|
|
@ -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, "], ");
|
||||
|
||||
if (top->target_pid)
|
||||
if (top->target.pid)
|
||||
ret += SNPRINTF(bf + ret, size - ret, " (target_pid: %s",
|
||||
top->target_pid);
|
||||
else if (top->target_tid)
|
||||
top->target.pid);
|
||||
else if (top->target.tid)
|
||||
ret += SNPRINTF(bf + ret, size - ret, " (target_tid: %s",
|
||||
top->target_tid);
|
||||
else if (top->uid_str != NULL)
|
||||
top->target.tid);
|
||||
else if (top->target.uid_str != NULL)
|
||||
ret += SNPRINTF(bf + ret, size - ret, " (uid: %s",
|
||||
top->uid_str);
|
||||
top->target.uid_str);
|
||||
else
|
||||
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)",
|
||||
top->evlist->cpus->nr > 1 ? "s" : "", top->cpu_list);
|
||||
top->evlist->cpus->nr > 1 ? "s" : "",
|
||||
top->target.cpu_list);
|
||||
else {
|
||||
if (top->target_tid)
|
||||
if (top->target.tid)
|
||||
ret += SNPRINTF(bf + ret, size - ret, ")");
|
||||
else
|
||||
ret += SNPRINTF(bf + ret, size - ret, ", %d CPU%s)",
|
||||
|
|
|
@ -13,6 +13,7 @@ struct perf_session;
|
|||
struct perf_top {
|
||||
struct perf_tool tool;
|
||||
struct perf_evlist *evlist;
|
||||
struct perf_target target;
|
||||
/*
|
||||
* Symbols will be added here in perf_event__process_sample and will
|
||||
* get out after decayed.
|
||||
|
@ -23,10 +24,7 @@ struct perf_top {
|
|||
u64 guest_us_samples, guest_kernel_samples;
|
||||
int print_entries, count_filter, delay_secs;
|
||||
int freq;
|
||||
const char *target_pid, *target_tid;
|
||||
uid_t uid;
|
||||
bool hide_kernel_symbols, hide_user_symbols, zero;
|
||||
bool system_wide;
|
||||
bool use_tui, use_stdio;
|
||||
bool sort_has_symbols;
|
||||
bool dont_use_callchains;
|
||||
|
@ -37,7 +35,6 @@ struct perf_top {
|
|||
bool sample_id_all_missing;
|
||||
bool exclude_guest_missing;
|
||||
bool dump_symtab;
|
||||
const char *cpu_list;
|
||||
struct hist_entry *sym_filter_entry;
|
||||
struct perf_evsel *sym_evsel;
|
||||
struct perf_session *session;
|
||||
|
@ -47,7 +44,6 @@ struct perf_top {
|
|||
int realtime_prio;
|
||||
int sym_pcnt_filter;
|
||||
const char *sym_filter;
|
||||
const char *uid_str;
|
||||
};
|
||||
|
||||
size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size);
|
||||
|
|
|
@ -82,41 +82,3 @@ void warning(const char *warn, ...)
|
|||
warn_routine(warn, 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 @@
|
|||
#include <netinet/tcp.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <pwd.h>
|
||||
#include <inttypes.h>
|
||||
#include "../../../include/linux/magic.h"
|
||||
#include "types.h"
|
||||
|
@ -249,8 +248,6 @@ struct perf_event_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) _STR(x)
|
||||
|
||||
|
|
Loading…
Reference in a new issue