perf: 'perf kvm' tool for monitoring guest performance from host

Here is the patch of userspace perf tool.

Signed-off-by: Zhang Yanmin <yanmin_zhang@linux.intel.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
This commit is contained in:
Zhang, Yanmin
2010-04-19 13:32:50 +08:00
committed by Avi Kivity
parent ff9d07a0e7
commit a1645ce12a
30 changed files with 1407 additions and 316 deletions

View File

@@ -0,0 +1,67 @@
perf-kvm(1)
==============
NAME
----
perf-kvm - Tool to trace/measure kvm guest os
SYNOPSIS
--------
[verse]
'perf kvm' [--host] [--guest] [--guestmount=<path>
[--guestkallsyms=<path> --guestmodules=<path> | --guestvmlinux=<path>]]
{top|record|report|diff|buildid-list}
'perf kvm' [--host] [--guest] [--guestkallsyms=<path> --guestmodules=<path>
| --guestvmlinux=<path>] {top|record|report|diff|buildid-list}
DESCRIPTION
-----------
There are a couple of variants of perf kvm:
'perf kvm [options] top <command>' to generates and displays
a performance counter profile of guest os in realtime
of an arbitrary workload.
'perf kvm record <command>' to record the performance couinter profile
of an arbitrary workload and save it into a perf data file. If both
--host and --guest are input, the perf data file name is perf.data.kvm.
If there is no --host but --guest, the file name is perf.data.guest.
If there is no --guest but --host, the file name is perf.data.host.
'perf kvm report' to display the performance counter profile information
recorded via perf kvm record.
'perf kvm diff' to displays the performance difference amongst two perf.data
files captured via perf record.
'perf kvm buildid-list' to display the buildids found in a perf data file,
so that other tools can be used to fetch packages with matching symbol tables
for use by perf report.
OPTIONS
-------
--host=::
Collect host side perforamnce profile.
--guest=::
Collect guest side perforamnce profile.
--guestmount=<path>::
Guest os root file system mount directory. Users mounts guest os
root directories under <path> by a specific filesystem access method,
typically, sshfs. For example, start 2 guest os. The one's pid is 8888
and the other's is 9999.
#mkdir ~/guestmount; cd ~/guestmount
#sshfs -o allow_other,direct_io -p 5551 localhost:/ 8888/
#sshfs -o allow_other,direct_io -p 5552 localhost:/ 9999/
#perf kvm --host --guest --guestmount=~/guestmount top
--guestkallsyms=<path>::
Guest os /proc/kallsyms file copy. 'perf' kvm' reads it to get guest
kernel symbols. Users copy it out from guest os.
--guestmodules=<path>::
Guest os /proc/modules file copy. 'perf' kvm' reads it to get guest
kernel module information. Users copy it out from guest os.
--guestvmlinux=<path>::
Guest os kernel vmlinux.
SEE ALSO
--------
linkperf:perf-top[1] perf-record[1] perf-report[1] perf-diff[1] perf-buildid-list[1]

View File

@@ -472,6 +472,7 @@ BUILTIN_OBJS += $(OUTPUT)builtin-trace.o
BUILTIN_OBJS += $(OUTPUT)builtin-probe.o
BUILTIN_OBJS += $(OUTPUT)builtin-kmem.o
BUILTIN_OBJS += $(OUTPUT)builtin-lock.o
BUILTIN_OBJS += $(OUTPUT)builtin-kvm.o
PERFLIBS = $(LIB_FILE)

View File

@@ -571,7 +571,7 @@ static int __cmd_annotate(void)
perf_session__fprintf(session, stdout);
if (verbose > 2)
dsos__fprintf(stdout);
dsos__fprintf(&session->kerninfo_root, stdout);
perf_session__collapse_resort(&session->hists);
perf_session__output_resort(&session->hists, session->event_total[0]);

View File

@@ -46,7 +46,7 @@ static int __cmd_buildid_list(void)
if (with_hits)
perf_session__process_events(session, &build_id__mark_dso_hit_ops);
dsos__fprintf_buildid(stdout, with_hits);
dsos__fprintf_buildid(&session->kerninfo_root, stdout, with_hits);
perf_session__delete(session);
return err;

View File

@@ -33,7 +33,7 @@ static int perf_session__add_hist_entry(struct perf_session *self,
return -ENOMEM;
if (hit)
he->count += count;
__perf_session__add_count(he, al, count);
return 0;
}
@@ -225,6 +225,10 @@ int cmd_diff(int argc, const char **argv, const char *prefix __used)
input_new = argv[1];
} else
input_new = argv[0];
} else if (symbol_conf.default_guest_vmlinux_name ||
symbol_conf.default_guest_kallsyms) {
input_old = "perf.data.host";
input_new = "perf.data.guest";
}
symbol_conf.exclude_other = false;

View File

@@ -351,6 +351,7 @@ static void __print_result(struct rb_root *root, struct perf_session *session,
int n_lines, int is_caller)
{
struct rb_node *next;
struct kernel_info *kerninfo;
printf("%.102s\n", graph_dotted_line);
printf(" %-34s |", is_caller ? "Callsite": "Alloc Ptr");
@@ -359,10 +360,16 @@ static void __print_result(struct rb_root *root, struct perf_session *session,
next = rb_first(root);
kerninfo = kerninfo__findhost(&session->kerninfo_root);
if (!kerninfo) {
pr_err("__print_result: couldn't find kernel information\n");
return;
}
while (next && n_lines--) {
struct alloc_stat *data = rb_entry(next, struct alloc_stat,
node);
struct symbol *sym = NULL;
struct map_groups *kmaps = &kerninfo->kmaps;
struct map *map;
char buf[BUFSIZ];
u64 addr;
@@ -370,8 +377,8 @@ static void __print_result(struct rb_root *root, struct perf_session *session,
if (is_caller) {
addr = data->call_site;
if (!raw_ip)
sym = map_groups__find_function(&session->kmaps,
addr, &map, NULL);
sym = map_groups__find_function(kmaps, addr,
&map, NULL);
} else
addr = data->ptr;

144
tools/perf/builtin-kvm.c Normal file
View File

@@ -0,0 +1,144 @@
#include "builtin.h"
#include "perf.h"
#include "util/util.h"
#include "util/cache.h"
#include "util/symbol.h"
#include "util/thread.h"
#include "util/header.h"
#include "util/session.h"
#include "util/parse-options.h"
#include "util/trace-event.h"
#include "util/debug.h"
#include <sys/prctl.h>
#include <semaphore.h>
#include <pthread.h>
#include <math.h>
static char *file_name;
static char name_buffer[256];
int perf_host = 1;
int perf_guest;
static const char * const kvm_usage[] = {
"perf kvm [<options>] {top|record|report|diff|buildid-list}",
NULL
};
static const struct option kvm_options[] = {
OPT_STRING('i', "input", &file_name, "file",
"Input file name"),
OPT_STRING('o', "output", &file_name, "file",
"Output file name"),
OPT_BOOLEAN(0, "guest", &perf_guest,
"Collect guest os data"),
OPT_BOOLEAN(0, "host", &perf_host,
"Collect guest os data"),
OPT_STRING(0, "guestmount", &symbol_conf.guestmount, "directory",
"guest mount directory under which every guest os"
" instance has a subdir"),
OPT_STRING(0, "guestvmlinux", &symbol_conf.default_guest_vmlinux_name,
"file", "file saving guest os vmlinux"),
OPT_STRING(0, "guestkallsyms", &symbol_conf.default_guest_kallsyms,
"file", "file saving guest os /proc/kallsyms"),
OPT_STRING(0, "guestmodules", &symbol_conf.default_guest_modules,
"file", "file saving guest os /proc/modules"),
OPT_END()
};
static int __cmd_record(int argc, const char **argv)
{
int rec_argc, i = 0, j;
const char **rec_argv;
rec_argc = argc + 2;
rec_argv = calloc(rec_argc + 1, sizeof(char *));
rec_argv[i++] = strdup("record");
rec_argv[i++] = strdup("-o");
rec_argv[i++] = strdup(file_name);
for (j = 1; j < argc; j++, i++)
rec_argv[i] = argv[j];
BUG_ON(i != rec_argc);
return cmd_record(i, rec_argv, NULL);
}
static int __cmd_report(int argc, const char **argv)
{
int rec_argc, i = 0, j;
const char **rec_argv;
rec_argc = argc + 2;
rec_argv = calloc(rec_argc + 1, sizeof(char *));
rec_argv[i++] = strdup("report");
rec_argv[i++] = strdup("-i");
rec_argv[i++] = strdup(file_name);
for (j = 1; j < argc; j++, i++)
rec_argv[i] = argv[j];
BUG_ON(i != rec_argc);
return cmd_report(i, rec_argv, NULL);
}
static int __cmd_buildid_list(int argc, const char **argv)
{
int rec_argc, i = 0, j;
const char **rec_argv;
rec_argc = argc + 2;
rec_argv = calloc(rec_argc + 1, sizeof(char *));
rec_argv[i++] = strdup("buildid-list");
rec_argv[i++] = strdup("-i");
rec_argv[i++] = strdup(file_name);
for (j = 1; j < argc; j++, i++)
rec_argv[i] = argv[j];
BUG_ON(i != rec_argc);
return cmd_buildid_list(i, rec_argv, NULL);
}
int cmd_kvm(int argc, const char **argv, const char *prefix __used)
{
perf_host = perf_guest = 0;
argc = parse_options(argc, argv, kvm_options, kvm_usage,
PARSE_OPT_STOP_AT_NON_OPTION);
if (!argc)
usage_with_options(kvm_usage, kvm_options);
if (!perf_host)
perf_guest = 1;
if (!file_name) {
if (perf_host && !perf_guest)
sprintf(name_buffer, "perf.data.host");
else if (!perf_host && perf_guest)
sprintf(name_buffer, "perf.data.guest");
else
sprintf(name_buffer, "perf.data.kvm");
file_name = name_buffer;
}
if (!strncmp(argv[0], "rec", 3))
return __cmd_record(argc, argv);
else if (!strncmp(argv[0], "rep", 3))
return __cmd_report(argc, argv);
else if (!strncmp(argv[0], "diff", 4))
return cmd_diff(argc, argv, NULL);
else if (!strncmp(argv[0], "top", 3))
return cmd_top(argc, argv, NULL);
else if (!strncmp(argv[0], "buildid-list", 12))
return __cmd_buildid_list(argc, argv);
else
usage_with_options(kvm_usage, kvm_options);
return 0;
}

View File

@@ -456,6 +456,52 @@ static void atexit_header(void)
}
}
static void event__synthesize_guest_os(struct kernel_info *kerninfo,
void *data __attribute__((unused)))
{
int err;
char *guest_kallsyms;
char path[PATH_MAX];
if (is_host_kernel(kerninfo))
return;
/*
*As for guest kernel when processing subcommand record&report,
*we arrange module mmap prior to guest kernel mmap and trigger
*a preload dso because default guest module symbols are loaded
*from guest kallsyms instead of /lib/modules/XXX/XXX. This
*method is used to avoid symbol missing when the first addr is
*in module instead of in guest kernel.
*/
err = event__synthesize_modules(process_synthesized_event,
session,
kerninfo);
if (err < 0)
pr_err("Couldn't record guest kernel [%d]'s reference"
" relocation symbol.\n", kerninfo->pid);
if (is_default_guest(kerninfo))
guest_kallsyms = (char *) symbol_conf.default_guest_kallsyms;
else {
sprintf(path, "%s/proc/kallsyms", kerninfo->root_dir);
guest_kallsyms = path;
}
/*
* We use _stext for guest kernel because guest kernel's /proc/kallsyms
* have no _text sometimes.
*/
err = event__synthesize_kernel_mmap(process_synthesized_event,
session, kerninfo, "_text");
if (err < 0)
err = event__synthesize_kernel_mmap(process_synthesized_event,
session, kerninfo, "_stext");
if (err < 0)
pr_err("Couldn't record guest kernel [%d]'s reference"
" relocation symbol.\n", kerninfo->pid);
}
static int __cmd_record(int argc, const char **argv)
{
int i, counter;
@@ -467,6 +513,7 @@ static int __cmd_record(int argc, const char **argv)
int child_ready_pipe[2], go_pipe[2];
const bool forks = argc > 0;
char buf;
struct kernel_info *kerninfo;
page_size = sysconf(_SC_PAGE_SIZE);
@@ -635,21 +682,31 @@ static int __cmd_record(int argc, const char **argv)
advance_output(err);
}
kerninfo = kerninfo__findhost(&session->kerninfo_root);
if (!kerninfo) {
pr_err("Couldn't find native kernel information.\n");
return -1;
}
err = event__synthesize_kernel_mmap(process_synthesized_event,
session, "_text");
session, kerninfo, "_text");
if (err < 0)
err = event__synthesize_kernel_mmap(process_synthesized_event,
session, "_stext");
session, kerninfo, "_stext");
if (err < 0) {
pr_err("Couldn't record kernel reference relocation symbol.\n");
return err;
}
err = event__synthesize_modules(process_synthesized_event, session);
err = event__synthesize_modules(process_synthesized_event,
session, kerninfo);
if (err < 0) {
pr_err("Couldn't record kernel reference relocation symbol.\n");
return err;
}
if (perf_guest)
kerninfo__process_allkernels(&session->kerninfo_root,
event__synthesize_guest_os, session);
if (!system_wide && profile_cpu == -1)
event__synthesize_thread(target_tid, process_synthesized_event,

View File

@@ -108,7 +108,7 @@ static int perf_session__add_hist_entry(struct perf_session *self,
return -ENOMEM;
if (hit)
he->count += data->period;
__perf_session__add_count(he, al, data->period);
if (symbol_conf.use_callchain) {
if (!hit)
@@ -313,7 +313,7 @@ static int __cmd_report(void)
perf_session__fprintf(session, stdout);
if (verbose > 2)
dsos__fprintf(stdout);
dsos__fprintf(&session->kerninfo_root, stdout);
next = rb_first(&session->stats_by_id);
while (next) {
@@ -450,6 +450,8 @@ static const struct option options[] = {
"sort by key(s): pid, comm, dso, symbol, parent"),
OPT_BOOLEAN('P', "full-paths", &symbol_conf.full_paths,
"Don't shorten the pathnames taking into account the cwd"),
OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization,
"Show sample percentage for different cpu modes"),
OPT_STRING('p', "parent", &parent_pattern, "regex",
"regex filter to identify parent, see: '--sort parent'"),
OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other,

View File

@@ -420,8 +420,9 @@ static double sym_weight(const struct sym_entry *sym)
}
static long samples;
static long userspace_samples;
static long kernel_samples, us_samples;
static long exact_samples;
static long guest_us_samples, guest_kernel_samples;
static const char CONSOLE_CLEAR[] = "";
static void __list_insert_active_sym(struct sym_entry *syme)
@@ -461,7 +462,10 @@ static void print_sym_table(void)
int printed = 0, j;
int counter, snap = !display_weighted ? sym_counter : 0;
float samples_per_sec = samples/delay_secs;
float ksamples_per_sec = (samples-userspace_samples)/delay_secs;
float ksamples_per_sec = kernel_samples/delay_secs;
float us_samples_per_sec = (us_samples)/delay_secs;
float guest_kernel_samples_per_sec = (guest_kernel_samples)/delay_secs;
float guest_us_samples_per_sec = (guest_us_samples)/delay_secs;
float esamples_percent = (100.0*exact_samples)/samples;
float sum_ksamples = 0.0;
struct sym_entry *syme, *n;
@@ -470,7 +474,8 @@ static void print_sym_table(void)
int sym_width = 0, dso_width = 0, dso_short_width = 0;
const int win_width = winsize.ws_col - 1;
samples = userspace_samples = exact_samples = 0;
samples = us_samples = kernel_samples = exact_samples = 0;
guest_kernel_samples = guest_us_samples = 0;
/* Sort the active symbols */
pthread_mutex_lock(&active_symbols_lock);
@@ -501,10 +506,30 @@ static void print_sym_table(void)
puts(CONSOLE_CLEAR);
printf("%-*.*s\n", win_width, win_width, graph_dotted_line);
printf( " PerfTop:%8.0f irqs/sec kernel:%4.1f%% exact: %4.1f%% [",
samples_per_sec,
100.0 - (100.0*((samples_per_sec-ksamples_per_sec)/samples_per_sec)),
esamples_percent);
if (!perf_guest) {
printf(" PerfTop:%8.0f irqs/sec kernel:%4.1f%%"
" exact: %4.1f%% [",
samples_per_sec,
100.0 - (100.0 * ((samples_per_sec - ksamples_per_sec) /
samples_per_sec)),
esamples_percent);
} else {
printf(" PerfTop:%8.0f irqs/sec kernel:%4.1f%% us:%4.1f%%"
" guest kernel:%4.1f%% guest us:%4.1f%%"
" exact: %4.1f%% [",
samples_per_sec,
100.0 - (100.0 * ((samples_per_sec-ksamples_per_sec) /
samples_per_sec)),
100.0 - (100.0 * ((samples_per_sec-us_samples_per_sec) /
samples_per_sec)),
100.0 - (100.0 * ((samples_per_sec -
guest_kernel_samples_per_sec) /
samples_per_sec)),
100.0 - (100.0 * ((samples_per_sec -
guest_us_samples_per_sec) /
samples_per_sec)),
esamples_percent);
}
if (nr_counters == 1 || !display_weighted) {
printf("%Ld", (u64)attrs[0].sample_period);
@@ -597,7 +622,6 @@ static void print_sym_table(void)
syme = rb_entry(nd, struct sym_entry, rb_node);
sym = sym_entry__symbol(syme);
if (++printed > print_entries || (int)syme->snap_count < count_filter)
continue;
@@ -761,7 +785,7 @@ static int key_mapped(int c)
return 0;
}
static void handle_keypress(int c)
static void handle_keypress(struct perf_session *session, int c)
{
if (!key_mapped(c)) {
struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
@@ -830,7 +854,7 @@ static void handle_keypress(int c)
case 'Q':
printf("exiting.\n");
if (dump_symtab)
dsos__fprintf(stderr);
dsos__fprintf(&session->kerninfo_root, stderr);
exit(0);
case 's':
prompt_symbol(&sym_filter_entry, "Enter details symbol");
@@ -866,6 +890,7 @@ static void *display_thread(void *arg __used)
struct pollfd stdin_poll = { .fd = 0, .events = POLLIN };
struct termios tc, save;
int delay_msecs, c;
struct perf_session *session = (struct perf_session *) arg;
tcgetattr(0, &save);
tc = save;
@@ -886,7 +911,7 @@ repeat:
c = getc(stdin);
tcsetattr(0, TCSAFLUSH, &save);
handle_keypress(c);
handle_keypress(session, c);
goto repeat;
return NULL;
@@ -957,24 +982,46 @@ static void event__process_sample(const event_t *self,
u64 ip = self->ip.ip;
struct sym_entry *syme;
struct addr_location al;
struct kernel_info *kerninfo;
u8 origin = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
++samples;
switch (origin) {
case PERF_RECORD_MISC_USER:
++userspace_samples;
++us_samples;
if (hide_user_symbols)
return;
kerninfo = kerninfo__findhost(&session->kerninfo_root);
break;
case PERF_RECORD_MISC_KERNEL:
++kernel_samples;
if (hide_kernel_symbols)
return;
kerninfo = kerninfo__findhost(&session->kerninfo_root);
break;
case PERF_RECORD_MISC_GUEST_KERNEL:
++guest_kernel_samples;
kerninfo = kerninfo__find(&session->kerninfo_root,
self->ip.pid);
break;
case PERF_RECORD_MISC_GUEST_USER:
++guest_us_samples;
/*
* TODO: we don't process guest user from host side
* except simple counting.
*/
return;
default:
return;
}
if (!kerninfo && perf_guest) {
pr_err("Can't find guest [%d]'s kernel information\n",
self->ip.pid);
return;
}
if (self->header.misc & PERF_RECORD_MISC_EXACT)
exact_samples++;
@@ -994,7 +1041,7 @@ static void event__process_sample(const event_t *self,
* --hide-kernel-symbols, even if the user specifies an
* invalid --vmlinux ;-)
*/
if (al.map == session->vmlinux_maps[MAP__FUNCTION] &&
if (al.map == kerninfo->vmlinux_maps[MAP__FUNCTION] &&
RB_EMPTY_ROOT(&al.map->dso->symbols[MAP__FUNCTION])) {
pr_err("The %s file can't be used\n",
symbol_conf.vmlinux_name);
@@ -1261,7 +1308,7 @@ static int __cmd_top(void)
perf_session__mmap_read(session);
if (pthread_create(&thread, NULL, display_thread, NULL)) {
if (pthread_create(&thread, NULL, display_thread, session)) {
printf("Could not create display thread.\n");
exit(-1);
}

View File

@@ -32,5 +32,6 @@ extern int cmd_version(int argc, const char **argv, const char *prefix);
extern int cmd_probe(int argc, const char **argv, const char *prefix);
extern int cmd_kmem(int argc, const char **argv, const char *prefix);
extern int cmd_lock(int argc, const char **argv, const char *prefix);
extern int cmd_kvm(int argc, const char **argv, const char *prefix);
#endif

View File

@@ -19,3 +19,4 @@ perf-trace mainporcelain common
perf-probe mainporcelain common
perf-kmem mainporcelain common
perf-lock mainporcelain common
perf-kvm mainporcelain common

View File

@@ -307,6 +307,7 @@ static void handle_internal_command(int argc, const char **argv)
{ "probe", cmd_probe, 0 },
{ "kmem", cmd_kmem, 0 },
{ "lock", cmd_lock, 0 },
{ "kvm", cmd_kvm, 0 },
};
unsigned int i;
static const char ext[] = STRIP_EXTENSION;

View File

@@ -131,4 +131,6 @@ struct ip_callchain {
u64 ips[0];
};
extern int perf_host, perf_guest;
#endif

View File

@@ -24,7 +24,7 @@ static int build_id__mark_dso_hit(event_t *event, struct perf_session *session)
}
thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION,
event->ip.ip, &al);
event->ip.pid, event->ip.ip, &al);
if (al.map != NULL)
al.map->dso->hit = 1;

View File

@@ -112,7 +112,11 @@ static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
event_t ev = {
.header = {
.type = PERF_RECORD_MMAP,
.misc = 0, /* Just like the kernel, see kernel/perf_event.c __perf_event_mmap */
/*
* Just like the kernel, see __perf_event_mmap
* in kernel/perf_event.c
*/
.misc = PERF_RECORD_MISC_USER,
},
};
int n;
@@ -167,11 +171,23 @@ static int event__synthesize_mmap_events(pid_t pid, pid_t tgid,
}
int event__synthesize_modules(event__handler_t process,
struct perf_session *session)
struct perf_session *session,
struct kernel_info *kerninfo)
{
struct rb_node *nd;
struct map_groups *kmaps = &kerninfo->kmaps;
u16 misc;
for (nd = rb_first(&session->kmaps.maps[MAP__FUNCTION]);
/*
* kernel uses 0 for user space maps, see kernel/perf_event.c
* __perf_event_mmap
*/
if (is_host_kernel(kerninfo))
misc = PERF_RECORD_MISC_KERNEL;
else
misc = PERF_RECORD_MISC_GUEST_KERNEL;
for (nd = rb_first(&kmaps->maps[MAP__FUNCTION]);
nd; nd = rb_next(nd)) {
event_t ev;
size_t size;
@@ -182,12 +198,13 @@ int event__synthesize_modules(event__handler_t process,
size = ALIGN(pos->dso->long_name_len + 1, sizeof(u64));
memset(&ev, 0, sizeof(ev));
ev.mmap.header.misc = 1; /* kernel uses 0 for user space maps, see kernel/perf_event.c __perf_event_mmap */
ev.mmap.header.misc = misc;
ev.mmap.header.type = PERF_RECORD_MMAP;
ev.mmap.header.size = (sizeof(ev.mmap) -
(sizeof(ev.mmap.filename) - size));
ev.mmap.start = pos->start;
ev.mmap.len = pos->end - pos->start;
ev.mmap.pid = kerninfo->pid;
memcpy(ev.mmap.filename, pos->dso->long_name,
pos->dso->long_name_len + 1);
@@ -250,13 +267,18 @@ static int find_symbol_cb(void *arg, const char *name, char type, u64 start)
int event__synthesize_kernel_mmap(event__handler_t process,
struct perf_session *session,
struct kernel_info *kerninfo,
const char *symbol_name)
{
size_t size;
const char *filename, *mmap_name;
char path[PATH_MAX];
char name_buff[PATH_MAX];
struct map *map;
event_t ev = {
.header = {
.type = PERF_RECORD_MMAP,
.misc = 1, /* kernel uses 0 for user space maps, see kernel/perf_event.c __perf_event_mmap */
},
};
/*
@@ -266,16 +288,37 @@ int event__synthesize_kernel_mmap(event__handler_t process,
*/
struct process_symbol_args args = { .name = symbol_name, };
if (kallsyms__parse("/proc/kallsyms", &args, find_symbol_cb) <= 0)
mmap_name = kern_mmap_name(kerninfo, name_buff);
if (is_host_kernel(kerninfo)) {
/*
* kernel uses PERF_RECORD_MISC_USER for user space maps,
* see kernel/perf_event.c __perf_event_mmap
*/
ev.header.misc = PERF_RECORD_MISC_KERNEL;
filename = "/proc/kallsyms";
} else {
ev.header.misc = PERF_RECORD_MISC_GUEST_KERNEL;
if (is_default_guest(kerninfo))
filename = (char *) symbol_conf.default_guest_kallsyms;
else {
sprintf(path, "%s/proc/kallsyms", kerninfo->root_dir);
filename = path;
}
}
if (kallsyms__parse(filename, &args, find_symbol_cb) <= 0)
return -ENOENT;
map = kerninfo->vmlinux_maps[MAP__FUNCTION];
size = snprintf(ev.mmap.filename, sizeof(ev.mmap.filename),
"[kernel.kallsyms.%s]", symbol_name) + 1;
"%s%s", mmap_name, symbol_name) + 1;
size = ALIGN(size, sizeof(u64));
ev.mmap.header.size = (sizeof(ev.mmap) - (sizeof(ev.mmap.filename) - size));
ev.mmap.header.size = (sizeof(ev.mmap) -
(sizeof(ev.mmap.filename) - size));
ev.mmap.pgoff = args.start;
ev.mmap.start = session->vmlinux_maps[MAP__FUNCTION]->start;
ev.mmap.len = session->vmlinux_maps[MAP__FUNCTION]->end - ev.mmap.start ;
ev.mmap.start = map->start;
ev.mmap.len = map->end - ev.mmap.start;
ev.mmap.pid = kerninfo->pid;
return process(&ev, session);
}
@@ -329,22 +372,50 @@ int event__process_lost(event_t *self, struct perf_session *session)
return 0;
}
int event__process_mmap(event_t *self, struct perf_session *session)
static void event_set_kernel_mmap_len(struct map **maps, event_t *self)
{
maps[MAP__FUNCTION]->start = self->mmap.start;
maps[MAP__FUNCTION]->end = self->mmap.start + self->mmap.len;
/*
* Be a bit paranoid here, some perf.data file came with
* a zero sized synthesized MMAP event for the kernel.
*/
if (maps[MAP__FUNCTION]->end == 0)
maps[MAP__FUNCTION]->end = ~0UL;
}
static int event__process_kernel_mmap(event_t *self,
struct perf_session *session)
{
struct thread *thread;
struct map *map;
char kmmap_prefix[PATH_MAX];
struct kernel_info *kerninfo;
enum dso_kernel_type kernel_type;
bool is_kernel_mmap;
dump_printf(" %d/%d: [%#Lx(%#Lx) @ %#Lx]: %s\n",
self->mmap.pid, self->mmap.tid, self->mmap.start,
self->mmap.len, self->mmap.pgoff, self->mmap.filename);
kerninfo = kerninfo__findnew(&session->kerninfo_root, self->mmap.pid);
if (!kerninfo) {
pr_err("Can't find id %d's kerninfo\n", self->mmap.pid);
goto out_problem;
}
if (self->mmap.pid == 0) {
static const char kmmap_prefix[] = "[kernel.kallsyms.";
kern_mmap_name(kerninfo, kmmap_prefix);
if (is_host_kernel(kerninfo))
kernel_type = DSO_TYPE_KERNEL;
else
kernel_type = DSO_TYPE_GUEST_KERNEL;
is_kernel_mmap = memcmp(self->mmap.filename,
kmmap_prefix,
strlen(kmmap_prefix)) == 0;
if (self->mmap.filename[0] == '/' ||
(!is_kernel_mmap && self->mmap.filename[0] == '[')) {
char short_module_name[1024];
char *name, *dot;
if (self->mmap.filename[0] == '/') {
char short_module_name[1024];
char *name = strrchr(self->mmap.filename, '/'), *dot;
name = strrchr(self->mmap.filename, '/');
if (name == NULL)
goto out_problem;
@@ -352,59 +423,86 @@ int event__process_mmap(event_t *self, struct perf_session *session)
dot = strrchr(name, '.');
if (dot == NULL)
goto out_problem;
snprintf(short_module_name, sizeof(short_module_name),
"[%.*s]", (int)(dot - name), name);
"[%.*s]", (int)(dot - name), name);
strxfrchar(short_module_name, '-', '_');
} else
strcpy(short_module_name, self->mmap.filename);
map = perf_session__new_module_map(session,
self->mmap.start,
self->mmap.filename);
if (map == NULL)
goto out_problem;
map = map_groups__new_module(&kerninfo->kmaps,
self->mmap.start,
self->mmap.filename,
kerninfo);
if (map == NULL)
goto out_problem;
name = strdup(short_module_name);
if (name == NULL)
goto out_problem;
name = strdup(short_module_name);
if (name == NULL)
goto out_problem;
map->dso->short_name = name;
map->end = map->start + self->mmap.len;
} else if (memcmp(self->mmap.filename, kmmap_prefix,
sizeof(kmmap_prefix) - 1) == 0) {
const char *symbol_name = (self->mmap.filename +
sizeof(kmmap_prefix) - 1);
map->dso->short_name = name;
map->end = map->start + self->mmap.len;
} else if (is_kernel_mmap) {
const char *symbol_name = (self->mmap.filename +
strlen(kmmap_prefix));
/*
* Should be there already, from the build-id table in
* the header.
*/
struct dso *kernel = __dsos__findnew(&kerninfo->dsos__kernel,
kmmap_prefix);
if (kernel == NULL)
goto out_problem;
kernel->kernel = kernel_type;
if (__map_groups__create_kernel_maps(&kerninfo->kmaps,
kerninfo->vmlinux_maps, kernel) < 0)
goto out_problem;
event_set_kernel_mmap_len(kerninfo->vmlinux_maps, self);
perf_session__set_kallsyms_ref_reloc_sym(kerninfo->vmlinux_maps,
symbol_name,
self->mmap.pgoff);
if (is_default_guest(kerninfo)) {
/*
* Should be there already, from the build-id table in
* the header.
* preload dso of guest kernel and modules
*/
struct dso *kernel = __dsos__findnew(&dsos__kernel,
"[kernel.kallsyms]");
if (kernel == NULL)
goto out_problem;
kernel->kernel = 1;
if (__perf_session__create_kernel_maps(session, kernel) < 0)
goto out_problem;
session->vmlinux_maps[MAP__FUNCTION]->start = self->mmap.start;
session->vmlinux_maps[MAP__FUNCTION]->end = self->mmap.start + self->mmap.len;
/*
* Be a bit paranoid here, some perf.data file came with
* a zero sized synthesized MMAP event for the kernel.
*/
if (session->vmlinux_maps[MAP__FUNCTION]->end == 0)
session->vmlinux_maps[MAP__FUNCTION]->end = ~0UL;
perf_session__set_kallsyms_ref_reloc_sym(session, symbol_name,
self->mmap.pgoff);
dso__load(kernel,
kerninfo->vmlinux_maps[MAP__FUNCTION],
NULL);
}
}
return 0;
out_problem:
return -1;
}
int event__process_mmap(event_t *self, struct perf_session *session)
{
struct kernel_info *kerninfo;
struct thread *thread;
struct map *map;
u8 cpumode = self->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
int ret = 0;
dump_printf(" %d/%d: [%#Lx(%#Lx) @ %#Lx]: %s\n",
self->mmap.pid, self->mmap.tid, self->mmap.start,
self->mmap.len, self->mmap.pgoff, self->mmap.filename);
if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL ||
cpumode == PERF_RECORD_MISC_KERNEL) {
ret = event__process_kernel_mmap(self, session);
if (ret < 0)
goto out_problem;
return 0;
}
thread = perf_session__findnew(session, self->mmap.pid);
map = map__new(self->mmap.start, self->mmap.len, self->mmap.pgoff,
self->mmap.pid, self->mmap.filename, MAP__FUNCTION,
session->cwd, session->cwdlen);
kerninfo = kerninfo__findhost(&session->kerninfo_root);
map = map__new(&kerninfo->dsos__user, self->mmap.start,
self->mmap.len, self->mmap.pgoff,
self->mmap.pid, self->mmap.filename,
MAP__FUNCTION, session->cwd, session->cwdlen);
if (thread == NULL || map == NULL)
goto out_problem;
@@ -444,22 +542,52 @@ int event__process_task(event_t *self, struct perf_session *session)
void thread__find_addr_map(struct thread *self,
struct perf_session *session, u8 cpumode,
enum map_type type, u64 addr,
enum map_type type, pid_t pid, u64 addr,
struct addr_location *al)
{
struct map_groups *mg = &self->mg;
struct kernel_info *kerninfo = NULL;
al->thread = self;
al->addr = addr;
al->cpumode = cpumode;
al->filtered = false;
if (cpumode == PERF_RECORD_MISC_KERNEL) {
if (cpumode == PERF_RECORD_MISC_KERNEL && perf_host) {
al->level = 'k';
mg = &session->kmaps;
} else if (cpumode == PERF_RECORD_MISC_USER)
kerninfo = kerninfo__findhost(&session->kerninfo_root);
mg = &kerninfo->kmaps;
} else if (cpumode == PERF_RECORD_MISC_USER && perf_host) {
al->level = '.';
else {
al->level = 'H';
kerninfo = kerninfo__findhost(&session->kerninfo_root);
} else if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL && perf_guest) {
al->level = 'g';
kerninfo = kerninfo__find(&session->kerninfo_root, pid);
if (!kerninfo) {
al->map = NULL;
return;
}
mg = &kerninfo->kmaps;
} else {
/*
* 'u' means guest os user space.
* TODO: We don't support guest user space. Might support late.
*/
if (cpumode == PERF_RECORD_MISC_GUEST_USER && perf_guest)
al->level = 'u';
else
al->level = 'H';
al->map = NULL;
if ((cpumode == PERF_RECORD_MISC_GUEST_USER ||
cpumode == PERF_RECORD_MISC_GUEST_KERNEL) &&
!perf_guest)
al->filtered = true;
if ((cpumode == PERF_RECORD_MISC_USER ||
cpumode == PERF_RECORD_MISC_KERNEL) &&
!perf_host)
al->filtered = true;
return;
}
try_again:
@@ -474,8 +602,11 @@ try_again:
* "[vdso]" dso, but for now lets use the old trick of looking
* in the whole kernel symbol list.
*/
if ((long long)al->addr < 0 && mg != &session->kmaps) {
mg = &session->kmaps;
if ((long long)al->addr < 0 &&
cpumode == PERF_RECORD_MISC_KERNEL &&
kerninfo &&
mg != &kerninfo->kmaps) {
mg = &kerninfo->kmaps;
goto try_again;
}
} else
@@ -484,11 +615,11 @@ try_again:
void thread__find_addr_location(struct thread *self,
struct perf_session *session, u8 cpumode,
enum map_type type, u64 addr,
enum map_type type, pid_t pid, u64 addr,
struct addr_location *al,
symbol_filter_t filter)
{
thread__find_addr_map(self, session, cpumode, type, addr, al);
thread__find_addr_map(self, session, cpumode, type, pid, addr, al);
if (al->map != NULL)
al->sym = map__find_symbol(al->map, al->addr, filter);
else
@@ -524,7 +655,7 @@ int event__preprocess_sample(const event_t *self, struct perf_session *session,
dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION,
self->ip.ip, al);
self->ip.pid, self->ip.ip, al);
dump_printf(" ...... dso: %s\n",
al->map ? al->map->dso->long_name :
al->level == 'H' ? "[hypervisor]" : "<not found>");
@@ -554,7 +685,6 @@ int event__preprocess_sample(const event_t *self, struct perf_session *session,
!strlist__has_entry(symbol_conf.sym_list, al->sym->name))
goto out_filtered;
al->filtered = false;
return 0;
out_filtered:

View File

@@ -79,6 +79,7 @@ struct sample_data {
struct build_id_event {
struct perf_event_header header;
pid_t pid;
u8 build_id[ALIGN(BUILD_ID_SIZE, sizeof(u64))];
char filename[];
};
@@ -154,10 +155,13 @@ int event__synthesize_thread(pid_t pid, event__handler_t process,
void event__synthesize_threads(event__handler_t process,
struct perf_session *session);
int event__synthesize_kernel_mmap(event__handler_t process,
struct perf_session *session,
const char *symbol_name);
struct perf_session *session,
struct kernel_info *kerninfo,
const char *symbol_name);
int event__synthesize_modules(event__handler_t process,
struct perf_session *session);
struct perf_session *session,
struct kernel_info *kerninfo);
int event__process_comm(event_t *self, struct perf_session *session);
int event__process_lost(event_t *self, struct perf_session *session);

View File

@@ -190,7 +190,8 @@ static int write_padded(int fd, const void *bf, size_t count,
continue; \
else
static int __dsos__write_buildid_table(struct list_head *head, u16 misc, int fd)
static int __dsos__write_buildid_table(struct list_head *head, pid_t pid,
u16 misc, int fd)
{
struct dso *pos;
@@ -205,6 +206,7 @@ static int __dsos__write_buildid_table(struct list_head *head, u16 misc, int fd)
len = ALIGN(len, NAME_ALIGN);
memset(&b, 0, sizeof(b));
memcpy(&b.build_id, pos->build_id, sizeof(pos->build_id));
b.pid = pid;
b.header.misc = misc;
b.header.size = sizeof(b) + len;
err = do_write(fd, &b, sizeof(b));
@@ -219,13 +221,33 @@ static int __dsos__write_buildid_table(struct list_head *head, u16 misc, int fd)
return 0;
}
static int dsos__write_buildid_table(int fd)
static int dsos__write_buildid_table(struct perf_header *header, int fd)
{
int err = __dsos__write_buildid_table(&dsos__kernel,
PERF_RECORD_MISC_KERNEL, fd);
if (err == 0)
err = __dsos__write_buildid_table(&dsos__user,
PERF_RECORD_MISC_USER, fd);
struct perf_session *session = container_of(header,
struct perf_session, header);
struct rb_node *nd;
int err = 0;
u16 kmisc, umisc;
for (nd = rb_first(&session->kerninfo_root); nd; nd = rb_next(nd)) {
struct kernel_info *pos = rb_entry(nd, struct kernel_info,
rb_node);
if (is_host_kernel(pos)) {
kmisc = PERF_RECORD_MISC_KERNEL;
umisc = PERF_RECORD_MISC_USER;
} else {
kmisc = PERF_RECORD_MISC_GUEST_KERNEL;
umisc = PERF_RECORD_MISC_GUEST_USER;
}
err = __dsos__write_buildid_table(&pos->dsos__kernel, pos->pid,
kmisc, fd);
if (err == 0)
err = __dsos__write_buildid_table(&pos->dsos__user,
pos->pid, umisc, fd);
if (err)
break;
}
return err;
}
@@ -342,9 +364,12 @@ static int __dsos__cache_build_ids(struct list_head *head, const char *debugdir)
return err;
}
static int dsos__cache_build_ids(void)
static int dsos__cache_build_ids(struct perf_header *self)
{
int err_kernel, err_user;
struct perf_session *session = container_of(self,
struct perf_session, header);
struct rb_node *nd;
int ret = 0;
char debugdir[PATH_MAX];
snprintf(debugdir, sizeof(debugdir), "%s/%s", getenv("HOME"),
@@ -353,9 +378,30 @@ static int dsos__cache_build_ids(void)
if (mkdir(debugdir, 0755) != 0 && errno != EEXIST)
return -1;
err_kernel = __dsos__cache_build_ids(&dsos__kernel, debugdir);
err_user = __dsos__cache_build_ids(&dsos__user, debugdir);
return err_kernel || err_user ? -1 : 0;
for (nd = rb_first(&session->kerninfo_root); nd; nd = rb_next(nd)) {
struct kernel_info *pos = rb_entry(nd, struct kernel_info,
rb_node);
ret |= __dsos__cache_build_ids(&pos->dsos__kernel, debugdir);
ret |= __dsos__cache_build_ids(&pos->dsos__user, debugdir);
}
return ret ? -1 : 0;
}
static bool dsos__read_build_ids(struct perf_header *self, bool with_hits)
{
bool ret = false;
struct perf_session *session = container_of(self,
struct perf_session, header);
struct rb_node *nd;
for (nd = rb_first(&session->kerninfo_root); nd; nd = rb_next(nd)) {
struct kernel_info *pos = rb_entry(nd, struct kernel_info,
rb_node);
ret |= __dsos__read_build_ids(&pos->dsos__kernel, with_hits);
ret |= __dsos__read_build_ids(&pos->dsos__user, with_hits);
}
return ret;
}
static int perf_header__adds_write(struct perf_header *self, int fd)
@@ -366,7 +412,7 @@ static int perf_header__adds_write(struct perf_header *self, int fd)
u64 sec_start;
int idx = 0, err;
if (dsos__read_build_ids(true))
if (dsos__read_build_ids(self, true))
perf_header__set_feat(self, HEADER_BUILD_ID);
nr_sections = bitmap_weight(self->adds_features, HEADER_FEAT_BITS);
@@ -401,14 +447,14 @@ static int perf_header__adds_write(struct perf_header *self, int fd)
/* Write build-ids */
buildid_sec->offset = lseek(fd, 0, SEEK_CUR);
err = dsos__write_buildid_table(fd);
err = dsos__write_buildid_table(self, fd);
if (err < 0) {
pr_debug("failed to write buildid table\n");
goto out_free;
}
buildid_sec->size = lseek(fd, 0, SEEK_CUR) -
buildid_sec->offset;
dsos__cache_build_ids();
dsos__cache_build_ids(self);
}
lseek(fd, sec_start, SEEK_SET);
@@ -633,6 +679,85 @@ int perf_file_header__read(struct perf_file_header *self,
return 0;
}
static int __event_process_build_id(struct build_id_event *bev,
char *filename,
struct perf_session *session)
{
int err = -1;
struct list_head *head;
struct kernel_info *kerninfo;
u16 misc;
struct dso *dso;
enum dso_kernel_type dso_type;
kerninfo = kerninfo__findnew(&session->kerninfo_root, bev->pid);
if (!kerninfo)
goto out;
misc = bev->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
switch (misc) {
case PERF_RECORD_MISC_KERNEL:
dso_type = DSO_TYPE_KERNEL;
head = &kerninfo->dsos__kernel;
break;
case PERF_RECORD_MISC_GUEST_KERNEL:
dso_type = DSO_TYPE_GUEST_KERNEL;
head = &kerninfo->dsos__kernel;
break;
case PERF_RECORD_MISC_USER:
case PERF_RECORD_MISC_GUEST_USER:
dso_type = DSO_TYPE_USER;
head = &kerninfo->dsos__user;
break;
default:
goto out;
}
dso = __dsos__findnew(head, filename);
if (dso != NULL) {
dso__set_build_id(dso, &bev->build_id);
if (filename[0] == '[')
dso->kernel = dso_type;
}
err = 0;
out:
return err;
}
static int perf_header__read_build_ids(struct perf_header *self,
int input, u64 offset, u64 size)
{
struct perf_session *session = container_of(self,
struct perf_session, header);
struct build_id_event bev;
char filename[PATH_MAX];
u64 limit = offset + size;
int err = -1;
while (offset < limit) {
ssize_t len;
if (read(input, &bev, sizeof(bev)) != sizeof(bev))
goto out;
if (self->needs_swap)
perf_event_header__bswap(&bev.header);
len = bev.header.size - sizeof(bev);
if (read(input, filename, len) != len)
goto out;
__event_process_build_id(&bev, filename, session);
offset += bev.header.size;
}
err = 0;
out:
return err;
}
static int perf_file_section__process(struct perf_file_section *self,
struct perf_header *ph,
int feat, int fd)
@@ -989,6 +1114,7 @@ int event__process_tracing_data(event_t *self,
int event__synthesize_build_id(struct dso *pos, u16 misc,
event__handler_t process,
struct kernel_info *kerninfo,
struct perf_session *session)
{
event_t ev;
@@ -1005,6 +1131,7 @@ int event__synthesize_build_id(struct dso *pos, u16 misc,
memcpy(&ev.build_id.build_id, pos->build_id, sizeof(pos->build_id));
ev.build_id.header.type = PERF_RECORD_HEADER_BUILD_ID;
ev.build_id.header.misc = misc;
ev.build_id.pid = kerninfo->pid;
ev.build_id.header.size = sizeof(ev.build_id) + len;
memcpy(&ev.build_id.filename, pos->long_name, pos->long_name_len);
@@ -1015,6 +1142,7 @@ int event__synthesize_build_id(struct dso *pos, u16 misc,
static int __event_synthesize_build_ids(struct list_head *head, u16 misc,
event__handler_t process,
struct kernel_info *kerninfo,
struct perf_session *session)
{
struct dso *pos;
@@ -1024,7 +1152,8 @@ static int __event_synthesize_build_ids(struct list_head *head, u16 misc,
if (!pos->hit)
continue;
err = event__synthesize_build_id(pos, misc, process, session);
err = event__synthesize_build_id(pos, misc, process,
kerninfo, session);
if (err < 0)
return err;
}
@@ -1035,44 +1164,48 @@ static int __event_synthesize_build_ids(struct list_head *head, u16 misc,
int event__synthesize_build_ids(event__handler_t process,
struct perf_session *session)
{
int err;
int err = 0;
u16 kmisc, umisc;
struct kernel_info *pos;
struct rb_node *nd;
if (!dsos__read_build_ids(true))
if (!dsos__read_build_ids(&session->header, true))
return 0;
err = __event_synthesize_build_ids(&dsos__kernel,
PERF_RECORD_MISC_KERNEL,
process, session);
if (err == 0)
err = __event_synthesize_build_ids(&dsos__user,
PERF_RECORD_MISC_USER,
process, session);
for (nd = rb_first(&session->kerninfo_root); nd; nd = rb_next(nd)) {
pos = rb_entry(nd, struct kernel_info, rb_node);
if (is_host_kernel(pos)) {
kmisc = PERF_RECORD_MISC_KERNEL;
umisc = PERF_RECORD_MISC_USER;
} else {
kmisc = PERF_RECORD_MISC_GUEST_KERNEL;
umisc = PERF_RECORD_MISC_GUEST_USER;
}
err = __event_synthesize_build_ids(&pos->dsos__kernel,
kmisc, process, pos, session);
if (err == 0)
err = __event_synthesize_build_ids(&pos->dsos__user,
umisc, process, pos, session);
if (err)
break;
}
if (err < 0) {
pr_debug("failed to synthesize build ids\n");
return err;
}
dsos__cache_build_ids();
dsos__cache_build_ids(&session->header);
return 0;
}
int event__process_build_id(event_t *self,
struct perf_session *session __unused)
struct perf_session *session)
{
struct list_head *head = &dsos__user;
struct dso *dso;
if (self->build_id.header.misc & PERF_RECORD_MISC_KERNEL)
head = &dsos__kernel;
dso = __dsos__findnew(head, self->build_id.filename);
if (dso != NULL) {
dso__set_build_id(dso, &self->build_id.build_id);
if (head == &dsos__kernel && self->build_id.filename[0] == '[')
dso->kernel = 1;
}
__event_process_build_id(&self->build_id,
self->build_id.filename,
session);
return 0;
}

View File

@@ -120,6 +120,7 @@ int event__process_tracing_data(event_t *self,
int event__synthesize_build_id(struct dso *pos, u16 misc,
event__handler_t process,
struct kernel_info *kerninfo,
struct perf_session *session);
int event__synthesize_build_ids(event__handler_t process,
struct perf_session *session);

View File

@@ -8,6 +8,30 @@ struct callchain_param callchain_param = {
.min_percent = 0.5
};
void __perf_session__add_count(struct hist_entry *he,
struct addr_location *al,
u64 count)
{
he->count += count;
switch (al->cpumode) {
case PERF_RECORD_MISC_KERNEL:
he->count_sys += count;
break;
case PERF_RECORD_MISC_USER:
he->count_us += count;
break;
case PERF_RECORD_MISC_GUEST_KERNEL:
he->count_guest_sys += count;
break;
case PERF_RECORD_MISC_GUEST_USER:
he->count_guest_us += count;
break;
default:
break;
}
}
/*
* histogram, sorted on item, collects counts
*/
@@ -464,7 +488,7 @@ int hist_entry__snprintf(struct hist_entry *self,
u64 session_total)
{
struct sort_entry *se;
u64 count, total;
u64 count, total, count_sys, count_us, count_guest_sys, count_guest_us;
const char *sep = symbol_conf.field_sep;
int ret;
@@ -474,9 +498,17 @@ int hist_entry__snprintf(struct hist_entry *self,
if (pair_session) {
count = self->pair ? self->pair->count : 0;
total = pair_session->events_stats.total;
count_sys = self->pair ? self->pair->count_sys : 0;
count_us = self->pair ? self->pair->count_us : 0;
count_guest_sys = self->pair ? self->pair->count_guest_sys : 0;
count_guest_us = self->pair ? self->pair->count_guest_us : 0;
} else {
count = self->count;
total = session_total;
count_sys = self->count_sys;
count_us = self->count_us;
count_guest_sys = self->count_guest_sys;
count_guest_us = self->count_guest_us;
}
if (total) {
@@ -487,6 +519,26 @@ int hist_entry__snprintf(struct hist_entry *self,
else
ret = snprintf(s, size, sep ? "%.2f" : " %6.2f%%",
(count * 100.0) / total);
if (symbol_conf.show_cpu_utilization) {
ret += percent_color_snprintf(s + ret, size - ret,
sep ? "%.2f" : " %6.2f%%",
(count_sys * 100.0) / total);
ret += percent_color_snprintf(s + ret, size - ret,
sep ? "%.2f" : " %6.2f%%",
(count_us * 100.0) / total);
if (perf_guest) {
ret += percent_color_snprintf(s + ret,
size - ret,
sep ? "%.2f" : " %6.2f%%",
(count_guest_sys * 100.0) /
total);
ret += percent_color_snprintf(s + ret,
size - ret,
sep ? "%.2f" : " %6.2f%%",
(count_guest_us * 100.0) /
total);
}
}
} else
ret = snprintf(s, size, sep ? "%lld" : "%12lld ", count);
@@ -597,6 +649,24 @@ size_t perf_session__fprintf_hists(struct rb_root *hists,
fputs(" Samples ", fp);
}
if (symbol_conf.show_cpu_utilization) {
if (sep) {
ret += fprintf(fp, "%csys", *sep);
ret += fprintf(fp, "%cus", *sep);
if (perf_guest) {
ret += fprintf(fp, "%cguest sys", *sep);
ret += fprintf(fp, "%cguest us", *sep);
}
} else {
ret += fprintf(fp, " sys ");
ret += fprintf(fp, " us ");
if (perf_guest) {
ret += fprintf(fp, " guest sys ");
ret += fprintf(fp, " guest us ");
}
}
}
if (pair) {
if (sep)
ret += fprintf(fp, "%cDelta", *sep);

Some files were not shown because too many files have changed in this diff Show More