perf/core improvements and fixes:

User visible:
 
 - Print callchains asked for events requested via 'perf trace --event' too:
   (Arnaldo Carvalho de Melo)
 
   # trace -e nanosleep --call dwarf --event sched:sched_switch/call-graph=fp/ usleep 1
    0.346 (0.005 ms): usleep/24428 nanosleep(rqtp: 0x7fffa15a0540) ...
    0.346 (        ): sched:sched_switch:usleep:24428 [120] S ==> swapper/3:0 [120])
                                     __schedule+0xfe200402 ([kernel.kallsyms])
                                     schedule+0xfe200035 ([kernel.kallsyms])
                                     do_nanosleep+0xfe20006f ([kernel.kallsyms])
                                     hrtimer_nanosleep+0xfe2000dc ([kernel.kallsyms])
                                     sys_nanosleep+0xfe20007a ([kernel.kallsyms])
                                     do_syscall_64+0xfe200062 ([kernel.kallsyms])
                                     return_from_SYSCALL_64+0xfe200000 ([kernel.kallsyms])
                                     __nanosleep+0xffff005b8d602010 (/usr/lib64/libc-2.22.so)
    0.400 (0.059 ms): usleep/24428  ... [continued]: nanosleep()) = 0
                                     __nanosleep+0x10 (/usr/lib64/libc-2.22.so)
                                     usleep+0x34 (/usr/lib64/libc-2.22.so)
                                     main+0x1eb (/usr/bin/usleep)
                                     __libc_start_main+0xf0 (/usr/lib64/libc-2.22.so)
                                     _start+0x29 (/usr/bin/usleep)
 
 - Allow requesting that some CPUs or PIDs be highlighted in 'perf sched map' (Jiri Olsa)
 
 - Compact 'perf sched map' to show just CPUs with activity, improving the output
   in high core count systems (Jiri Olsa)
 
 - Fix segfault with 'perf trace --no-syscalls -e syscall-names' by bailing out
   such request, doesn't make sense to ask for no syscalls and then specify which
   ones should be printed (Arnaldo Carvalho de Melo)
 
 Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2
 
 iQIcBAABCAAGBQJXDljhAAoJENZQFvNTUqpARMwQAK+pwzNfcx4BJXA4RuPfb2cL
 rvlZKXvJuhdYtH+mEYjkqW24CDTMObXGzJHX/ESkADnhHqBz15/aCCYYcN6Ib6TC
 b4hYKR8VfGe1oWFyKavFEl2iHeTZHJKqR//CV6ujmcC9/q9CV8FFjiYptyswqIiI
 qS1clOTVh/xhKEZqhTfCq2CgJcX0G/N9iTJJ4nm5JAb4wAUeQeTyX5Tbw7CrKOOQ
 D21EYviHxDQM3urG8eEB7FXVRbrjGHI4V0MUEth8Arkx64fvC7UTwTb+tsWjVVji
 MHLi0yylLH8mdDpzEnjRcj1z8/FjiNh9Cc5arC12cBREy98Sy7J50fLiSyR6UWyY
 UUB1qTwYe4cqi0bPGt50nMzizH/lOcYcbgyWEiKxsH6pfuNWvOJReFJt+Ovpg/wc
 Xr/0mhUOhy/aIMfUvvSST/+f/01BFzIx49PpDquKU/XAnB1PSHTnERV2BdY3D9Jr
 s9JaaKahj5P333wqxgQfOS9d+eu259kQcSvgHcsKAzZv4hUGsdAMMYaUOIfx1jBH
 qMOdD5aW1kzhzN9rm7saUCKZtplM48ZFM7cXKduxHpMhDCiQnUAEp+faM+uQm+n7
 9TGMLIA7by0TohG/jRQqObq5a/d8oDtwNwlZvOMf+BoJrG6ZXYii5KZ0vSiBVfIJ
 e7PhQIBfsJaeb+98EGgv
 =VzVp
 -----END PGP SIGNATURE-----

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

Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo:

User visible changes:

- Print callchains asked for events requested via 'perf trace --event' too:
  (Arnaldo Carvalho de Melo)

  # trace -e nanosleep --call dwarf --event sched:sched_switch/call-graph=fp/ usleep 1
   0.346 (0.005 ms): usleep/24428 nanosleep(rqtp: 0x7fffa15a0540) ...
   0.346 (        ): sched:sched_switch:usleep:24428 [120] S ==> swapper/3:0 [120])
                                    __schedule+0xfe200402 ([kernel.kallsyms])
                                    schedule+0xfe200035 ([kernel.kallsyms])
                                    do_nanosleep+0xfe20006f ([kernel.kallsyms])
                                    hrtimer_nanosleep+0xfe2000dc ([kernel.kallsyms])
                                    sys_nanosleep+0xfe20007a ([kernel.kallsyms])
                                    do_syscall_64+0xfe200062 ([kernel.kallsyms])
                                    return_from_SYSCALL_64+0xfe200000 ([kernel.kallsyms])
                                    __nanosleep+0xffff005b8d602010 (/usr/lib64/libc-2.22.so)
   0.400 (0.059 ms): usleep/24428  ... [continued]: nanosleep()) = 0
                                    __nanosleep+0x10 (/usr/lib64/libc-2.22.so)
                                    usleep+0x34 (/usr/lib64/libc-2.22.so)
                                    main+0x1eb (/usr/bin/usleep)
                                    __libc_start_main+0xf0 (/usr/lib64/libc-2.22.so)
                                    _start+0x29 (/usr/bin/usleep)

- Allow requesting that some CPUs or PIDs be highlighted in 'perf sched map' (Jiri Olsa)

- Compact 'perf sched map' to show just CPUs with activity, improving the output
  in high core count systems (Jiri Olsa)

- Fix segfault with 'perf trace --no-syscalls -e syscall-names' by bailing out
  such request, doesn't make sense to ask for no syscalls and then specify which
  ones should be printed (Arnaldo Carvalho de Melo)

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
Ingo Molnar 2016-04-13 20:27:58 +02:00
commit c5ab6ad7f6
12 changed files with 416 additions and 178 deletions

View File

@ -50,6 +50,22 @@ OPTIONS
--dump-raw-trace=::
Display verbose dump of the sched data.
OPTIONS for 'perf sched map'
----------------------------
--compact::
Show only CPUs with activity. Helps visualizing on high core
count systems.
--cpus::
Show just entries with activities for the given CPUs.
--color-cpus::
Highlight the given cpus.
--color-pids::
Highlight the given pids.
SEE ALSO
--------
linkperf:perf-record[1]

View File

@ -11,6 +11,8 @@
#include "util/session.h"
#include "util/tool.h"
#include "util/cloexec.h"
#include "util/thread_map.h"
#include "util/color.h"
#include <subcmd/parse-options.h>
#include "util/trace-event.h"
@ -122,6 +124,21 @@ struct trace_sched_handler {
struct machine *machine);
};
#define COLOR_PIDS PERF_COLOR_BLUE
#define COLOR_CPUS PERF_COLOR_BG_RED
struct perf_sched_map {
DECLARE_BITMAP(comp_cpus_mask, MAX_CPUS);
int *comp_cpus;
bool comp;
struct thread_map *color_pids;
const char *color_pids_str;
struct cpu_map *color_cpus;
const char *color_cpus_str;
struct cpu_map *cpus;
const char *cpus_str;
};
struct perf_sched {
struct perf_tool tool;
const char *sort_order;
@ -173,6 +190,7 @@ struct perf_sched {
struct list_head sort_list, cmp_pid;
bool force;
bool skip_merge;
struct perf_sched_map map;
};
static u64 get_nsecs(void)
@ -1339,6 +1357,38 @@ static int process_sched_wakeup_event(struct perf_tool *tool,
return 0;
}
union map_priv {
void *ptr;
bool color;
};
static bool thread__has_color(struct thread *thread)
{
union map_priv priv = {
.ptr = thread__priv(thread),
};
return priv.color;
}
static struct thread*
map__findnew_thread(struct perf_sched *sched, struct machine *machine, pid_t pid, pid_t tid)
{
struct thread *thread = machine__findnew_thread(machine, pid, tid);
union map_priv priv = {
.color = false,
};
if (!sched->map.color_pids || !thread || thread__priv(thread))
return thread;
if (thread_map__has(sched->map.color_pids, tid))
priv.color = true;
thread__set_priv(thread, priv.ptr);
return thread;
}
static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel,
struct perf_sample *sample, struct machine *machine)
{
@ -1347,13 +1397,25 @@ static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel,
int new_shortname;
u64 timestamp0, timestamp = sample->time;
s64 delta;
int cpu, this_cpu = sample->cpu;
int i, this_cpu = sample->cpu;
int cpus_nr;
bool new_cpu = false;
const char *color = PERF_COLOR_NORMAL;
BUG_ON(this_cpu >= MAX_CPUS || this_cpu < 0);
if (this_cpu > sched->max_cpu)
sched->max_cpu = this_cpu;
if (sched->map.comp) {
cpus_nr = bitmap_weight(sched->map.comp_cpus_mask, MAX_CPUS);
if (!test_and_set_bit(this_cpu, sched->map.comp_cpus_mask)) {
sched->map.comp_cpus[cpus_nr++] = this_cpu;
new_cpu = true;
}
} else
cpus_nr = sched->max_cpu;
timestamp0 = sched->cpu_last_switched[this_cpu];
sched->cpu_last_switched[this_cpu] = timestamp;
if (timestamp0)
@ -1366,7 +1428,7 @@ static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel,
return -1;
}
sched_in = machine__findnew_thread(machine, -1, next_pid);
sched_in = map__findnew_thread(sched, machine, -1, next_pid);
if (sched_in == NULL)
return -1;
@ -1400,26 +1462,52 @@ static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel,
new_shortname = 1;
}
for (cpu = 0; cpu <= sched->max_cpu; cpu++) {
for (i = 0; i < cpus_nr; i++) {
int cpu = sched->map.comp ? sched->map.comp_cpus[i] : i;
struct thread *curr_thread = sched->curr_thread[cpu];
const char *pid_color = color;
const char *cpu_color = color;
if (curr_thread && thread__has_color(curr_thread))
pid_color = COLOR_PIDS;
if (sched->map.cpus && !cpu_map__has(sched->map.cpus, cpu))
continue;
if (sched->map.color_cpus && cpu_map__has(sched->map.color_cpus, cpu))
cpu_color = COLOR_CPUS;
if (cpu != this_cpu)
printf(" ");
color_fprintf(stdout, cpu_color, " ");
else
printf("*");
color_fprintf(stdout, cpu_color, "*");
if (sched->curr_thread[cpu])
printf("%2s ", sched->curr_thread[cpu]->shortname);
color_fprintf(stdout, pid_color, "%2s ", sched->curr_thread[cpu]->shortname);
else
printf(" ");
color_fprintf(stdout, color, " ");
}
printf(" %12.6f secs ", (double)timestamp/1e9);
if (sched->map.cpus && !cpu_map__has(sched->map.cpus, this_cpu))
goto out;
color_fprintf(stdout, color, " %12.6f secs ", (double)timestamp/1e9);
if (new_shortname) {
printf("%s => %s:%d\n",
const char *pid_color = color;
if (thread__has_color(sched_in))
pid_color = COLOR_PIDS;
color_fprintf(stdout, pid_color, "%s => %s:%d",
sched_in->shortname, thread__comm_str(sched_in), sched_in->tid);
} else {
printf("\n");
}
if (sched->map.comp && new_cpu)
color_fprintf(stdout, color, " (CPU %d)", this_cpu);
out:
color_fprintf(stdout, color, "\n");
thread__put(sched_in);
return 0;
@ -1675,9 +1763,75 @@ static int perf_sched__lat(struct perf_sched *sched)
return 0;
}
static int setup_map_cpus(struct perf_sched *sched)
{
struct cpu_map *map;
sched->max_cpu = sysconf(_SC_NPROCESSORS_CONF);
if (sched->map.comp) {
sched->map.comp_cpus = zalloc(sched->max_cpu * sizeof(int));
if (!sched->map.comp_cpus)
return -1;
}
if (!sched->map.cpus_str)
return 0;
map = cpu_map__new(sched->map.cpus_str);
if (!map) {
pr_err("failed to get cpus map from %s\n", sched->map.cpus_str);
return -1;
}
sched->map.cpus = map;
return 0;
}
static int setup_color_pids(struct perf_sched *sched)
{
struct thread_map *map;
if (!sched->map.color_pids_str)
return 0;
map = thread_map__new_by_tid_str(sched->map.color_pids_str);
if (!map) {
pr_err("failed to get thread map from %s\n", sched->map.color_pids_str);
return -1;
}
sched->map.color_pids = map;
return 0;
}
static int setup_color_cpus(struct perf_sched *sched)
{
struct cpu_map *map;
if (!sched->map.color_cpus_str)
return 0;
map = cpu_map__new(sched->map.color_cpus_str);
if (!map) {
pr_err("failed to get thread map from %s\n", sched->map.color_cpus_str);
return -1;
}
sched->map.color_cpus = map;
return 0;
}
static int perf_sched__map(struct perf_sched *sched)
{
sched->max_cpu = sysconf(_SC_NPROCESSORS_CONF);
if (setup_map_cpus(sched))
return -1;
if (setup_color_pids(sched))
return -1;
if (setup_color_cpus(sched))
return -1;
setup_pager();
if (perf_sched__read_events(sched))
@ -1831,6 +1985,17 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)
"dump raw trace in ASCII"),
OPT_END()
};
const struct option map_options[] = {
OPT_BOOLEAN(0, "compact", &sched.map.comp,
"map output in compact mode"),
OPT_STRING(0, "color-pids", &sched.map.color_pids_str, "pids",
"highlight given pids in map"),
OPT_STRING(0, "color-cpus", &sched.map.color_cpus_str, "cpus",
"highlight given CPUs in map"),
OPT_STRING(0, "cpus", &sched.map.cpus_str, "cpus",
"display given CPUs in map"),
OPT_END()
};
const char * const latency_usage[] = {
"perf sched latency [<options>]",
NULL
@ -1839,6 +2004,10 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)
"perf sched replay [<options>]",
NULL
};
const char * const map_usage[] = {
"perf sched map [<options>]",
NULL
};
const char *const sched_subcommands[] = { "record", "latency", "map",
"replay", "script", NULL };
const char *sched_usage[] = {
@ -1887,6 +2056,11 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)
setup_sorting(&sched, latency_options, latency_usage);
return perf_sched__lat(&sched);
} else if (!strcmp(argv[0], "map")) {
if (argc) {
argc = parse_options(argc, argv, map_options, map_usage, 0);
if (argc)
usage_with_options(map_usage, map_options);
}
sched.tp_handler = &map_ops;
setup_sorting(&sched, latency_options, latency_usage);
return perf_sched__map(&sched);

View File

@ -317,19 +317,19 @@ static void set_print_ip_opts(struct perf_event_attr *attr)
output[type].print_ip_opts = 0;
if (PRINT_FIELD(IP))
output[type].print_ip_opts |= PRINT_IP_OPT_IP;
output[type].print_ip_opts |= EVSEL__PRINT_IP;
if (PRINT_FIELD(SYM))
output[type].print_ip_opts |= PRINT_IP_OPT_SYM;
output[type].print_ip_opts |= EVSEL__PRINT_SYM;
if (PRINT_FIELD(DSO))
output[type].print_ip_opts |= PRINT_IP_OPT_DSO;
output[type].print_ip_opts |= EVSEL__PRINT_DSO;
if (PRINT_FIELD(SYMOFFSET))
output[type].print_ip_opts |= PRINT_IP_OPT_SYMOFFSET;
output[type].print_ip_opts |= EVSEL__PRINT_SYMOFFSET;
if (PRINT_FIELD(SRCLINE))
output[type].print_ip_opts |= PRINT_IP_OPT_SRCLINE;
output[type].print_ip_opts |= EVSEL__PRINT_SRCLINE;
}
/*
@ -574,9 +574,9 @@ static void print_sample_bts(struct perf_sample *sample,
printf("\n");
} else {
printf(" ");
if (print_opts & PRINT_IP_OPT_SRCLINE) {
if (print_opts & EVSEL__PRINT_SRCLINE) {
print_srcline_last = true;
print_opts &= ~PRINT_IP_OPT_SRCLINE;
print_opts &= ~EVSEL__PRINT_SRCLINE;
}
}
perf_evsel__fprintf_sym(evsel, sample, al, 0, print_opts,

View File

@ -2114,6 +2114,28 @@ out_put:
return err;
}
static int trace__fprintf_callchain(struct trace *trace, struct perf_evsel *evsel,
struct perf_sample *sample)
{
struct addr_location al;
/* TODO: user-configurable print_opts */
const unsigned int print_opts = EVSEL__PRINT_SYM |
EVSEL__PRINT_DSO |
EVSEL__PRINT_UNKNOWN_AS_ADDR;
if (sample->callchain == NULL)
return 0;
if (machine__resolve(trace->host, &al, sample) < 0) {
pr_err("Problem processing %s callchain, skipping...\n",
perf_evsel__name(evsel));
return 0;
}
return perf_evsel__fprintf_callchain(evsel, sample, &al, 38, print_opts,
scripting_max_stack, trace->output);
}
static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel,
union perf_event *event __maybe_unused,
struct perf_sample *sample)
@ -2193,21 +2215,7 @@ signed_print:
fputc('\n', trace->output);
if (sample->callchain) {
struct addr_location al;
/* TODO: user-configurable print_opts */
const unsigned int print_opts = PRINT_IP_OPT_SYM |
PRINT_IP_OPT_DSO |
PRINT_IP_OPT_UNKNOWN_AS_ADDR;
if (machine__resolve(trace->host, &al, sample) < 0) {
pr_err("problem processing %d event, skipping it.\n",
event->header.type);
goto out_put;
}
perf_evsel__fprintf_callchain(evsel, sample, &al, 38, print_opts,
scripting_max_stack, trace->output);
}
trace__fprintf_callchain(trace, evsel, sample);
out:
ttrace->entry_pending = false;
err = 0;
@ -2355,6 +2363,9 @@ static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
}
fprintf(trace->output, ")\n");
trace__fprintf_callchain(trace, evsel, sample);
return 0;
}
@ -3333,6 +3344,8 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
goto out;
}
err = -1;
if (trace.trace_pgfaults) {
trace.opts.sample_address = true;
trace.opts.sample_time = true;
@ -3357,6 +3370,11 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
return -1;
}
if (!trace.trace_syscalls && ev_qualifier_str) {
pr_err("The -e option can't be used with --no-syscalls.\n");
goto out;
}
if (output_name != NULL) {
err = trace__open_output(&trace, output_name);
if (err < 0) {

View File

@ -587,3 +587,15 @@ int cpu__setup_cpunode_map(void)
closedir(dir1);
return 0;
}
bool cpu_map__has(struct cpu_map *cpus, int cpu)
{
int i;
for (i = 0; i < cpus->nr; ++i) {
if (cpus->map[i] == cpu)
return true;
}
return false;
}

View File

@ -66,4 +66,6 @@ int cpu__get_node(int cpu);
int cpu_map__build_map(struct cpu_map *cpus, struct cpu_map **res,
int (*f)(struct cpu_map *map, int cpu, void *data),
void *data);
bool cpu_map__has(struct cpu_map *cpus, int cpu);
#endif /* __PERF_CPUMAP_H */

View File

@ -2343,6 +2343,137 @@ out:
return ++printed;
}
int perf_evsel__fprintf_callchain(struct perf_evsel *evsel, struct perf_sample *sample,
struct addr_location *al, int left_alignment,
unsigned int print_opts, unsigned int stack_depth,
FILE *fp)
{
int printed = 0;
struct callchain_cursor_node *node;
int print_ip = print_opts & EVSEL__PRINT_IP;
int print_sym = print_opts & EVSEL__PRINT_SYM;
int print_dso = print_opts & EVSEL__PRINT_DSO;
int print_symoffset = print_opts & EVSEL__PRINT_SYMOFFSET;
int print_oneline = print_opts & EVSEL__PRINT_ONELINE;
int print_srcline = print_opts & EVSEL__PRINT_SRCLINE;
int print_unknown_as_addr = print_opts & EVSEL__PRINT_UNKNOWN_AS_ADDR;
char s = print_oneline ? ' ' : '\t';
if (sample->callchain) {
struct addr_location node_al;
if (thread__resolve_callchain(al->thread, evsel,
sample, NULL, NULL,
stack_depth) != 0) {
if (verbose)
error("Failed to resolve callchain. Skipping\n");
return printed;
}
callchain_cursor_commit(&callchain_cursor);
if (print_symoffset)
node_al = *al;
while (stack_depth) {
u64 addr = 0;
node = callchain_cursor_current(&callchain_cursor);
if (!node)
break;
if (node->sym && node->sym->ignore)
goto next;
printed += fprintf(fp, "%-*.*s", left_alignment, left_alignment, " ");
if (print_ip)
printed += fprintf(fp, "%c%16" PRIx64, s, node->ip);
if (node->map)
addr = node->map->map_ip(node->map, node->ip);
if (print_sym) {
printed += fprintf(fp, " ");
node_al.addr = addr;
node_al.map = node->map;
if (print_symoffset) {
printed += __symbol__fprintf_symname_offs(node->sym, &node_al,
print_unknown_as_addr, fp);
} else {
printed += __symbol__fprintf_symname(node->sym, &node_al,
print_unknown_as_addr, fp);
}
}
if (print_dso) {
printed += fprintf(fp, " (");
printed += map__fprintf_dsoname(node->map, fp);
printed += fprintf(fp, ")");
}
if (print_srcline)
printed += map__fprintf_srcline(node->map, addr, "\n ", fp);
if (!print_oneline)
printed += fprintf(fp, "\n");
stack_depth--;
next:
callchain_cursor_advance(&callchain_cursor);
}
}
return printed;
}
int perf_evsel__fprintf_sym(struct perf_evsel *evsel, struct perf_sample *sample,
struct addr_location *al, int left_alignment,
unsigned int print_opts, unsigned int stack_depth,
FILE *fp)
{
int printed = 0;
int print_ip = print_opts & EVSEL__PRINT_IP;
int print_sym = print_opts & EVSEL__PRINT_SYM;
int print_dso = print_opts & EVSEL__PRINT_DSO;
int print_symoffset = print_opts & EVSEL__PRINT_SYMOFFSET;
int print_srcline = print_opts & EVSEL__PRINT_SRCLINE;
int print_unknown_as_addr = print_opts & EVSEL__PRINT_UNKNOWN_AS_ADDR;
if (symbol_conf.use_callchain && sample->callchain) {
printed += perf_evsel__fprintf_callchain(evsel, sample, al, left_alignment,
print_opts, stack_depth, fp);
} else if (!(al->sym && al->sym->ignore)) {
printed += fprintf(fp, "%-*.*s", left_alignment, left_alignment, " ");
if (print_ip)
printed += fprintf(fp, "%16" PRIx64, sample->ip);
if (print_sym) {
printed += fprintf(fp, " ");
if (print_symoffset) {
printed += __symbol__fprintf_symname_offs(al->sym, al,
print_unknown_as_addr, fp);
} else {
printed += __symbol__fprintf_symname(al->sym, al,
print_unknown_as_addr, fp);
}
}
if (print_dso) {
printed += fprintf(fp, " (");
printed += map__fprintf_dsoname(al->map, fp);
printed += fprintf(fp, ")");
}
if (print_srcline)
printed += map__fprintf_srcline(al->map, al->addr, "\n ", fp);
}
return printed;
}
bool perf_evsel__fallback(struct perf_evsel *evsel, int err,
char *msg, size_t msgsize)
{

View File

@ -387,12 +387,25 @@ struct perf_attr_details {
int perf_evsel__fprintf(struct perf_evsel *evsel,
struct perf_attr_details *details, FILE *fp);
#define EVSEL__PRINT_IP (1<<0)
#define EVSEL__PRINT_SYM (1<<1)
#define EVSEL__PRINT_DSO (1<<2)
#define EVSEL__PRINT_SYMOFFSET (1<<3)
#define EVSEL__PRINT_ONELINE (1<<4)
#define EVSEL__PRINT_SRCLINE (1<<5)
#define EVSEL__PRINT_UNKNOWN_AS_ADDR (1<<6)
int perf_evsel__fprintf_callchain(struct perf_evsel *evsel,
struct perf_sample *sample,
struct addr_location *al, int left_alignment,
unsigned int print_opts,
unsigned int stack_depth, FILE *fp);
int perf_evsel__fprintf_sym(struct perf_evsel *evsel, struct perf_sample *sample,
struct addr_location *al, int left_alignment,
unsigned int print_opts, unsigned int stack_depth,
FILE *fp);
bool perf_evsel__fallback(struct perf_evsel *evsel, int err,
char *msg, size_t msgsize);
int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target,

View File

@ -1953,136 +1953,6 @@ struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
return NULL;
}
int perf_evsel__fprintf_callchain(struct perf_evsel *evsel, struct perf_sample *sample,
struct addr_location *al, int left_alignment,
unsigned int print_opts, unsigned int stack_depth,
FILE *fp)
{
int printed = 0;
struct callchain_cursor_node *node;
int print_ip = print_opts & PRINT_IP_OPT_IP;
int print_sym = print_opts & PRINT_IP_OPT_SYM;
int print_dso = print_opts & PRINT_IP_OPT_DSO;
int print_symoffset = print_opts & PRINT_IP_OPT_SYMOFFSET;
int print_oneline = print_opts & PRINT_IP_OPT_ONELINE;
int print_srcline = print_opts & PRINT_IP_OPT_SRCLINE;
int print_unknown_as_addr = print_opts & PRINT_IP_OPT_UNKNOWN_AS_ADDR;
char s = print_oneline ? ' ' : '\t';
if (sample->callchain) {
struct addr_location node_al;
if (thread__resolve_callchain(al->thread, evsel,
sample, NULL, NULL,
stack_depth) != 0) {
if (verbose)
error("Failed to resolve callchain. Skipping\n");
return printed;
}
callchain_cursor_commit(&callchain_cursor);
if (print_symoffset)
node_al = *al;
while (stack_depth) {
u64 addr = 0;
node = callchain_cursor_current(&callchain_cursor);
if (!node)
break;
if (node->sym && node->sym->ignore)
goto next;
printed += fprintf(fp, "%-*.*s", left_alignment, left_alignment, " ");
if (print_ip)
printed += fprintf(fp, "%c%16" PRIx64, s, node->ip);
if (node->map)
addr = node->map->map_ip(node->map, node->ip);
if (print_sym) {
printed += fprintf(fp, " ");
node_al.addr = addr;
node_al.map = node->map;
if (print_symoffset) {
printed += __symbol__fprintf_symname_offs(node->sym, &node_al,
print_unknown_as_addr, fp);
} else {
printed += __symbol__fprintf_symname(node->sym, &node_al,
print_unknown_as_addr, fp);
}
}
if (print_dso) {
printed += fprintf(fp, " (");
printed += map__fprintf_dsoname(node->map, fp);
printed += fprintf(fp, ")");
}
if (print_srcline)
printed += map__fprintf_srcline(node->map, addr, "\n ", fp);
if (!print_oneline)
printed += fprintf(fp, "\n");
stack_depth--;
next:
callchain_cursor_advance(&callchain_cursor);
}
}
return printed;
}
int perf_evsel__fprintf_sym(struct perf_evsel *evsel, struct perf_sample *sample,
struct addr_location *al, int left_alignment,
unsigned int print_opts, unsigned int stack_depth,
FILE *fp)
{
int printed = 0;
int print_ip = print_opts & PRINT_IP_OPT_IP;
int print_sym = print_opts & PRINT_IP_OPT_SYM;
int print_dso = print_opts & PRINT_IP_OPT_DSO;
int print_symoffset = print_opts & PRINT_IP_OPT_SYMOFFSET;
int print_srcline = print_opts & PRINT_IP_OPT_SRCLINE;
int print_unknown_as_addr = print_opts & PRINT_IP_OPT_UNKNOWN_AS_ADDR;
if (symbol_conf.use_callchain && sample->callchain) {
printed += perf_evsel__fprintf_callchain(evsel, sample, al, left_alignment,
print_opts, stack_depth, fp);
} else if (!(al->sym && al->sym->ignore)) {
printed += fprintf(fp, "%-*.*s", left_alignment, left_alignment, " ");
if (print_ip)
printed += fprintf(fp, "%16" PRIx64, sample->ip);
if (print_sym) {
printed += fprintf(fp, " ");
if (print_symoffset) {
printed += __symbol__fprintf_symname_offs(al->sym, al,
print_unknown_as_addr, fp);
} else {
printed += __symbol__fprintf_symname(al->sym, al,
print_unknown_as_addr, fp);
}
}
if (print_dso) {
printed += fprintf(fp, " (");
printed += map__fprintf_dsoname(al->map, fp);
printed += fprintf(fp, ")");
}
if (print_srcline)
printed += map__fprintf_srcline(al->map, al->addr, "\n ", fp);
}
return printed;
}
int perf_session__cpu_bitmap(struct perf_session *session,
const char *cpu_list, unsigned long *cpu_bitmap)
{

View File

@ -36,14 +36,6 @@ struct perf_session {
struct perf_tool *tool;
};
#define PRINT_IP_OPT_IP (1<<0)
#define PRINT_IP_OPT_SYM (1<<1)
#define PRINT_IP_OPT_DSO (1<<2)
#define PRINT_IP_OPT_SYMOFFSET (1<<3)
#define PRINT_IP_OPT_ONELINE (1<<4)
#define PRINT_IP_OPT_SRCLINE (1<<5)
#define PRINT_IP_OPT_UNKNOWN_AS_ADDR (1<<6)
struct perf_tool;
struct perf_session *perf_session__new(struct perf_data_file *file,
@ -105,11 +97,6 @@ size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp);
struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
unsigned int type);
int perf_evsel__fprintf_sym(struct perf_evsel *evsel, struct perf_sample *sample,
struct addr_location *al, int left_alignment,
unsigned int print_opts, unsigned int stack_depth,
FILE *fp);
int perf_session__cpu_bitmap(struct perf_session *session,
const char *cpu_list, unsigned long *cpu_bitmap);

View File

@ -260,7 +260,7 @@ struct thread_map *thread_map__new_dummy(void)
return threads;
}
static struct thread_map *thread_map__new_by_tid_str(const char *tid_str)
struct thread_map *thread_map__new_by_tid_str(const char *tid_str)
{
struct thread_map *threads = NULL, *nt;
int ntasks = 0;
@ -436,3 +436,15 @@ struct thread_map *thread_map__new_event(struct thread_map_event *event)
return threads;
}
bool thread_map__has(struct thread_map *threads, pid_t pid)
{
int i;
for (i = 0; i < threads->nr; ++i) {
if (threads->map[i].pid == pid)
return true;
}
return false;
}

View File

@ -31,6 +31,8 @@ void thread_map__put(struct thread_map *map);
struct thread_map *thread_map__new_str(const char *pid,
const char *tid, uid_t uid);
struct thread_map *thread_map__new_by_tid_str(const char *tid_str);
size_t thread_map__fprintf(struct thread_map *threads, FILE *fp);
static inline int thread_map__nr(struct thread_map *threads)
@ -55,4 +57,5 @@ static inline char *thread_map__comm(struct thread_map *map, int thread)
}
void thread_map__read_comms(struct thread_map *threads);
bool thread_map__has(struct thread_map *threads, pid_t pid);
#endif /* __PERF_THREAD_MAP_H */