Commit f60f3593 authored by Arun Sharma's avatar Arun Sharma Committed by Arnaldo Carvalho de Melo

perf report: Implement --sort cpu

In a shared multi-core environment, users want to analyze why their
program was slow. In particular, if the code ran slower only on certain
CPUs due to interference from other programs or kernel threads, the user
should be able to notice that.

Sample usage:

perf record -f -a -- sleep 3
perf report --sort cpu,comm

Workload:

program is running on 16 CPUs
Experiencing interference from an antagonist only on 4 CPUs.

  Samples: 106218177676 cycles

  Overhead  CPU          Command
  ........  ...  ...............

     6.25%  2            program
     6.24%  6            program
     6.24%  11           program
     6.24%  5            program
     6.24%  9            program
     6.24%  10           program
     6.23%  15           program
     6.23%  7            program
     6.23%  3            program
     6.23%  14           program
     6.22%  1            program
     6.20%  13           program
     3.17%  12           program
     3.15%  8            program
     3.14%  0            program
     3.13%  4            program
     3.11%  4         antagonist
     3.11%  0         antagonist
     3.10%  8         antagonist
     3.07%  12        antagonist

Cc: David S. Miller <davem@davemloft.net>
Cc: Frédéric Weisbecker <fweisbec@gmail.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Tom Zanussi <tzanussi@gmail.com>
LKML-Reference: <20100505181612.GA5091@sharma-home.net>
Signed-off-by: default avatarArun Sharma <aruns@google.com>
Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 41a37e20
...@@ -274,6 +274,9 @@ static void create_counter(int counter, int cpu) ...@@ -274,6 +274,9 @@ static void create_counter(int counter, int cpu)
if (call_graph) if (call_graph)
attr->sample_type |= PERF_SAMPLE_CALLCHAIN; attr->sample_type |= PERF_SAMPLE_CALLCHAIN;
if (system_wide)
attr->sample_type |= PERF_SAMPLE_CPU;
if (raw_samples) { if (raw_samples) {
attr->sample_type |= PERF_SAMPLE_TIME; attr->sample_type |= PERF_SAMPLE_TIME;
attr->sample_type |= PERF_SAMPLE_RAW; attr->sample_type |= PERF_SAMPLE_RAW;
......
...@@ -710,6 +710,7 @@ int event__preprocess_sample(const event_t *self, struct perf_session *session, ...@@ -710,6 +710,7 @@ int event__preprocess_sample(const event_t *self, struct perf_session *session,
al->map ? al->map->dso->long_name : al->map ? al->map->dso->long_name :
al->level == 'H' ? "[hypervisor]" : "<not found>"); al->level == 'H' ? "[hypervisor]" : "<not found>");
al->sym = NULL; al->sym = NULL;
al->cpu = data->cpu;
if (al->map) { if (al->map) {
if (symbol_conf.dso_list && if (symbol_conf.dso_list &&
......
...@@ -70,6 +70,7 @@ struct hist_entry *__hists__add_entry(struct hists *self, ...@@ -70,6 +70,7 @@ struct hist_entry *__hists__add_entry(struct hists *self,
.map = al->map, .map = al->map,
.sym = al->sym, .sym = al->sym,
}, },
.cpu = al->cpu,
.ip = al->addr, .ip = al->addr,
.level = al->level, .level = al->level,
.period = period, .period = period,
......
...@@ -13,6 +13,7 @@ enum sort_type sort__first_dimension; ...@@ -13,6 +13,7 @@ enum sort_type sort__first_dimension;
unsigned int dsos__col_width; unsigned int dsos__col_width;
unsigned int comms__col_width; unsigned int comms__col_width;
unsigned int threads__col_width; unsigned int threads__col_width;
unsigned int cpus__col_width;
static unsigned int parent_symbol__col_width; static unsigned int parent_symbol__col_width;
char * field_sep; char * field_sep;
...@@ -28,6 +29,8 @@ static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf, ...@@ -28,6 +29,8 @@ static int hist_entry__sym_snprintf(struct hist_entry *self, char *bf,
size_t size, unsigned int width); size_t size, unsigned int width);
static int hist_entry__parent_snprintf(struct hist_entry *self, char *bf, static int hist_entry__parent_snprintf(struct hist_entry *self, char *bf,
size_t size, unsigned int width); size_t size, unsigned int width);
static int hist_entry__cpu_snprintf(struct hist_entry *self, char *bf,
size_t size, unsigned int width);
struct sort_entry sort_thread = { struct sort_entry sort_thread = {
.se_header = "Command: Pid", .se_header = "Command: Pid",
...@@ -63,6 +66,13 @@ struct sort_entry sort_parent = { ...@@ -63,6 +66,13 @@ struct sort_entry sort_parent = {
.se_snprintf = hist_entry__parent_snprintf, .se_snprintf = hist_entry__parent_snprintf,
.se_width = &parent_symbol__col_width, .se_width = &parent_symbol__col_width,
}; };
struct sort_entry sort_cpu = {
.se_header = "CPU",
.se_cmp = sort__cpu_cmp,
.se_snprintf = hist_entry__cpu_snprintf,
.se_width = &cpus__col_width,
};
struct sort_dimension { struct sort_dimension {
const char *name; const char *name;
...@@ -76,6 +86,7 @@ static struct sort_dimension sort_dimensions[] = { ...@@ -76,6 +86,7 @@ static struct sort_dimension sort_dimensions[] = {
{ .name = "dso", .entry = &sort_dso, }, { .name = "dso", .entry = &sort_dso, },
{ .name = "symbol", .entry = &sort_sym, }, { .name = "symbol", .entry = &sort_sym, },
{ .name = "parent", .entry = &sort_parent, }, { .name = "parent", .entry = &sort_parent, },
{ .name = "cpu", .entry = &sort_cpu, },
}; };
int64_t cmp_null(void *l, void *r) int64_t cmp_null(void *l, void *r)
...@@ -242,6 +253,20 @@ static int hist_entry__parent_snprintf(struct hist_entry *self, char *bf, ...@@ -242,6 +253,20 @@ static int hist_entry__parent_snprintf(struct hist_entry *self, char *bf,
self->parent ? self->parent->name : "[other]"); self->parent ? self->parent->name : "[other]");
} }
/* --sort cpu */
int64_t
sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right)
{
return right->cpu - left->cpu;
}
static int hist_entry__cpu_snprintf(struct hist_entry *self, char *bf,
size_t size, unsigned int width)
{
return repsep_snprintf(bf, size, "%-*d", width, self->cpu);
}
int sort_dimension__add(const char *tok) int sort_dimension__add(const char *tok)
{ {
unsigned int i; unsigned int i;
...@@ -281,6 +306,8 @@ int sort_dimension__add(const char *tok) ...@@ -281,6 +306,8 @@ int sort_dimension__add(const char *tok)
sort__first_dimension = SORT_SYM; sort__first_dimension = SORT_SYM;
else if (!strcmp(sd->name, "parent")) else if (!strcmp(sd->name, "parent"))
sort__first_dimension = SORT_PARENT; sort__first_dimension = SORT_PARENT;
else if (!strcmp(sd->name, "cpu"))
sort__first_dimension = SORT_CPU;
} }
list_add_tail(&sd->entry->list, &hist_entry__sort_list); list_add_tail(&sd->entry->list, &hist_entry__sort_list);
......
...@@ -39,6 +39,7 @@ extern struct sort_entry sort_parent; ...@@ -39,6 +39,7 @@ extern struct sort_entry sort_parent;
extern unsigned int dsos__col_width; extern unsigned int dsos__col_width;
extern unsigned int comms__col_width; extern unsigned int comms__col_width;
extern unsigned int threads__col_width; extern unsigned int threads__col_width;
extern unsigned int cpus__col_width;
extern enum sort_type sort__first_dimension; extern enum sort_type sort__first_dimension;
struct hist_entry { struct hist_entry {
...@@ -51,6 +52,7 @@ struct hist_entry { ...@@ -51,6 +52,7 @@ struct hist_entry {
struct map_symbol ms; struct map_symbol ms;
struct thread *thread; struct thread *thread;
u64 ip; u64 ip;
s32 cpu;
u32 nr_events; u32 nr_events;
char level; char level;
u8 filtered; u8 filtered;
...@@ -68,7 +70,8 @@ enum sort_type { ...@@ -68,7 +70,8 @@ enum sort_type {
SORT_COMM, SORT_COMM,
SORT_DSO, SORT_DSO,
SORT_SYM, SORT_SYM,
SORT_PARENT SORT_PARENT,
SORT_CPU,
}; };
/* /*
...@@ -104,6 +107,7 @@ extern int64_t sort__comm_collapse(struct hist_entry *, struct hist_entry *); ...@@ -104,6 +107,7 @@ extern int64_t sort__comm_collapse(struct hist_entry *, struct hist_entry *);
extern int64_t sort__dso_cmp(struct hist_entry *, struct hist_entry *); extern int64_t sort__dso_cmp(struct hist_entry *, struct hist_entry *);
extern int64_t sort__sym_cmp(struct hist_entry *, struct hist_entry *); extern int64_t sort__sym_cmp(struct hist_entry *, struct hist_entry *);
extern int64_t sort__parent_cmp(struct hist_entry *, struct hist_entry *); extern int64_t sort__parent_cmp(struct hist_entry *, struct hist_entry *);
int64_t sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right);
extern size_t sort__parent_print(FILE *, struct hist_entry *, unsigned int); extern size_t sort__parent_print(FILE *, struct hist_entry *, unsigned int);
extern int sort_dimension__add(const char *); extern int sort_dimension__add(const char *);
void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list, void sort_entry__setup_elide(struct sort_entry *self, struct strlist *list,
......
...@@ -110,7 +110,8 @@ struct addr_location { ...@@ -110,7 +110,8 @@ struct addr_location {
u64 addr; u64 addr;
char level; char level;
bool filtered; bool filtered;
unsigned int cpumode; u8 cpumode;
s32 cpu;
}; };
enum dso_kernel_type { enum dso_kernel_type {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment