Merge branch 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
* 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (39 commits) perf tools: Fix compile error on x86_64 Ubuntu perf report: Fix --stdio output alignment when --showcpuutilization used perf annotate: Get rid of field_sep check perf annotate: Fix usage string perf kmem: Fix a memory leak perf kmem: Add missing closedir() calls perf top: Add error message for EMFILE perf test: Change type of '-v' option to INCR perf script: Add missing closedir() calls tracing: Fix compile error when static ftrace is enabled recordmcount: Fix handling of elf64 big-endian objects. perf tools: Add const.h to MANIFEST to make perf-tar-src-pkg work again perf tools: Add support for guest/host-only profiling perf kvm: Do guest-only counting by default perf top: Don't update total_period on process_sample perf hists: Stop using 'self' for struct hist_entry perf hists: Rename total_session to total_period x86: Add counter when debug stack is used with interrupts enabled x86: Allow NMIs to hit breakpoints in i386 x86: Keep current stack in NMI breakpoints ...
This commit is contained in:
@@ -21,6 +21,8 @@ EVENT MODIFIERS
|
||||
Events can optionally have a modifer by appending a colon and one or
|
||||
more modifiers. Modifiers allow the user to restrict when events are
|
||||
counted with 'u' for user-space, 'k' for kernel, 'h' for hypervisor.
|
||||
Additional modifiers are 'G' for guest counting (in KVM guests) and 'H'
|
||||
for host counting (not in KVM guests).
|
||||
|
||||
The 'p' modifier can be used for specifying how precise the instruction
|
||||
address should be. The 'p' modifier is currently only implemented for
|
||||
|
@@ -1,4 +1,5 @@
|
||||
tools/perf
|
||||
include/linux/const.h
|
||||
include/linux/perf_event.h
|
||||
include/linux/rbtree.h
|
||||
include/linux/list.h
|
||||
|
@@ -235,7 +235,7 @@ out_delete:
|
||||
}
|
||||
|
||||
static const char * const annotate_usage[] = {
|
||||
"perf annotate [<options>] <command>",
|
||||
"perf annotate [<options>]",
|
||||
NULL
|
||||
};
|
||||
|
||||
@@ -313,10 +313,5 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __used)
|
||||
annotate.sym_hist_filter = argv[0];
|
||||
}
|
||||
|
||||
if (field_sep && *field_sep == '.') {
|
||||
pr_err("'.' is the only non valid --field-separator argument\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return __cmd_annotate(&annotate);
|
||||
}
|
||||
|
@@ -108,7 +108,9 @@ static void setup_cpunode_map(void)
|
||||
continue;
|
||||
cpunode_map[cpu] = mem;
|
||||
}
|
||||
closedir(dir2);
|
||||
}
|
||||
closedir(dir1);
|
||||
}
|
||||
|
||||
static void insert_alloc_stat(unsigned long call_site, unsigned long ptr,
|
||||
@@ -645,6 +647,7 @@ static int setup_sorting(struct list_head *sort_list, const char *arg)
|
||||
break;
|
||||
if (sort_dimension__add(tok, sort_list) < 0) {
|
||||
error("Unknown --sort key: '%s'", tok);
|
||||
free(str);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
@@ -22,9 +22,6 @@
|
||||
static const char *file_name;
|
||||
static char name_buffer[256];
|
||||
|
||||
bool perf_host = 1;
|
||||
bool perf_guest;
|
||||
|
||||
static const char * const kvm_usage[] = {
|
||||
"perf kvm [<options>] {top|record|report|diff|buildid-list}",
|
||||
NULL
|
||||
@@ -107,7 +104,8 @@ static int __cmd_buildid_list(int argc, const char **argv)
|
||||
|
||||
int cmd_kvm(int argc, const char **argv, const char *prefix __used)
|
||||
{
|
||||
perf_host = perf_guest = 0;
|
||||
perf_host = 0;
|
||||
perf_guest = 1;
|
||||
|
||||
argc = parse_options(argc, argv, kvm_options, kvm_usage,
|
||||
PARSE_OPT_STOP_AT_NON_OPTION);
|
||||
|
@@ -1018,13 +1018,17 @@ static char *get_script_path(const char *script_root, const char *suffix)
|
||||
__script_root = get_script_root(&script_dirent, suffix);
|
||||
if (__script_root && !strcmp(script_root, __script_root)) {
|
||||
free(__script_root);
|
||||
closedir(lang_dir);
|
||||
closedir(scripts_dir);
|
||||
snprintf(script_path, MAXPATHLEN, "%s/%s",
|
||||
lang_path, script_dirent.d_name);
|
||||
return strdup(script_path);
|
||||
}
|
||||
free(__script_root);
|
||||
}
|
||||
closedir(lang_dir);
|
||||
}
|
||||
closedir(scripts_dir);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
@@ -1396,7 +1396,7 @@ int cmd_test(int argc, const char **argv, const char *prefix __used)
|
||||
NULL,
|
||||
};
|
||||
const struct option test_options[] = {
|
||||
OPT_INTEGER('v', "verbose", &verbose,
|
||||
OPT_INCR('v', "verbose", &verbose,
|
||||
"be more verbose (show symbol address, etc)"),
|
||||
OPT_END()
|
||||
};
|
||||
|
@@ -235,7 +235,6 @@ static struct hist_entry *perf_evsel__add_hist_entry(struct perf_evsel *evsel,
|
||||
if (he == NULL)
|
||||
return NULL;
|
||||
|
||||
evsel->hists.stats.total_period += sample->period;
|
||||
hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
|
||||
return he;
|
||||
}
|
||||
@@ -889,6 +888,10 @@ try_again:
|
||||
ui__warning("The %s event is not supported.\n",
|
||||
event_name(counter));
|
||||
goto out_err;
|
||||
} else if (err == EMFILE) {
|
||||
ui__warning("Too many events are opened.\n"
|
||||
"Try again after reducing the number of events\n");
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
ui__warning("The sys_perf_event_open() syscall "
|
||||
|
@@ -111,8 +111,11 @@ int perf_evlist__add_default(struct perf_evlist *evlist)
|
||||
.type = PERF_TYPE_HARDWARE,
|
||||
.config = PERF_COUNT_HW_CPU_CYCLES,
|
||||
};
|
||||
struct perf_evsel *evsel = perf_evsel__new(&attr, 0);
|
||||
struct perf_evsel *evsel;
|
||||
|
||||
event_attr_init(&attr);
|
||||
|
||||
evsel = perf_evsel__new(&attr, 0);
|
||||
if (evsel == NULL)
|
||||
goto error;
|
||||
|
||||
|
@@ -76,21 +76,21 @@ static void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
|
||||
}
|
||||
}
|
||||
|
||||
static void hist_entry__add_cpumode_period(struct hist_entry *self,
|
||||
static void hist_entry__add_cpumode_period(struct hist_entry *he,
|
||||
unsigned int cpumode, u64 period)
|
||||
{
|
||||
switch (cpumode) {
|
||||
case PERF_RECORD_MISC_KERNEL:
|
||||
self->period_sys += period;
|
||||
he->period_sys += period;
|
||||
break;
|
||||
case PERF_RECORD_MISC_USER:
|
||||
self->period_us += period;
|
||||
he->period_us += period;
|
||||
break;
|
||||
case PERF_RECORD_MISC_GUEST_KERNEL:
|
||||
self->period_guest_sys += period;
|
||||
he->period_guest_sys += period;
|
||||
break;
|
||||
case PERF_RECORD_MISC_GUEST_USER:
|
||||
self->period_guest_us += period;
|
||||
he->period_guest_us += period;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -165,18 +165,18 @@ void hists__decay_entries_threaded(struct hists *hists,
|
||||
static struct hist_entry *hist_entry__new(struct hist_entry *template)
|
||||
{
|
||||
size_t callchain_size = symbol_conf.use_callchain ? sizeof(struct callchain_root) : 0;
|
||||
struct hist_entry *self = malloc(sizeof(*self) + callchain_size);
|
||||
struct hist_entry *he = malloc(sizeof(*he) + callchain_size);
|
||||
|
||||
if (self != NULL) {
|
||||
*self = *template;
|
||||
self->nr_events = 1;
|
||||
if (self->ms.map)
|
||||
self->ms.map->referenced = true;
|
||||
if (he != NULL) {
|
||||
*he = *template;
|
||||
he->nr_events = 1;
|
||||
if (he->ms.map)
|
||||
he->ms.map->referenced = true;
|
||||
if (symbol_conf.use_callchain)
|
||||
callchain_init(self->callchain);
|
||||
callchain_init(he->callchain);
|
||||
}
|
||||
|
||||
return self;
|
||||
return he;
|
||||
}
|
||||
|
||||
static void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h)
|
||||
@@ -677,15 +677,16 @@ static size_t callchain__fprintf_flat(FILE *fp, struct callchain_node *self,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static size_t hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
|
||||
u64 total_samples, int left_margin)
|
||||
static size_t hist_entry_callchain__fprintf(struct hist_entry *he,
|
||||
u64 total_samples, int left_margin,
|
||||
FILE *fp)
|
||||
{
|
||||
struct rb_node *rb_node;
|
||||
struct callchain_node *chain;
|
||||
size_t ret = 0;
|
||||
u32 entries_printed = 0;
|
||||
|
||||
rb_node = rb_first(&self->sorted_chain);
|
||||
rb_node = rb_first(&he->sorted_chain);
|
||||
while (rb_node) {
|
||||
double percent;
|
||||
|
||||
@@ -730,35 +731,35 @@ void hists__output_recalc_col_len(struct hists *hists, int max_rows)
|
||||
}
|
||||
}
|
||||
|
||||
static int hist_entry__pcnt_snprintf(struct hist_entry *self, char *s,
|
||||
static int hist_entry__pcnt_snprintf(struct hist_entry *he, char *s,
|
||||
size_t size, struct hists *pair_hists,
|
||||
bool show_displacement, long displacement,
|
||||
bool color, u64 session_total)
|
||||
bool color, u64 total_period)
|
||||
{
|
||||
u64 period, total, period_sys, period_us, period_guest_sys, period_guest_us;
|
||||
u64 nr_events;
|
||||
const char *sep = symbol_conf.field_sep;
|
||||
int ret;
|
||||
|
||||
if (symbol_conf.exclude_other && !self->parent)
|
||||
if (symbol_conf.exclude_other && !he->parent)
|
||||
return 0;
|
||||
|
||||
if (pair_hists) {
|
||||
period = self->pair ? self->pair->period : 0;
|
||||
nr_events = self->pair ? self->pair->nr_events : 0;
|
||||
period = he->pair ? he->pair->period : 0;
|
||||
nr_events = he->pair ? he->pair->nr_events : 0;
|
||||
total = pair_hists->stats.total_period;
|
||||
period_sys = self->pair ? self->pair->period_sys : 0;
|
||||
period_us = self->pair ? self->pair->period_us : 0;
|
||||
period_guest_sys = self->pair ? self->pair->period_guest_sys : 0;
|
||||
period_guest_us = self->pair ? self->pair->period_guest_us : 0;
|
||||
period_sys = he->pair ? he->pair->period_sys : 0;
|
||||
period_us = he->pair ? he->pair->period_us : 0;
|
||||
period_guest_sys = he->pair ? he->pair->period_guest_sys : 0;
|
||||
period_guest_us = he->pair ? he->pair->period_guest_us : 0;
|
||||
} else {
|
||||
period = self->period;
|
||||
nr_events = self->nr_events;
|
||||
total = session_total;
|
||||
period_sys = self->period_sys;
|
||||
period_us = self->period_us;
|
||||
period_guest_sys = self->period_guest_sys;
|
||||
period_guest_us = self->period_guest_us;
|
||||
period = he->period;
|
||||
nr_events = he->nr_events;
|
||||
total = total_period;
|
||||
period_sys = he->period_sys;
|
||||
period_us = he->period_us;
|
||||
period_guest_sys = he->period_guest_sys;
|
||||
period_guest_us = he->period_guest_us;
|
||||
}
|
||||
|
||||
if (total) {
|
||||
@@ -812,8 +813,8 @@ static int hist_entry__pcnt_snprintf(struct hist_entry *self, char *s,
|
||||
|
||||
if (total > 0)
|
||||
old_percent = (period * 100.0) / total;
|
||||
if (session_total > 0)
|
||||
new_percent = (self->period * 100.0) / session_total;
|
||||
if (total_period > 0)
|
||||
new_percent = (he->period * 100.0) / total_period;
|
||||
|
||||
diff = new_percent - old_percent;
|
||||
|
||||
@@ -862,9 +863,10 @@ int hist_entry__snprintf(struct hist_entry *he, char *s, size_t size,
|
||||
return ret;
|
||||
}
|
||||
|
||||
int hist_entry__fprintf(struct hist_entry *he, size_t size, struct hists *hists,
|
||||
struct hists *pair_hists, bool show_displacement,
|
||||
long displacement, FILE *fp, u64 session_total)
|
||||
static int hist_entry__fprintf(struct hist_entry *he, size_t size,
|
||||
struct hists *hists, struct hists *pair_hists,
|
||||
bool show_displacement, long displacement,
|
||||
u64 total_period, FILE *fp)
|
||||
{
|
||||
char bf[512];
|
||||
int ret;
|
||||
@@ -874,14 +876,14 @@ int hist_entry__fprintf(struct hist_entry *he, size_t size, struct hists *hists,
|
||||
|
||||
ret = hist_entry__pcnt_snprintf(he, bf, size, pair_hists,
|
||||
show_displacement, displacement,
|
||||
true, session_total);
|
||||
true, total_period);
|
||||
hist_entry__snprintf(he, bf + ret, size - ret, hists);
|
||||
return fprintf(fp, "%s\n", bf);
|
||||
}
|
||||
|
||||
static size_t hist_entry__fprintf_callchain(struct hist_entry *self,
|
||||
struct hists *hists, FILE *fp,
|
||||
u64 session_total)
|
||||
static size_t hist_entry__fprintf_callchain(struct hist_entry *he,
|
||||
struct hists *hists,
|
||||
u64 total_period, FILE *fp)
|
||||
{
|
||||
int left_margin = 0;
|
||||
|
||||
@@ -889,11 +891,10 @@ static size_t hist_entry__fprintf_callchain(struct hist_entry *self,
|
||||
struct sort_entry *se = list_first_entry(&hist_entry__sort_list,
|
||||
typeof(*se), list);
|
||||
left_margin = hists__col_len(hists, se->se_width_idx);
|
||||
left_margin -= thread__comm_len(self->thread);
|
||||
left_margin -= thread__comm_len(he->thread);
|
||||
}
|
||||
|
||||
return hist_entry_callchain__fprintf(fp, self, session_total,
|
||||
left_margin);
|
||||
return hist_entry_callchain__fprintf(he, total_period, left_margin, fp);
|
||||
}
|
||||
|
||||
size_t hists__fprintf(struct hists *hists, struct hists *pair,
|
||||
@@ -903,6 +904,7 @@ size_t hists__fprintf(struct hists *hists, struct hists *pair,
|
||||
struct sort_entry *se;
|
||||
struct rb_node *nd;
|
||||
size_t ret = 0;
|
||||
u64 total_period;
|
||||
unsigned long position = 1;
|
||||
long displacement = 0;
|
||||
unsigned int width;
|
||||
@@ -917,6 +919,24 @@ size_t hists__fprintf(struct hists *hists, struct hists *pair,
|
||||
|
||||
fprintf(fp, "# %s", pair ? "Baseline" : "Overhead");
|
||||
|
||||
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 (symbol_conf.show_nr_samples) {
|
||||
if (sep)
|
||||
fprintf(fp, "%cSamples", *sep);
|
||||
@@ -931,24 +951,6 @@ size_t hists__fprintf(struct hists *hists, struct hists *pair,
|
||||
ret += fprintf(fp, " Period ");
|
||||
}
|
||||
|
||||
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);
|
||||
@@ -993,6 +995,8 @@ size_t hists__fprintf(struct hists *hists, struct hists *pair,
|
||||
goto print_entries;
|
||||
|
||||
fprintf(fp, "# ........");
|
||||
if (symbol_conf.show_cpu_utilization)
|
||||
fprintf(fp, " ....... .......");
|
||||
if (symbol_conf.show_nr_samples)
|
||||
fprintf(fp, " ..........");
|
||||
if (symbol_conf.show_total_period)
|
||||
@@ -1025,6 +1029,8 @@ size_t hists__fprintf(struct hists *hists, struct hists *pair,
|
||||
goto out;
|
||||
|
||||
print_entries:
|
||||
total_period = hists->stats.total_period;
|
||||
|
||||
for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
|
||||
struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
|
||||
|
||||
@@ -1040,11 +1046,10 @@ print_entries:
|
||||
++position;
|
||||
}
|
||||
ret += hist_entry__fprintf(h, max_cols, hists, pair, show_displacement,
|
||||
displacement, fp, hists->stats.total_period);
|
||||
displacement, total_period, fp);
|
||||
|
||||
if (symbol_conf.use_callchain)
|
||||
ret += hist_entry__fprintf_callchain(h, hists, fp,
|
||||
hists->stats.total_period);
|
||||
ret += hist_entry__fprintf_callchain(h, hists, total_period, fp);
|
||||
if (max_rows && ++nr_rows >= max_rows)
|
||||
goto out;
|
||||
|
||||
|
@@ -66,11 +66,8 @@ struct hists {
|
||||
struct hist_entry *__hists__add_entry(struct hists *self,
|
||||
struct addr_location *al,
|
||||
struct symbol *parent, u64 period);
|
||||
extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *);
|
||||
extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *);
|
||||
int hist_entry__fprintf(struct hist_entry *he, size_t size, struct hists *hists,
|
||||
struct hists *pair_hists, bool show_displacement,
|
||||
long displacement, FILE *fp, u64 session_total);
|
||||
int64_t hist_entry__cmp(struct hist_entry *left, struct hist_entry *right);
|
||||
int64_t hist_entry__collapse(struct hist_entry *left, struct hist_entry *right);
|
||||
int hist_entry__snprintf(struct hist_entry *self, char *bf, size_t size,
|
||||
struct hists *hists);
|
||||
void hist_entry__free(struct hist_entry *);
|
||||
|
@@ -735,8 +735,8 @@ static int
|
||||
parse_event_modifier(const char **strp, struct perf_event_attr *attr)
|
||||
{
|
||||
const char *str = *strp;
|
||||
int exclude = 0;
|
||||
int eu = 0, ek = 0, eh = 0, precise = 0;
|
||||
int exclude = 0, exclude_GH = 0;
|
||||
int eu = 0, ek = 0, eh = 0, eH = 0, eG = 0, precise = 0;
|
||||
|
||||
if (!*str)
|
||||
return 0;
|
||||
@@ -760,6 +760,14 @@ parse_event_modifier(const char **strp, struct perf_event_attr *attr)
|
||||
if (!exclude)
|
||||
exclude = eu = ek = eh = 1;
|
||||
eh = 0;
|
||||
} else if (*str == 'G') {
|
||||
if (!exclude_GH)
|
||||
exclude_GH = eG = eH = 1;
|
||||
eG = 0;
|
||||
} else if (*str == 'H') {
|
||||
if (!exclude_GH)
|
||||
exclude_GH = eG = eH = 1;
|
||||
eH = 0;
|
||||
} else if (*str == 'p') {
|
||||
precise++;
|
||||
} else
|
||||
@@ -776,6 +784,8 @@ parse_event_modifier(const char **strp, struct perf_event_attr *attr)
|
||||
attr->exclude_kernel = ek;
|
||||
attr->exclude_hv = eh;
|
||||
attr->precise_ip = precise;
|
||||
attr->exclude_host = eH;
|
||||
attr->exclude_guest = eG;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -838,6 +848,7 @@ int parse_events(struct perf_evlist *evlist , const char *str, int unset __used)
|
||||
for (;;) {
|
||||
ostr = str;
|
||||
memset(&attr, 0, sizeof(attr));
|
||||
event_attr_init(&attr);
|
||||
ret = parse_event_symbols(evlist, &str, &attr);
|
||||
if (ret == EVT_FAILED)
|
||||
return -1;
|
||||
|
@@ -18,7 +18,6 @@
|
||||
*
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
*/
|
||||
#include <ctype.h>
|
||||
#include "util.h"
|
||||
#include <dirent.h>
|
||||
#include <mntent.h>
|
||||
|
@@ -1,6 +1,21 @@
|
||||
#include "../perf.h"
|
||||
#include "util.h"
|
||||
#include <sys/mman.h>
|
||||
|
||||
/*
|
||||
* XXX We need to find a better place for these things...
|
||||
*/
|
||||
bool perf_host = true;
|
||||
bool perf_guest = true;
|
||||
|
||||
void event_attr_init(struct perf_event_attr *attr)
|
||||
{
|
||||
if (!perf_host)
|
||||
attr->exclude_host = 1;
|
||||
if (!perf_guest)
|
||||
attr->exclude_guest = 1;
|
||||
}
|
||||
|
||||
int mkdir_p(char *path, mode_t mode)
|
||||
{
|
||||
struct stat st;
|
||||
|
@@ -242,6 +242,10 @@ int strtailcmp(const char *s1, const char *s2);
|
||||
unsigned long convert_unit(unsigned long value, char *unit);
|
||||
int readn(int fd, void *buf, size_t size);
|
||||
|
||||
struct perf_event_attr;
|
||||
|
||||
void event_attr_init(struct perf_event_attr *attr);
|
||||
|
||||
#define _STR(x) #x
|
||||
#define STR(x) _STR(x)
|
||||
|
||||
|
Reference in New Issue
Block a user