Merge branch 'perf/core' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux-2.6 into perf/core
This commit is contained in:
commit
e4cc9f4a20
|
@ -8,7 +8,7 @@ perf-list - List all symbolic event types
|
|||
SYNOPSIS
|
||||
--------
|
||||
[verse]
|
||||
'perf list'
|
||||
'perf list' [hw|sw|cache|tracepoint|event_glob]
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
|
@ -63,7 +63,26 @@ details. Some of them are referenced in the SEE ALSO section below.
|
|||
|
||||
OPTIONS
|
||||
-------
|
||||
None
|
||||
|
||||
Without options all known events will be listed.
|
||||
|
||||
To limit the list use:
|
||||
|
||||
. 'hw' or 'hardware' to list hardware events such as cache-misses, etc.
|
||||
|
||||
. 'sw' or 'software' to list software events such as context switches, etc.
|
||||
|
||||
. 'cache' or 'hwcache' to list hardware cache events such as L1-dcache-loads, etc.
|
||||
|
||||
. 'tracepoint' to list all tracepoint events, alternatively use
|
||||
'subsys_glob:event_glob' to filter by tracepoint subsystems such as sched,
|
||||
block, etc.
|
||||
|
||||
. If none of the above is matched, it will apply the supplied glob to all
|
||||
events, printing the ones that match.
|
||||
|
||||
One or more types can be used at the same time, listing the events for the
|
||||
types specified.
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
*
|
||||
* Copyright (C) 2009, Thomas Gleixner <tglx@linutronix.de>
|
||||
* Copyright (C) 2008-2009, Red Hat Inc, Ingo Molnar <mingo@redhat.com>
|
||||
* Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
|
||||
*/
|
||||
#include "builtin.h"
|
||||
|
||||
|
@ -13,9 +14,47 @@
|
|||
#include "util/parse-events.h"
|
||||
#include "util/cache.h"
|
||||
|
||||
int cmd_list(int argc __used, const char **argv __used, const char *prefix __used)
|
||||
int cmd_list(int argc, const char **argv, const char *prefix __used)
|
||||
{
|
||||
setup_pager();
|
||||
print_events();
|
||||
|
||||
if (argc == 1)
|
||||
print_events(NULL);
|
||||
else {
|
||||
int i;
|
||||
|
||||
for (i = 1; i < argc; ++i) {
|
||||
if (i > 1)
|
||||
putchar('\n');
|
||||
if (strncmp(argv[i], "tracepoint", 10) == 0)
|
||||
print_tracepoint_events(NULL, NULL);
|
||||
else if (strcmp(argv[i], "hw") == 0 ||
|
||||
strcmp(argv[i], "hardware") == 0)
|
||||
print_events_type(PERF_TYPE_HARDWARE);
|
||||
else if (strcmp(argv[i], "sw") == 0 ||
|
||||
strcmp(argv[i], "software") == 0)
|
||||
print_events_type(PERF_TYPE_SOFTWARE);
|
||||
else if (strcmp(argv[i], "cache") == 0 ||
|
||||
strcmp(argv[i], "hwcache") == 0)
|
||||
print_hwcache_events(NULL);
|
||||
else {
|
||||
char *sep = strchr(argv[i], ':'), *s;
|
||||
int sep_idx;
|
||||
|
||||
if (sep == NULL) {
|
||||
print_events(argv[i]);
|
||||
continue;
|
||||
}
|
||||
sep_idx = sep - argv[i];
|
||||
s = strdup(argv[i]);
|
||||
if (s == NULL)
|
||||
return -1;
|
||||
|
||||
s[sep_idx] = '\0';
|
||||
print_tracepoint_events(s, s + sep_idx + 1);
|
||||
free(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -538,11 +538,6 @@ static int __cmd_record(int argc, const char **argv)
|
|||
if (have_tracepoints(&evsel_list->entries))
|
||||
perf_header__set_feat(&session->header, HEADER_TRACE_INFO);
|
||||
|
||||
/*
|
||||
* perf_session__delete(session) will be called at atexit_header()
|
||||
*/
|
||||
atexit(atexit_header);
|
||||
|
||||
if (forks) {
|
||||
child_pid = fork();
|
||||
if (child_pid < 0) {
|
||||
|
@ -601,6 +596,11 @@ static int __cmd_record(int argc, const char **argv)
|
|||
|
||||
perf_session__set_sample_type(session, sample_type);
|
||||
|
||||
/*
|
||||
* perf_session__delete(session) will be called at atexit_header()
|
||||
*/
|
||||
atexit(atexit_header);
|
||||
|
||||
if (pipe_output) {
|
||||
err = perf_header__write_pipe(output);
|
||||
if (err < 0)
|
||||
|
|
|
@ -350,6 +350,12 @@ static int __cmd_report(void)
|
|||
perf_session__fprintf_dsos(session, stdout);
|
||||
|
||||
next = rb_first(&session->hists_tree);
|
||||
|
||||
if (next == NULL) {
|
||||
ui__warning("The %s file has no samples!\n", input_name);
|
||||
goto out_delete;
|
||||
}
|
||||
|
||||
while (next) {
|
||||
struct hists *hists;
|
||||
|
||||
|
|
|
@ -86,6 +86,7 @@ void perf_evsel__delete(struct perf_evsel *evsel)
|
|||
{
|
||||
perf_evsel__exit(evsel);
|
||||
close_cgroup(evsel->cgrp);
|
||||
free(evsel->name);
|
||||
free(evsel);
|
||||
}
|
||||
|
||||
|
|
|
@ -37,6 +37,12 @@ struct perf_sample_id {
|
|||
struct perf_evsel *evsel;
|
||||
};
|
||||
|
||||
/** struct perf_evsel - event selector
|
||||
*
|
||||
* @name - Can be set to retain the original event name passed by the user,
|
||||
* so that when showing results in tools such as 'perf stat', we
|
||||
* show the name used, not some alias.
|
||||
*/
|
||||
struct perf_evsel {
|
||||
struct list_head node;
|
||||
struct perf_event_attr attr;
|
||||
|
@ -45,6 +51,7 @@ struct perf_evsel {
|
|||
struct xyarray *id;
|
||||
struct perf_counts *counts;
|
||||
int idx;
|
||||
char *name;
|
||||
void *priv;
|
||||
struct cgroup_sel *cgrp;
|
||||
};
|
||||
|
|
|
@ -591,6 +591,7 @@ int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size,
|
|||
{
|
||||
struct sort_entry *se;
|
||||
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;
|
||||
|
||||
|
@ -599,6 +600,7 @@ int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size,
|
|||
|
||||
if (pair_hists) {
|
||||
period = self->pair ? self->pair->period : 0;
|
||||
nr_events = self->pair ? self->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;
|
||||
|
@ -606,6 +608,7 @@ int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size,
|
|||
period_guest_us = self->pair ? self->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;
|
||||
|
@ -646,9 +649,9 @@ int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size,
|
|||
|
||||
if (symbol_conf.show_nr_samples) {
|
||||
if (sep)
|
||||
ret += snprintf(s + ret, size - ret, "%c%" PRIu64, *sep, period);
|
||||
ret += snprintf(s + ret, size - ret, "%c%" PRIu64, *sep, nr_events);
|
||||
else
|
||||
ret += snprintf(s + ret, size - ret, "%11" PRIu64, period);
|
||||
ret += snprintf(s + ret, size - ret, "%11" PRIu64, nr_events);
|
||||
}
|
||||
|
||||
if (pair_hists) {
|
||||
|
|
|
@ -268,6 +268,9 @@ const char *event_name(struct perf_evsel *evsel)
|
|||
u64 config = evsel->attr.config;
|
||||
int type = evsel->attr.type;
|
||||
|
||||
if (evsel->name)
|
||||
return evsel->name;
|
||||
|
||||
return __event_name(type, config);
|
||||
}
|
||||
|
||||
|
@ -782,8 +785,10 @@ int parse_events(const struct option *opt, const char *str, int unset __used)
|
|||
struct perf_evlist *evlist = *(struct perf_evlist **)opt->value;
|
||||
struct perf_event_attr attr;
|
||||
enum event_result ret;
|
||||
const char *ostr;
|
||||
|
||||
for (;;) {
|
||||
ostr = str;
|
||||
memset(&attr, 0, sizeof(attr));
|
||||
ret = parse_event_symbols(opt, &str, &attr);
|
||||
if (ret == EVT_FAILED)
|
||||
|
@ -798,6 +803,11 @@ int parse_events(const struct option *opt, const char *str, int unset __used)
|
|||
if (evsel == NULL)
|
||||
return -1;
|
||||
perf_evlist__add(evlist, evsel);
|
||||
|
||||
evsel->name = calloc(str - ostr + 1, 1);
|
||||
if (!evsel->name)
|
||||
return -1;
|
||||
strncpy(evsel->name, ostr, str - ostr);
|
||||
}
|
||||
|
||||
if (*str == 0)
|
||||
|
@ -848,7 +858,7 @@ static const char * const event_type_descriptors[] = {
|
|||
* Print the events from <debugfs_mount_point>/tracing/events
|
||||
*/
|
||||
|
||||
static void print_tracepoint_events(void)
|
||||
void print_tracepoint_events(const char *subsys_glob, const char *event_glob)
|
||||
{
|
||||
DIR *sys_dir, *evt_dir;
|
||||
struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent;
|
||||
|
@ -863,6 +873,9 @@ static void print_tracepoint_events(void)
|
|||
return;
|
||||
|
||||
for_each_subsystem(sys_dir, sys_dirent, sys_next) {
|
||||
if (subsys_glob != NULL &&
|
||||
!strglobmatch(sys_dirent.d_name, subsys_glob))
|
||||
continue;
|
||||
|
||||
snprintf(dir_path, MAXPATHLEN, "%s/%s", debugfs_path,
|
||||
sys_dirent.d_name);
|
||||
|
@ -871,6 +884,10 @@ static void print_tracepoint_events(void)
|
|||
continue;
|
||||
|
||||
for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) {
|
||||
if (event_glob != NULL &&
|
||||
!strglobmatch(evt_dirent.d_name, event_glob))
|
||||
continue;
|
||||
|
||||
snprintf(evt_path, MAXPATHLEN, "%s:%s",
|
||||
sys_dirent.d_name, evt_dirent.d_name);
|
||||
printf(" %-42s [%s]\n", evt_path,
|
||||
|
@ -922,13 +939,61 @@ int is_valid_tracepoint(const char *event_string)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void print_events_type(u8 type)
|
||||
{
|
||||
struct event_symbol *syms = event_symbols;
|
||||
unsigned int i;
|
||||
char name[64];
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) {
|
||||
if (type != syms->type)
|
||||
continue;
|
||||
|
||||
if (strlen(syms->alias))
|
||||
snprintf(name, sizeof(name), "%s OR %s",
|
||||
syms->symbol, syms->alias);
|
||||
else
|
||||
snprintf(name, sizeof(name), "%s", syms->symbol);
|
||||
|
||||
printf(" %-42s [%s]\n", name,
|
||||
event_type_descriptors[type]);
|
||||
}
|
||||
}
|
||||
|
||||
int print_hwcache_events(const char *event_glob)
|
||||
{
|
||||
unsigned int type, op, i, printed = 0;
|
||||
|
||||
for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) {
|
||||
for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) {
|
||||
/* skip invalid cache type */
|
||||
if (!is_cache_op_valid(type, op))
|
||||
continue;
|
||||
|
||||
for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) {
|
||||
char *name = event_cache_name(type, op, i);
|
||||
|
||||
if (event_glob != NULL &&
|
||||
!strglobmatch(name, event_glob))
|
||||
continue;
|
||||
|
||||
printf(" %-42s [%s]\n", name,
|
||||
event_type_descriptors[PERF_TYPE_HW_CACHE]);
|
||||
++printed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return printed;
|
||||
}
|
||||
|
||||
/*
|
||||
* Print the help text for the event symbols:
|
||||
*/
|
||||
void print_events(void)
|
||||
void print_events(const char *event_glob)
|
||||
{
|
||||
struct event_symbol *syms = event_symbols;
|
||||
unsigned int i, type, op, prev_type = -1;
|
||||
unsigned int i, type, prev_type = -1, printed = 0, ntypes_printed = 0;
|
||||
char name[40];
|
||||
|
||||
printf("\n");
|
||||
|
@ -937,8 +1002,16 @@ void print_events(void)
|
|||
for (i = 0; i < ARRAY_SIZE(event_symbols); i++, syms++) {
|
||||
type = syms->type;
|
||||
|
||||
if (type != prev_type)
|
||||
if (type != prev_type && printed) {
|
||||
printf("\n");
|
||||
printed = 0;
|
||||
ntypes_printed++;
|
||||
}
|
||||
|
||||
if (event_glob != NULL &&
|
||||
!(strglobmatch(syms->symbol, event_glob) ||
|
||||
(syms->alias && strglobmatch(syms->alias, event_glob))))
|
||||
continue;
|
||||
|
||||
if (strlen(syms->alias))
|
||||
sprintf(name, "%s OR %s", syms->symbol, syms->alias);
|
||||
|
@ -948,22 +1021,17 @@ void print_events(void)
|
|||
event_type_descriptors[type]);
|
||||
|
||||
prev_type = type;
|
||||
++printed;
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
for (type = 0; type < PERF_COUNT_HW_CACHE_MAX; type++) {
|
||||
for (op = 0; op < PERF_COUNT_HW_CACHE_OP_MAX; op++) {
|
||||
/* skip invalid cache type */
|
||||
if (!is_cache_op_valid(type, op))
|
||||
continue;
|
||||
|
||||
for (i = 0; i < PERF_COUNT_HW_CACHE_RESULT_MAX; i++) {
|
||||
printf(" %-42s [%s]\n",
|
||||
event_cache_name(type, op, i),
|
||||
event_type_descriptors[PERF_TYPE_HW_CACHE]);
|
||||
}
|
||||
}
|
||||
if (ntypes_printed) {
|
||||
printed = 0;
|
||||
printf("\n");
|
||||
}
|
||||
print_hwcache_events(event_glob);
|
||||
|
||||
if (event_glob != NULL)
|
||||
return;
|
||||
|
||||
printf("\n");
|
||||
printf(" %-42s [%s]\n",
|
||||
|
@ -976,7 +1044,7 @@ void print_events(void)
|
|||
event_type_descriptors[PERF_TYPE_BREAKPOINT]);
|
||||
printf("\n");
|
||||
|
||||
print_tracepoint_events();
|
||||
print_tracepoint_events(NULL, NULL);
|
||||
|
||||
exit(129);
|
||||
}
|
||||
|
|
|
@ -28,7 +28,10 @@ extern int parse_filter(const struct option *opt, const char *str, int unset);
|
|||
|
||||
#define EVENTS_HELP_MAX (128*1024)
|
||||
|
||||
extern void print_events(void);
|
||||
void print_events(const char *event_glob);
|
||||
void print_events_type(u8 type);
|
||||
void print_tracepoint_events(const char *subsys_glob, const char *event_glob);
|
||||
int print_hwcache_events(const char *event_glob);
|
||||
extern int is_valid_tracepoint(const char *event_string);
|
||||
|
||||
extern char debugfs_path[];
|
||||
|
|
|
@ -5,7 +5,7 @@ from distutils.core import setup, Extension
|
|||
perf = Extension('perf',
|
||||
sources = ['util/python.c', 'util/ctype.c', 'util/evlist.c',
|
||||
'util/evsel.c', 'util/cpumap.c', 'util/thread_map.c',
|
||||
'util/util.c', 'util/xyarray.c'],
|
||||
'util/util.c', 'util/xyarray.c', 'util/cgroup.c'],
|
||||
include_dirs = ['util/include'],
|
||||
extra_compile_args = ['-fno-strict-aliasing', '-Wno-write-strings'])
|
||||
|
||||
|
|
Loading…
Reference in New Issue