aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util
diff options
context:
space:
mode:
authorAndi Kleen <ak@linux.intel.com>2013-01-24 10:10:29 -0500
committerArnaldo Carvalho de Melo <acme@redhat.com>2013-04-01 11:19:43 -0400
commit05484298cbfebbf8c8c55b000541a245bc286bec (patch)
tree1b1336957d96defc9e637faf14aebacb5b9b693a /tools/perf/util
parent2fe85427e3bf65d791700d065132772fc26e4d75 (diff)
perf tools: Add support for weight v7 (modified)
perf record has a new option -W that enables weightened sampling. Add sorting support in top/report for the average weight per sample and the total weight sum. This allows to both compare relative cost per event and the total cost over the measurement period. Add the necessary glue to perf report, record and the library. v2: Merge with new hist refactoring. v3: Fix manpage. Remove value check. Rename global_weight to weight and weight to local_weight. v4: Readd sort keys to manpage v5: Move weight to end v6: Move weight to template v7: Rename weight key. Original patch from Andi modified by Stephane Eranian <eranian@google.com> to include ONLY the weight supporting code and apply to pristine 3.8.0-rc4. Signed-off-by: Andi Kleen <ak@linux.intel.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Jiri Olsa <jolsa@redhat.com> Cc: Namhyung Kim <namhyung.kim@lge.com> Cc: Peter Zijlstra <peterz@infradead.org> Link: http://lkml.kernel.org/r/1359040242-8269-6-git-send-email-eranian@google.com [ committer note: changed to cope with fc5871ed and the hists_link perf test entry ] Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf/util')
-rw-r--r--tools/perf/util/event.h1
-rw-r--r--tools/perf/util/evsel.c10
-rw-r--r--tools/perf/util/hist.c23
-rw-r--r--tools/perf/util/hist.h8
-rw-r--r--tools/perf/util/session.c3
-rw-r--r--tools/perf/util/sort.c45
-rw-r--r--tools/perf/util/sort.h3
7 files changed, 84 insertions, 9 deletions
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 0d573ff4771a..a97fbbe6b3b3 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -88,6 +88,7 @@ struct perf_sample {
88 u64 id; 88 u64 id;
89 u64 stream_id; 89 u64 stream_id;
90 u64 period; 90 u64 period;
91 u64 weight;
91 u32 cpu; 92 u32 cpu;
92 u32 raw_size; 93 u32 raw_size;
93 void *raw_data; 94 void *raw_data;
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 1adb824610f0..23061a6ccd77 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -563,6 +563,9 @@ void perf_evsel__config(struct perf_evsel *evsel,
563 attr->branch_sample_type = opts->branch_stack; 563 attr->branch_sample_type = opts->branch_stack;
564 } 564 }
565 565
566 if (opts->sample_weight)
567 attr->sample_type |= PERF_SAMPLE_WEIGHT;
568
566 attr->mmap = track; 569 attr->mmap = track;
567 attr->comm = track; 570 attr->comm = track;
568 571
@@ -1017,6 +1020,7 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
1017 data->cpu = data->pid = data->tid = -1; 1020 data->cpu = data->pid = data->tid = -1;
1018 data->stream_id = data->id = data->time = -1ULL; 1021 data->stream_id = data->id = data->time = -1ULL;
1019 data->period = 1; 1022 data->period = 1;
1023 data->weight = 0;
1020 1024
1021 if (event->header.type != PERF_RECORD_SAMPLE) { 1025 if (event->header.type != PERF_RECORD_SAMPLE) {
1022 if (!evsel->attr.sample_id_all) 1026 if (!evsel->attr.sample_id_all)
@@ -1167,6 +1171,12 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
1167 } 1171 }
1168 } 1172 }
1169 1173
1174 data->weight = 0;
1175 if (type & PERF_SAMPLE_WEIGHT) {
1176 data->weight = *array;
1177 array++;
1178 }
1179
1170 return 0; 1180 return 0;
1171} 1181}
1172 1182
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index f855941bebea..97ddd18acd7c 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -155,9 +155,11 @@ static void hist_entry__add_cpumode_period(struct hist_entry *he,
155 } 155 }
156} 156}
157 157
158static void he_stat__add_period(struct he_stat *he_stat, u64 period) 158static void he_stat__add_period(struct he_stat *he_stat, u64 period,
159 u64 weight)
159{ 160{
160 he_stat->period += period; 161 he_stat->period += period;
162 he_stat->weight += weight;
161 he_stat->nr_events += 1; 163 he_stat->nr_events += 1;
162} 164}
163 165
@@ -169,12 +171,14 @@ static void he_stat__add_stat(struct he_stat *dest, struct he_stat *src)
169 dest->period_guest_sys += src->period_guest_sys; 171 dest->period_guest_sys += src->period_guest_sys;
170 dest->period_guest_us += src->period_guest_us; 172 dest->period_guest_us += src->period_guest_us;
171 dest->nr_events += src->nr_events; 173 dest->nr_events += src->nr_events;
174 dest->weight += src->weight;
172} 175}
173 176
174static void hist_entry__decay(struct hist_entry *he) 177static void hist_entry__decay(struct hist_entry *he)
175{ 178{
176 he->stat.period = (he->stat.period * 7) / 8; 179 he->stat.period = (he->stat.period * 7) / 8;
177 he->stat.nr_events = (he->stat.nr_events * 7) / 8; 180 he->stat.nr_events = (he->stat.nr_events * 7) / 8;
181 /* XXX need decay for weight too? */
178} 182}
179 183
180static bool hists__decay_entry(struct hists *hists, struct hist_entry *he) 184static bool hists__decay_entry(struct hists *hists, struct hist_entry *he)
@@ -282,7 +286,8 @@ static u8 symbol__parent_filter(const struct symbol *parent)
282static struct hist_entry *add_hist_entry(struct hists *hists, 286static struct hist_entry *add_hist_entry(struct hists *hists,
283 struct hist_entry *entry, 287 struct hist_entry *entry,
284 struct addr_location *al, 288 struct addr_location *al,
285 u64 period) 289 u64 period,
290 u64 weight)
286{ 291{
287 struct rb_node **p; 292 struct rb_node **p;
288 struct rb_node *parent = NULL; 293 struct rb_node *parent = NULL;
@@ -306,7 +311,7 @@ static struct hist_entry *add_hist_entry(struct hists *hists,
306 cmp = hist_entry__cmp(he, entry); 311 cmp = hist_entry__cmp(he, entry);
307 312
308 if (!cmp) { 313 if (!cmp) {
309 he_stat__add_period(&he->stat, period); 314 he_stat__add_period(&he->stat, period, weight);
310 315
311 /* If the map of an existing hist_entry has 316 /* If the map of an existing hist_entry has
312 * become out-of-date due to an exec() or 317 * become out-of-date due to an exec() or
@@ -345,7 +350,8 @@ struct hist_entry *__hists__add_branch_entry(struct hists *self,
345 struct addr_location *al, 350 struct addr_location *al,
346 struct symbol *sym_parent, 351 struct symbol *sym_parent,
347 struct branch_info *bi, 352 struct branch_info *bi,
348 u64 period) 353 u64 period,
354 u64 weight)
349{ 355{
350 struct hist_entry entry = { 356 struct hist_entry entry = {
351 .thread = al->thread, 357 .thread = al->thread,
@@ -359,6 +365,7 @@ struct hist_entry *__hists__add_branch_entry(struct hists *self,
359 .stat = { 365 .stat = {
360 .period = period, 366 .period = period,
361 .nr_events = 1, 367 .nr_events = 1,
368 .weight = weight,
362 }, 369 },
363 .parent = sym_parent, 370 .parent = sym_parent,
364 .filtered = symbol__parent_filter(sym_parent), 371 .filtered = symbol__parent_filter(sym_parent),
@@ -366,12 +373,13 @@ struct hist_entry *__hists__add_branch_entry(struct hists *self,
366 .hists = self, 373 .hists = self,
367 }; 374 };
368 375
369 return add_hist_entry(self, &entry, al, period); 376 return add_hist_entry(self, &entry, al, period, weight);
370} 377}
371 378
372struct hist_entry *__hists__add_entry(struct hists *self, 379struct hist_entry *__hists__add_entry(struct hists *self,
373 struct addr_location *al, 380 struct addr_location *al,
374 struct symbol *sym_parent, u64 period) 381 struct symbol *sym_parent, u64 period,
382 u64 weight)
375{ 383{
376 struct hist_entry entry = { 384 struct hist_entry entry = {
377 .thread = al->thread, 385 .thread = al->thread,
@@ -385,13 +393,14 @@ struct hist_entry *__hists__add_entry(struct hists *self,
385 .stat = { 393 .stat = {
386 .period = period, 394 .period = period,
387 .nr_events = 1, 395 .nr_events = 1,
396 .weight = weight,
388 }, 397 },
389 .parent = sym_parent, 398 .parent = sym_parent,
390 .filtered = symbol__parent_filter(sym_parent), 399 .filtered = symbol__parent_filter(sym_parent),
391 .hists = self, 400 .hists = self,
392 }; 401 };
393 402
394 return add_hist_entry(self, &entry, al, period); 403 return add_hist_entry(self, &entry, al, period, weight);
395} 404}
396 405
397int64_t 406int64_t
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 848331377bdb..121cc14b6041 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -49,6 +49,8 @@ enum hist_column {
49 HISTC_DSO_FROM, 49 HISTC_DSO_FROM,
50 HISTC_DSO_TO, 50 HISTC_DSO_TO,
51 HISTC_SRCLINE, 51 HISTC_SRCLINE,
52 HISTC_LOCAL_WEIGHT,
53 HISTC_GLOBAL_WEIGHT,
52 HISTC_NR_COLS, /* Last entry */ 54 HISTC_NR_COLS, /* Last entry */
53}; 55};
54 56
@@ -73,7 +75,8 @@ struct hists {
73 75
74struct hist_entry *__hists__add_entry(struct hists *self, 76struct hist_entry *__hists__add_entry(struct hists *self,
75 struct addr_location *al, 77 struct addr_location *al,
76 struct symbol *parent, u64 period); 78 struct symbol *parent, u64 period,
79 u64 weight);
77int64_t hist_entry__cmp(struct hist_entry *left, struct hist_entry *right); 80int64_t hist_entry__cmp(struct hist_entry *left, struct hist_entry *right);
78int64_t hist_entry__collapse(struct hist_entry *left, struct hist_entry *right); 81int64_t hist_entry__collapse(struct hist_entry *left, struct hist_entry *right);
79int hist_entry__sort_snprintf(struct hist_entry *self, char *bf, size_t size, 82int hist_entry__sort_snprintf(struct hist_entry *self, char *bf, size_t size,
@@ -84,7 +87,8 @@ struct hist_entry *__hists__add_branch_entry(struct hists *self,
84 struct addr_location *al, 87 struct addr_location *al,
85 struct symbol *sym_parent, 88 struct symbol *sym_parent,
86 struct branch_info *bi, 89 struct branch_info *bi,
87 u64 period); 90 u64 period,
91 u64 weight);
88 92
89void hists__output_resort(struct hists *self); 93void hists__output_resort(struct hists *self);
90void hists__output_resort_threaded(struct hists *hists); 94void hists__output_resort_threaded(struct hists *hists);
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index c8ba120b0dbe..627be09b479e 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -798,6 +798,9 @@ static void dump_sample(struct perf_evsel *evsel, union perf_event *event,
798 798
799 if (sample_type & PERF_SAMPLE_STACK_USER) 799 if (sample_type & PERF_SAMPLE_STACK_USER)
800 stack_user__printf(&sample->user_stack); 800 stack_user__printf(&sample->user_stack);
801
802 if (sample_type & PERF_SAMPLE_WEIGHT)
803 printf("... weight: %" PRIu64 "\n", sample->weight);
801} 804}
802 805
803static struct machine * 806static struct machine *
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index d41926cb9e3f..d66bcd33248c 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -464,6 +464,49 @@ struct sort_entry sort_mispredict = {
464 .se_width_idx = HISTC_MISPREDICT, 464 .se_width_idx = HISTC_MISPREDICT,
465}; 465};
466 466
467static u64 he_weight(struct hist_entry *he)
468{
469 return he->stat.nr_events ? he->stat.weight / he->stat.nr_events : 0;
470}
471
472static int64_t
473sort__local_weight_cmp(struct hist_entry *left, struct hist_entry *right)
474{
475 return he_weight(left) - he_weight(right);
476}
477
478static int hist_entry__local_weight_snprintf(struct hist_entry *self, char *bf,
479 size_t size, unsigned int width)
480{
481 return repsep_snprintf(bf, size, "%-*llu", width, he_weight(self));
482}
483
484struct sort_entry sort_local_weight = {
485 .se_header = "Local Weight",
486 .se_cmp = sort__local_weight_cmp,
487 .se_snprintf = hist_entry__local_weight_snprintf,
488 .se_width_idx = HISTC_LOCAL_WEIGHT,
489};
490
491static int64_t
492sort__global_weight_cmp(struct hist_entry *left, struct hist_entry *right)
493{
494 return left->stat.weight - right->stat.weight;
495}
496
497static int hist_entry__global_weight_snprintf(struct hist_entry *self, char *bf,
498 size_t size, unsigned int width)
499{
500 return repsep_snprintf(bf, size, "%-*llu", width, self->stat.weight);
501}
502
503struct sort_entry sort_global_weight = {
504 .se_header = "Weight",
505 .se_cmp = sort__global_weight_cmp,
506 .se_snprintf = hist_entry__global_weight_snprintf,
507 .se_width_idx = HISTC_GLOBAL_WEIGHT,
508};
509
467struct sort_dimension { 510struct sort_dimension {
468 const char *name; 511 const char *name;
469 struct sort_entry *entry; 512 struct sort_entry *entry;
@@ -480,6 +523,8 @@ static struct sort_dimension common_sort_dimensions[] = {
480 DIM(SORT_PARENT, "parent", sort_parent), 523 DIM(SORT_PARENT, "parent", sort_parent),
481 DIM(SORT_CPU, "cpu", sort_cpu), 524 DIM(SORT_CPU, "cpu", sort_cpu),
482 DIM(SORT_SRCLINE, "srcline", sort_srcline), 525 DIM(SORT_SRCLINE, "srcline", sort_srcline),
526 DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight),
527 DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
483}; 528};
484 529
485#undef DIM 530#undef DIM
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index b13e56f6ccbe..393925012796 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -49,6 +49,7 @@ struct he_stat {
49 u64 period_us; 49 u64 period_us;
50 u64 period_guest_sys; 50 u64 period_guest_sys;
51 u64 period_guest_us; 51 u64 period_guest_us;
52 u64 weight;
52 u32 nr_events; 53 u32 nr_events;
53}; 54};
54 55
@@ -130,6 +131,8 @@ enum sort_type {
130 SORT_PARENT, 131 SORT_PARENT,
131 SORT_CPU, 132 SORT_CPU,
132 SORT_SRCLINE, 133 SORT_SRCLINE,
134 SORT_LOCAL_WEIGHT,
135 SORT_GLOBAL_WEIGHT,
133 136
134 /* branch stack specific sort keys */ 137 /* branch stack specific sort keys */
135 __SORT_BRANCH_STACK, 138 __SORT_BRANCH_STACK,