From db8fd07a541fc2d5e8076f0151286e19591465b3 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 5 Mar 2013 14:53:21 +0900 Subject: perf annotate: Pass evsel instead of evidx on annotation functions Pass evsel instead of evidx. This is a preparation for supporting event group view in annotation and no functional change is intended. Signed-off-by: Namhyung Kim Cc: Andi Kleen Cc: Ingo Molnar Cc: Jiri Olsa Cc: Paul Mackerras Cc: Pekka Enberg Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1362462812-30885-2-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) (limited to 'tools/perf/util/annotate.c') diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index d33fe937e6f..7eac5f0895e 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -14,6 +14,7 @@ #include "symbol.h" #include "debug.h" #include "annotate.h" +#include "evsel.h" #include #include @@ -603,7 +604,7 @@ struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disa } static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 start, - int evidx, u64 len, int min_pcnt, int printed, + struct perf_evsel *evsel, u64 len, int min_pcnt, int printed, int max_lines, struct disasm_line *queue) { static const char *prev_line; @@ -616,7 +617,7 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st const char *color; struct annotation *notes = symbol__annotation(sym); struct source_line *src_line = notes->src->lines; - struct sym_hist *h = annotation__histogram(notes, evidx); + struct sym_hist *h = annotation__histogram(notes, evsel->idx); s64 offset = dl->offset; const u64 addr = start + offset; struct disasm_line *next; @@ -648,7 +649,7 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st list_for_each_entry_from(queue, ¬es->src->source, node) { if (queue == dl) break; - disasm_line__print(queue, sym, start, evidx, len, + disasm_line__print(queue, sym, start, evsel, len, 0, 0, 1, NULL); } } @@ -935,7 +936,8 @@ static void symbol__free_source_line(struct symbol *sym, int len) /* Get the filename:line for the colored entries */ static int symbol__get_source_line(struct symbol *sym, struct map *map, - int evidx, struct rb_root *root, int len, + struct perf_evsel *evsel, + struct rb_root *root, int len, const char *filename) { u64 start; @@ -943,7 +945,7 @@ static int symbol__get_source_line(struct symbol *sym, struct map *map, char cmd[PATH_MAX * 2]; struct source_line *src_line; struct annotation *notes = symbol__annotation(sym); - struct sym_hist *h = annotation__histogram(notes, evidx); + struct sym_hist *h = annotation__histogram(notes, evsel->idx); struct rb_root tmp_root = RB_ROOT; if (!h->sum) @@ -1018,10 +1020,10 @@ static void print_summary(struct rb_root *root, const char *filename) } } -static void symbol__annotate_hits(struct symbol *sym, int evidx) +static void symbol__annotate_hits(struct symbol *sym, struct perf_evsel *evsel) { struct annotation *notes = symbol__annotation(sym); - struct sym_hist *h = annotation__histogram(notes, evidx); + struct sym_hist *h = annotation__histogram(notes, evsel->idx); u64 len = symbol__size(sym), offset; for (offset = 0; offset < len; ++offset) @@ -1031,9 +1033,9 @@ static void symbol__annotate_hits(struct symbol *sym, int evidx) printf("%*s: %" PRIu64 "\n", BITS_PER_LONG / 2, "h->sum", h->sum); } -int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx, - bool full_paths, int min_pcnt, int max_lines, - int context) +int symbol__annotate_printf(struct symbol *sym, struct map *map, + struct perf_evsel *evsel, bool full_paths, + int min_pcnt, int max_lines, int context) { struct dso *dso = map->dso; char *filename; @@ -1060,7 +1062,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx, printf("------------------------------------------------\n"); if (verbose) - symbol__annotate_hits(sym, evidx); + symbol__annotate_hits(sym, evsel); list_for_each_entry(pos, ¬es->src->source, node) { if (context && queue == NULL) { @@ -1068,7 +1070,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx, queue_len = 0; } - switch (disasm_line__print(pos, sym, start, evidx, len, + switch (disasm_line__print(pos, sym, start, evsel, len, min_pcnt, printed, max_lines, queue)) { case 0: @@ -1163,9 +1165,9 @@ size_t disasm__fprintf(struct list_head *head, FILE *fp) return printed; } -int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx, - bool print_lines, bool full_paths, int min_pcnt, - int max_lines) +int symbol__tty_annotate(struct symbol *sym, struct map *map, + struct perf_evsel *evsel, bool print_lines, + bool full_paths, int min_pcnt, int max_lines) { struct dso *dso = map->dso; const char *filename = dso->long_name; @@ -1178,12 +1180,12 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx, len = symbol__size(sym); if (print_lines) { - symbol__get_source_line(sym, map, evidx, &source_line, + symbol__get_source_line(sym, map, evsel, &source_line, len, filename); print_summary(&source_line, filename); } - symbol__annotate_printf(sym, map, evidx, full_paths, + symbol__annotate_printf(sym, map, evsel, full_paths, min_pcnt, max_lines, 0); if (print_lines) symbol__free_source_line(sym, len); -- cgit v1.2.3-70-g09d2 From 3aec150af3de6c00570bdacf45bf5a999ab9cf1d Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 5 Mar 2013 14:53:22 +0900 Subject: perf annotate: Add a comment on the symbol__parse_objdump_line() The symbol__parse_objdump_line() parses result of the objdump run but it's hard to follow if one doesn't know the output format of the objdump. Add a head comment on the function to help her. Signed-off-by: Namhyung Kim Cc: Andi Kleen Cc: Ingo Molnar Cc: Jiri Olsa Cc: Paul Mackerras Cc: Pekka Enberg Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1362462812-30885-3-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'tools/perf/util/annotate.c') diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 7eac5f0895e..fa347b169e2 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -689,6 +689,26 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st return 0; } +/* + * symbol__parse_objdump_line() parses objdump output (with -d --no-show-raw) + * which looks like following + * + * 0000000000415500 <_init>: + * 415500: sub $0x8,%rsp + * 415504: mov 0x2f5ad5(%rip),%rax # 70afe0 <_DYNAMIC+0x2f8> + * 41550b: test %rax,%rax + * 41550e: je 415515 <_init+0x15> + * 415510: callq 416e70 <__gmon_start__@plt> + * 415515: add $0x8,%rsp + * 415519: retq + * + * it will be parsed and saved into struct disasm_line as + * + * + * The offset will be a relative offset from the start of the symbol and -1 + * means that it's not a disassembly line so should be treated differently. + * The ops.raw part will be parsed further according to type of the instruction. + */ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, FILE *file, size_t privsize) { -- cgit v1.2.3-70-g09d2 From e5ccf9f45d8bff6bfeafa561d2238b0e4beb415e Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 5 Mar 2013 14:53:23 +0900 Subject: perf annotate: Factor out disasm__calc_percent() Factor out calculation of histogram of a symbol into disasm__calc_percent. It'll be used for later changes. Signed-off-by: Namhyung Kim Cc: Andi Kleen Cc: Ingo Molnar Cc: Jiri Olsa Cc: Paul Mackerras Cc: Pekka Enberg Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1362462812-30885-4-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 49 ++++++++++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 19 deletions(-) (limited to 'tools/perf/util/annotate.c') diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index fa347b169e2..a91d7b18608 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -603,6 +603,33 @@ struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disa return NULL; } +static double disasm__calc_percent(struct disasm_line *next, + struct annotation *notes, int evidx, + s64 offset, u64 len, const char **path) +{ + struct source_line *src_line = notes->src->lines; + struct sym_hist *h = annotation__histogram(notes, evidx); + unsigned int hits = 0; + double percent = 0.0; + + while (offset < (s64)len && + (next == NULL || offset < next->offset)) { + if (src_line) { + if (*path == NULL) + *path = src_line[offset].path; + percent += src_line[offset].percent; + } else + hits += h->addr[offset]; + + ++offset; + } + + if (src_line == NULL && h->sum) + percent = 100.0 * hits / h->sum; + + return percent; +} + static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 start, struct perf_evsel *evsel, u64 len, int min_pcnt, int printed, int max_lines, struct disasm_line *queue) @@ -612,33 +639,17 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st if (dl->offset != -1) { const char *path = NULL; - unsigned int hits = 0; - double percent = 0.0; + double percent; const char *color; struct annotation *notes = symbol__annotation(sym); - struct source_line *src_line = notes->src->lines; - struct sym_hist *h = annotation__histogram(notes, evsel->idx); s64 offset = dl->offset; const u64 addr = start + offset; struct disasm_line *next; next = disasm__get_next_ip_line(¬es->src->source, dl); - while (offset < (s64)len && - (next == NULL || offset < next->offset)) { - if (src_line) { - if (path == NULL) - path = src_line[offset].path; - percent += src_line[offset].percent; - } else - hits += h->addr[offset]; - - ++offset; - } - - if (src_line == NULL && h->sum) - percent = 100.0 * hits / h->sum; - + percent = disasm__calc_percent(next, notes, evsel->idx, + offset, len, &path); if (percent < min_pcnt) return -1; -- cgit v1.2.3-70-g09d2 From bd64fcb8805d8e4575f95f0df22f43b74418a4ec Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 5 Mar 2013 14:53:24 +0900 Subject: perf annotate: Cleanup disasm__calc_percent() The loop end condition is calculated from next disasm_line or the symbol size if it's the last disasm_line. But it doesn't need to be calculated at every iteration. Moving it out of the function can simplify code a bit. Also the src_line doesn't need to be checked in every time. Signed-off-by: Namhyung Kim Cc: Andi Kleen Cc: Ingo Molnar Cc: Jiri Olsa Cc: Paul Mackerras Cc: Pekka Enberg Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1362462812-30885-5-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) (limited to 'tools/perf/util/annotate.c') diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index a91d7b18608..ae71325d3dc 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -603,29 +603,28 @@ struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disa return NULL; } -static double disasm__calc_percent(struct disasm_line *next, - struct annotation *notes, int evidx, - s64 offset, u64 len, const char **path) +static double disasm__calc_percent(struct annotation *notes, int evidx, + s64 offset, s64 end, const char **path) { struct source_line *src_line = notes->src->lines; struct sym_hist *h = annotation__histogram(notes, evidx); unsigned int hits = 0; double percent = 0.0; - while (offset < (s64)len && - (next == NULL || offset < next->offset)) { - if (src_line) { + if (src_line) { + while (offset < end) { if (*path == NULL) *path = src_line[offset].path; - percent += src_line[offset].percent; - } else - hits += h->addr[offset]; - ++offset; - } + percent += src_line[offset++].percent; + } + } else { + while (offset < end) + hits += h->addr[offset++]; - if (src_line == NULL && h->sum) - percent = 100.0 * hits / h->sum; + if (h->sum) + percent = 100.0 * hits / h->sum; + } return percent; } @@ -648,8 +647,9 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st next = disasm__get_next_ip_line(¬es->src->source, dl); - percent = disasm__calc_percent(next, notes, evsel->idx, - offset, len, &path); + percent = disasm__calc_percent(notes, evsel->idx, offset, + next ? next->offset : (s64) len, + &path); if (percent < min_pcnt) return -1; -- cgit v1.2.3-70-g09d2 From b1dd443296b4f8c6869eba790eec950f80392aea Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 5 Mar 2013 14:53:25 +0900 Subject: perf annotate: Add basic support to event group view Add --group option to enable event grouping. When enabled, all the group members information will be shown with the leader so skip non-leader events. It only supports --stdio output currently. Later patches will extend additional features. $ perf annotate --group --stdio ... Percent | Source code & Disassembly of libpthread-2.15.so -------------------------------------------------------------------------------- : : : : Disassembly of section .text: : : 000000387dc0aa50 <__pthread_mutex_unlock_usercnt>: 8.08 2.40 5.29 : 387dc0aa50: mov %rdi,%rdx 0.00 0.00 0.00 : 387dc0aa53: mov 0x10(%rdi),%edi 0.00 0.00 0.00 : 387dc0aa56: mov %edi,%eax 0.00 0.80 0.00 : 387dc0aa58: and $0x7f,%eax 3.03 2.40 3.53 : 387dc0aa5b: test $0x7c,%dil 0.00 0.00 0.00 : 387dc0aa5f: jne 387dc0aaa9 <__pthread_mutex_unlock_use 0.00 0.00 0.00 : 387dc0aa61: test %eax,%eax 0.00 0.00 0.00 : 387dc0aa63: jne 387dc0aa85 <__pthread_mutex_unlock_use 0.00 0.00 0.00 : 387dc0aa65: and $0x80,%edi 0.00 0.00 0.00 : 387dc0aa6b: test %esi,%esi 3.03 5.60 7.06 : 387dc0aa6d: movl $0x0,0x8(%rdx) 0.00 0.00 0.59 : 387dc0aa74: je 387dc0aa7a <__pthread_mutex_unlock_use 0.00 0.00 0.00 : 387dc0aa76: subl $0x1,0xc(%rdx) 2.02 5.60 1.18 : 387dc0aa7a: mov %edi,%esi 0.00 0.00 0.00 : 387dc0aa7c: lock decl (%rdx) 83.84 83.20 82.35 : 387dc0aa7f: jne 387dc0aada <_L_unlock_586> 0.00 0.00 0.00 : 387dc0aa81: nop 0.00 0.00 0.00 : 387dc0aa82: xor %eax,%eax 0.00 0.00 0.00 : 387dc0aa84: retq ... Signed-off-by: Namhyung Kim Cc: Andi Kleen Cc: Ingo Molnar Cc: Jiri Olsa Cc: Paul Mackerras Cc: Pekka Enberg Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1362462812-30885-6-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-annotate.txt | 3 ++ tools/perf/builtin-annotate.c | 7 ++++ tools/perf/util/annotate.c | 64 +++++++++++++++++++++++++----- 3 files changed, 63 insertions(+), 11 deletions(-) (limited to 'tools/perf/util/annotate.c') diff --git a/tools/perf/Documentation/perf-annotate.txt b/tools/perf/Documentation/perf-annotate.txt index 5ad07ef417f..e9cd39a92dc 100644 --- a/tools/perf/Documentation/perf-annotate.txt +++ b/tools/perf/Documentation/perf-annotate.txt @@ -93,6 +93,9 @@ OPTIONS --skip-missing:: Skip symbols that cannot be annotated. +--group:: + Show event group information together + SEE ALSO -------- linkperf:perf-record[1], linkperf:perf-report[1] diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 2f015a99481..ae36f3cb541 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -232,6 +232,11 @@ static int __cmd_annotate(struct perf_annotate *ann) total_nr_samples += nr_samples; hists__collapse_resort(hists); hists__output_resort(hists); + + if (symbol_conf.event_group && + !perf_evsel__is_group_leader(pos)) + continue; + hists__find_annotations(hists, pos, ann); } } @@ -314,6 +319,8 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused) "Specify disassembler style (e.g. -M intel for intel syntax)"), OPT_STRING(0, "objdump", &objdump_path, "path", "objdump binary to use for disassembly and annotations"), + OPT_BOOLEAN(0, "group", &symbol_conf.event_group, + "Show event group information together"), OPT_END() }; diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index ae71325d3dc..0955cff5b0e 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -638,7 +638,9 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st if (dl->offset != -1) { const char *path = NULL; - double percent; + double percent, max_percent = 0.0; + double *ppercents = &percent; + int i, nr_percent = 1; const char *color; struct annotation *notes = symbol__annotation(sym); s64 offset = dl->offset; @@ -647,10 +649,27 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st next = disasm__get_next_ip_line(¬es->src->source, dl); - percent = disasm__calc_percent(notes, evsel->idx, offset, - next ? next->offset : (s64) len, - &path); - if (percent < min_pcnt) + if (symbol_conf.event_group && + perf_evsel__is_group_leader(evsel) && + evsel->nr_members > 1) { + nr_percent = evsel->nr_members; + ppercents = calloc(nr_percent, sizeof(double)); + if (ppercents == NULL) + return -1; + } + + for (i = 0; i < nr_percent; i++) { + percent = disasm__calc_percent(notes, + evsel->idx + i, offset, + next ? next->offset : (s64) len, + &path); + + ppercents[i] = percent; + if (percent > max_percent) + max_percent = percent; + } + + if (max_percent < min_pcnt) return -1; if (max_lines && printed >= max_lines) @@ -665,7 +684,7 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st } } - color = get_percent_color(percent); + color = get_percent_color(max_percent); /* * Also color the filename and line if needed, with @@ -681,20 +700,35 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st } } - color_fprintf(stdout, color, " %7.2f", percent); + for (i = 0; i < nr_percent; i++) { + percent = ppercents[i]; + color = get_percent_color(percent); + color_fprintf(stdout, color, " %7.2f", percent); + } + printf(" : "); color_fprintf(stdout, PERF_COLOR_MAGENTA, " %" PRIx64 ":", addr); color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", dl->line); + + if (ppercents != &percent) + free(ppercents); + } else if (max_lines && printed >= max_lines) return 1; else { + int width = 8; + if (queue) return -1; + if (symbol_conf.event_group && + perf_evsel__is_group_leader(evsel)) + width *= evsel->nr_members; + if (!*dl->line) - printf(" :\n"); + printf(" %*s:\n", width, " "); else - printf(" : %s\n", dl->line); + printf(" %*s: %s\n", width, " ", dl->line); } return 0; @@ -1077,6 +1111,8 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int printed = 2, queue_len = 0; int more = 0; u64 len; + int width = 8; + int namelen; filename = strdup(dso->long_name); if (!filename) @@ -1088,9 +1124,15 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, d_filename = basename(filename); len = symbol__size(sym); + namelen = strlen(d_filename); + + if (symbol_conf.event_group && perf_evsel__is_group_leader(evsel)) + width *= evsel->nr_members; - printf(" Percent | Source code & Disassembly of %s\n", d_filename); - printf("------------------------------------------------\n"); + printf(" %-*.*s| Source code & Disassembly of %s\n", + width, width, "Percent", d_filename); + printf("-%-*.*s-------------------------------------\n", + width+namelen, width+namelen, graph_dotted_line); if (verbose) symbol__annotate_hits(sym, evsel); -- cgit v1.2.3-70-g09d2 From 759ff497e0e6749437b6723f8d26de0b1833c199 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 5 Mar 2013 14:53:26 +0900 Subject: perf evsel: Introduce perf_evsel__is_group_event() helper The perf_evsel__is_group_event function is for checking whether given evsel needs event group view support or not. Please note that it's different to the existing perf_evsel__is_group_leader() which checks only the given evsel is a leader or a standalone (i.e. non-group) event regardless of event group feature. Signed-off-by: Namhyung Kim Cc: Andi Kleen Cc: Ingo Molnar Cc: Jiri Olsa Cc: Paul Mackerras Cc: Pekka Enberg Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1362462812-30885-7-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-report.c | 2 +- tools/perf/ui/browsers/hists.c | 4 ++-- tools/perf/ui/gtk/hists.c | 7 ++----- tools/perf/ui/hist.c | 7 ++----- tools/perf/util/annotate.c | 9 +++------ tools/perf/util/evsel.h | 24 ++++++++++++++++++++++++ 6 files changed, 34 insertions(+), 19 deletions(-) (limited to 'tools/perf/util/annotate.c') diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 96b5a7fee4b..3f4a79ba5ad 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -314,7 +314,7 @@ static size_t hists__fprintf_nr_sample_events(struct hists *self, char buf[512]; size_t size = sizeof(buf); - if (symbol_conf.event_group && evsel->nr_members > 1) { + if (perf_evsel__is_group_event(evsel)) { struct perf_evsel *pos; perf_evsel__group_desc(evsel, buf, size); diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index 0e125e1543d..a5843fd6ab5 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -1193,7 +1193,7 @@ static int hists__browser_title(struct hists *hists, char *bf, size_t size, char buf[512]; size_t buflen = sizeof(buf); - if (symbol_conf.event_group && evsel->nr_members > 1) { + if (perf_evsel__is_group_event(evsel)) { struct perf_evsel *pos; perf_evsel__group_desc(evsel, buf, buflen); @@ -1709,7 +1709,7 @@ static void perf_evsel_menu__write(struct ui_browser *browser, ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED : HE_COLORSET_NORMAL); - if (symbol_conf.event_group && evsel->nr_members > 1) { + if (perf_evsel__is_group_event(evsel)) { struct perf_evsel *pos; ev_name = perf_evsel__group_name(evsel); diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c index 1e764a8ad25..6f259b3d14e 100644 --- a/tools/perf/ui/gtk/hists.c +++ b/tools/perf/ui/gtk/hists.c @@ -32,21 +32,18 @@ static int __hpp__color_fmt(struct perf_hpp *hpp, struct hist_entry *he, int ret; double percent = 0.0; struct hists *hists = he->hists; + struct perf_evsel *evsel = hists_to_evsel(hists); if (hists->stats.total_period) percent = 100.0 * get_field(he) / hists->stats.total_period; ret = __percent_color_snprintf(hpp->buf, hpp->size, percent); - if (symbol_conf.event_group) { + if (perf_evsel__is_group_event(evsel)) { int prev_idx, idx_delta; - struct perf_evsel *evsel = hists_to_evsel(hists); struct hist_entry *pair; int nr_members = evsel->nr_members; - if (nr_members <= 1) - return ret; - prev_idx = perf_evsel__group_idx(evsel); list_for_each_entry(pair, &he->pairs.head, pairs.node) { diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c index d671e63aa35..4bf91b09d62 100644 --- a/tools/perf/ui/hist.c +++ b/tools/perf/ui/hist.c @@ -16,6 +16,7 @@ static int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he, { int ret; struct hists *hists = he->hists; + struct perf_evsel *evsel = hists_to_evsel(hists); if (fmt_percent) { double percent = 0.0; @@ -28,15 +29,11 @@ static int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he, } else ret = print_fn(hpp->buf, hpp->size, fmt, get_field(he)); - if (symbol_conf.event_group) { + if (perf_evsel__is_group_event(evsel)) { int prev_idx, idx_delta; - struct perf_evsel *evsel = hists_to_evsel(hists); struct hist_entry *pair; int nr_members = evsel->nr_members; - if (nr_members <= 1) - return ret; - prev_idx = perf_evsel__group_idx(evsel); list_for_each_entry(pair, &he->pairs.head, pairs.node) { diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 0955cff5b0e..f080cc40f00 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -649,9 +649,7 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st next = disasm__get_next_ip_line(¬es->src->source, dl); - if (symbol_conf.event_group && - perf_evsel__is_group_leader(evsel) && - evsel->nr_members > 1) { + if (perf_evsel__is_group_event(evsel)) { nr_percent = evsel->nr_members; ppercents = calloc(nr_percent, sizeof(double)); if (ppercents == NULL) @@ -721,8 +719,7 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st if (queue) return -1; - if (symbol_conf.event_group && - perf_evsel__is_group_leader(evsel)) + if (perf_evsel__is_group_event(evsel)) width *= evsel->nr_members; if (!*dl->line) @@ -1126,7 +1123,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, len = symbol__size(sym); namelen = strlen(d_filename); - if (symbol_conf.event_group && perf_evsel__is_group_leader(evsel)) + if (perf_evsel__is_group_event(evsel)) width *= evsel->nr_members; printf(" %-*.*s| Source code & Disassembly of %s\n", diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 52021c3087d..bf758e53c92 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -9,6 +9,7 @@ #include "xyarray.h" #include "cgroup.h" #include "hist.h" +#include "symbol.h" struct perf_counts_values { union { @@ -246,11 +247,34 @@ static inline struct perf_evsel *perf_evsel__next(struct perf_evsel *evsel) return list_entry(evsel->node.next, struct perf_evsel, node); } +/** + * perf_evsel__is_group_leader - Return whether given evsel is a leader event + * + * @evsel - evsel selector to be tested + * + * Return %true if @evsel is a group leader or a stand-alone event + */ static inline bool perf_evsel__is_group_leader(const struct perf_evsel *evsel) { return evsel->leader == evsel; } +/** + * perf_evsel__is_group_event - Return whether given evsel is a group event + * + * @evsel - evsel selector to be tested + * + * Return %true iff event group view is enabled and @evsel is a actual group + * leader which has other members in the group + */ +static inline bool perf_evsel__is_group_event(struct perf_evsel *evsel) +{ + if (!symbol_conf.event_group) + return false; + + return perf_evsel__is_group_leader(evsel) && evsel->nr_members > 1; +} + struct perf_attr_details { bool freq; bool verbose; -- cgit v1.2.3-70-g09d2 From c5a8368ca667d22a6e45396f23a5392d90396f39 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 5 Mar 2013 14:53:27 +0900 Subject: perf annotate: Factor out struct source_line_percent The source_line_percent struct contains percentage value of the symbol histogram. This is a preparation of event group view change. Signed-off-by: Namhyung Kim Cc: Andi Kleen Cc: Ingo Molnar Cc: Jiri Olsa Cc: Paul Mackerras Cc: Pekka Enberg Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1362462812-30885-8-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 2 +- tools/perf/util/annotate.c | 14 +++++++------- tools/perf/util/annotate.h | 8 ++++++-- 3 files changed, 14 insertions(+), 10 deletions(-) (limited to 'tools/perf/util/annotate.c') diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 67798472384..cfae57f9014 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -257,7 +257,7 @@ static double disasm_line__calc_percent(struct disasm_line *dl, struct symbol *s while (offset < (s64)len && (next == NULL || offset < next->offset)) { if (src_line) { - percent += src_line[offset].percent; + percent += src_line[offset].p[0].percent; } else hits += h->addr[offset]; diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index f080cc40f00..ebf2596d7e2 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -616,7 +616,7 @@ static double disasm__calc_percent(struct annotation *notes, int evidx, if (*path == NULL) *path = src_line[offset].path; - percent += src_line[offset++].percent; + percent += src_line[offset++].p[0].percent; } } else { while (offset < end) @@ -929,7 +929,7 @@ static void insert_source_line(struct rb_root *root, struct source_line *src_lin ret = strcmp(iter->path, src_line->path); if (ret == 0) { - iter->percent_sum += src_line->percent; + iter->p[0].percent_sum += src_line->p[0].percent; return; } @@ -939,7 +939,7 @@ static void insert_source_line(struct rb_root *root, struct source_line *src_lin p = &(*p)->rb_right; } - src_line->percent_sum = src_line->percent; + src_line->p[0].percent_sum = src_line->p[0].percent; rb_link_node(&src_line->node, parent, p); rb_insert_color(&src_line->node, root); @@ -955,7 +955,7 @@ static void __resort_source_line(struct rb_root *root, struct source_line *src_l parent = *p; iter = rb_entry(parent, struct source_line, node); - if (src_line->percent_sum > iter->percent_sum) + if (src_line->p[0].percent_sum > iter->p[0].percent_sum) p = &(*p)->rb_left; else p = &(*p)->rb_right; @@ -1025,8 +1025,8 @@ static int symbol__get_source_line(struct symbol *sym, struct map *map, u64 offset; FILE *fp; - src_line[i].percent = 100.0 * h->addr[i] / h->sum; - if (src_line[i].percent <= 0.5) + src_line[i].p[0].percent = 100.0 * h->addr[i] / h->sum; + if (src_line[i].p[0].percent <= 0.5) continue; offset = start + i; @@ -1073,7 +1073,7 @@ static void print_summary(struct rb_root *root, const char *filename) char *path; src_line = rb_entry(node, struct source_line, node); - percent = src_line->percent_sum; + percent = src_line->p[0].percent_sum; color = get_percent_color(percent); path = src_line->path; diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 37639547566..bb2e3f99898 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -74,11 +74,15 @@ struct sym_hist { u64 addr[0]; }; -struct source_line { - struct rb_node node; +struct source_line_percent { double percent; double percent_sum; +}; + +struct source_line { + struct rb_node node; char *path; + struct source_line_percent p[1]; }; /** struct annotated_source - symbols with hits have this attached as in sannotation -- cgit v1.2.3-70-g09d2 From 1491c22a5f8563951d3a798758f82b471ecbf501 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 5 Mar 2013 14:53:28 +0900 Subject: perf annotate: Support event group view for --print-line Dynamically allocate source_line_percent according to a number of group members and save nr_pcnt to the struct source_line. This way we can handle multiple events in a general manner. However since the size of struct source_line is not fixed anymore, iterating whole source_line should care about its size. $ perf annotate --group --stdio --print-line Sorted summary for file /lib/ld-2.11.1.so ---------------------------------------------- 33.33 0.00 /build/buildd/eglibc-2.11.1/elf/rtld.c:381 33.33 0.00 /build/buildd/eglibc-2.11.1/elf/dynamic-link.h:128 33.33 0.00 /build/buildd/eglibc-2.11.1/elf/do-rel.h:105 0.00 75.00 /build/buildd/eglibc-2.11.1/elf/dynamic-link.h:137 0.00 25.00 /build/buildd/eglibc-2.11.1/elf/dynamic-link.h:187 ... Signed-off-by: Namhyung Kim Cc: Andi Kleen Cc: Ingo Molnar Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Pekka Enberg Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1362462812-30885-9-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 130 +++++++++++++++++++++++++++++++++------------ tools/perf/util/annotate.h | 1 + 2 files changed, 98 insertions(+), 33 deletions(-) (limited to 'tools/perf/util/annotate.c') diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index ebf2596d7e2..05e34df5d04 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -607,18 +607,26 @@ static double disasm__calc_percent(struct annotation *notes, int evidx, s64 offset, s64 end, const char **path) { struct source_line *src_line = notes->src->lines; - struct sym_hist *h = annotation__histogram(notes, evidx); - unsigned int hits = 0; double percent = 0.0; if (src_line) { + size_t sizeof_src_line = sizeof(*src_line) + + sizeof(src_line->p) * (src_line->nr_pcnt - 1); + while (offset < end) { + src_line = (void *)notes->src->lines + + (sizeof_src_line * offset); + if (*path == NULL) - *path = src_line[offset].path; + *path = src_line->path; - percent += src_line[offset++].p[0].percent; + percent += src_line->p[evidx].percent; + offset++; } } else { + struct sym_hist *h = annotation__histogram(notes, evidx); + unsigned int hits = 0; + while (offset < end) hits += h->addr[offset++]; @@ -658,9 +666,10 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st for (i = 0; i < nr_percent; i++) { percent = disasm__calc_percent(notes, - evsel->idx + i, offset, - next ? next->offset : (s64) len, - &path); + notes->src->lines ? i : evsel->idx + i, + offset, + next ? next->offset : (s64) len, + &path); ppercents[i] = percent; if (percent > max_percent) @@ -921,7 +930,7 @@ static void insert_source_line(struct rb_root *root, struct source_line *src_lin struct source_line *iter; struct rb_node **p = &root->rb_node; struct rb_node *parent = NULL; - int ret; + int i, ret; while (*p != NULL) { parent = *p; @@ -929,7 +938,8 @@ static void insert_source_line(struct rb_root *root, struct source_line *src_lin ret = strcmp(iter->path, src_line->path); if (ret == 0) { - iter->p[0].percent_sum += src_line->p[0].percent; + for (i = 0; i < src_line->nr_pcnt; i++) + iter->p[i].percent_sum += src_line->p[i].percent; return; } @@ -939,12 +949,26 @@ static void insert_source_line(struct rb_root *root, struct source_line *src_lin p = &(*p)->rb_right; } - src_line->p[0].percent_sum = src_line->p[0].percent; + for (i = 0; i < src_line->nr_pcnt; i++) + src_line->p[i].percent_sum = src_line->p[i].percent; rb_link_node(&src_line->node, parent, p); rb_insert_color(&src_line->node, root); } +static int cmp_source_line(struct source_line *a, struct source_line *b) +{ + int i; + + for (i = 0; i < a->nr_pcnt; i++) { + if (a->p[i].percent_sum == b->p[i].percent_sum) + continue; + return a->p[i].percent_sum > b->p[i].percent_sum; + } + + return 0; +} + static void __resort_source_line(struct rb_root *root, struct source_line *src_line) { struct source_line *iter; @@ -955,7 +979,7 @@ static void __resort_source_line(struct rb_root *root, struct source_line *src_l parent = *p; iter = rb_entry(parent, struct source_line, node); - if (src_line->p[0].percent_sum > iter->p[0].percent_sum) + if (cmp_source_line(src_line, iter)) p = &(*p)->rb_left; else p = &(*p)->rb_right; @@ -987,12 +1011,18 @@ static void symbol__free_source_line(struct symbol *sym, int len) { struct annotation *notes = symbol__annotation(sym); struct source_line *src_line = notes->src->lines; + size_t sizeof_src_line; int i; - for (i = 0; i < len; i++) - free(src_line[i].path); + sizeof_src_line = sizeof(*src_line) + + (sizeof(src_line->p) * (src_line->nr_pcnt - 1)); - free(src_line); + for (i = 0; i < len; i++) { + free(src_line->path); + src_line = (void *)src_line + sizeof_src_line; + } + + free(notes->src->lines); notes->src->lines = NULL; } @@ -1003,17 +1033,30 @@ static int symbol__get_source_line(struct symbol *sym, struct map *map, const char *filename) { u64 start; - int i; + int i, k; + int evidx = evsel->idx; char cmd[PATH_MAX * 2]; struct source_line *src_line; struct annotation *notes = symbol__annotation(sym); - struct sym_hist *h = annotation__histogram(notes, evsel->idx); + struct sym_hist *h = annotation__histogram(notes, evidx); struct rb_root tmp_root = RB_ROOT; + int nr_pcnt = 1; + u64 h_sum = h->sum; + size_t sizeof_src_line = sizeof(struct source_line); + + if (perf_evsel__is_group_event(evsel)) { + for (i = 1; i < evsel->nr_members; i++) { + h = annotation__histogram(notes, evidx + i); + h_sum += h->sum; + } + nr_pcnt = evsel->nr_members; + sizeof_src_line += (nr_pcnt - 1) * sizeof(src_line->p); + } - if (!h->sum) + if (!h_sum) return 0; - src_line = notes->src->lines = calloc(len, sizeof(struct source_line)); + src_line = notes->src->lines = calloc(len, sizeof_src_line); if (!notes->src->lines) return -1; @@ -1024,29 +1067,41 @@ static int symbol__get_source_line(struct symbol *sym, struct map *map, size_t line_len; u64 offset; FILE *fp; + double percent_max = 0.0; - src_line[i].p[0].percent = 100.0 * h->addr[i] / h->sum; - if (src_line[i].p[0].percent <= 0.5) - continue; + src_line->nr_pcnt = nr_pcnt; + + for (k = 0; k < nr_pcnt; k++) { + h = annotation__histogram(notes, evidx + k); + src_line->p[k].percent = 100.0 * h->addr[i] / h->sum; + + if (src_line->p[k].percent > percent_max) + percent_max = src_line->p[k].percent; + } + + if (percent_max <= 0.5) + goto next; offset = start + i; sprintf(cmd, "addr2line -e %s %016" PRIx64, filename, offset); fp = popen(cmd, "r"); if (!fp) - continue; + goto next; if (getline(&path, &line_len, fp) < 0 || !line_len) - goto next; + goto next_close; - src_line[i].path = malloc(sizeof(char) * line_len + 1); - if (!src_line[i].path) - goto next; + src_line->path = malloc(sizeof(char) * line_len + 1); + if (!src_line->path) + goto next_close; - strcpy(src_line[i].path, path); - insert_source_line(&tmp_root, &src_line[i]); + strcpy(src_line->path, path); + insert_source_line(&tmp_root, src_line); - next: + next_close: pclose(fp); + next: + src_line = (void *)src_line + sizeof_src_line; } resort_source_line(root, &tmp_root); @@ -1068,16 +1123,25 @@ static void print_summary(struct rb_root *root, const char *filename) node = rb_first(root); while (node) { - double percent; + double percent, percent_max = 0.0; const char *color; char *path; + int i; src_line = rb_entry(node, struct source_line, node); - percent = src_line->p[0].percent_sum; - color = get_percent_color(percent); + for (i = 0; i < src_line->nr_pcnt; i++) { + percent = src_line->p[i].percent_sum; + color = get_percent_color(percent); + color_fprintf(stdout, color, " %7.2f", percent); + + if (percent > percent_max) + percent_max = percent; + } + path = src_line->path; + color = get_percent_color(percent_max); + color_fprintf(stdout, color, " %s", path); - color_fprintf(stdout, color, " %7.2f %s", percent, path); node = rb_next(node); } } diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index bb2e3f99898..68f851e6c68 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -82,6 +82,7 @@ struct source_line_percent { struct source_line { struct rb_node node; char *path; + int nr_pcnt; struct source_line_percent p[1]; }; -- cgit v1.2.3-70-g09d2 From e64aa75bf5559be3ce72e53ae28b76a2f633ca06 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 5 Mar 2013 14:53:30 +0900 Subject: perf annotate browser: Use disasm__calc_percent() The disasm_line__calc_percent() which was used by annotate browser code almost duplicates disasm__calc_percent. Let's get rid of the code duplication. Signed-off-by: Namhyung Kim Cc: Andi Kleen Cc: Ingo Molnar Cc: Jiri Olsa Cc: Namhyung Kim Cc: Paul Mackerras Cc: Pekka Enberg Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1362462812-30885-11-git-send-email-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/annotate.c | 50 +++++++++++---------------------------- tools/perf/util/annotate.c | 4 ++-- tools/perf/util/annotate.h | 4 ++++ 3 files changed, 20 insertions(+), 38 deletions(-) (limited to 'tools/perf/util/annotate.c') diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 62369f0b660..8b16926dd56 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -240,40 +240,6 @@ static unsigned int annotate_browser__refresh(struct ui_browser *browser) return ret; } -static double disasm_line__calc_percent(struct disasm_line *dl, struct symbol *sym, int evidx) -{ - double percent = 0.0; - - if (dl->offset != -1) { - int len = sym->end - sym->start; - unsigned int hits = 0; - struct annotation *notes = symbol__annotation(sym); - struct source_line *src_line = notes->src->lines; - struct sym_hist *h = annotation__histogram(notes, evidx); - s64 offset = dl->offset; - struct disasm_line *next; - - next = disasm__get_next_ip_line(¬es->src->source, dl); - while (offset < (s64)len && - (next == NULL || offset < next->offset)) { - if (src_line) { - percent += src_line[offset].p[0].percent; - } else - hits += h->addr[offset]; - - ++offset; - } - /* - * If the percentage wasn't already calculated in - * symbol__get_source_line, do it now: - */ - if (src_line == NULL && h->sum) - percent = 100.0 * hits / h->sum; - } - - return percent; -} - static void disasm_rb_tree__insert(struct rb_root *root, struct browser_disasm_line *bdl) { struct rb_node **p = &root->rb_node; @@ -337,7 +303,8 @@ static void annotate_browser__calc_percent(struct annotate_browser *browser, struct map_symbol *ms = browser->b.priv; struct symbol *sym = ms->sym; struct annotation *notes = symbol__annotation(sym); - struct disasm_line *pos; + struct disasm_line *pos, *next; + s64 len = symbol__size(sym); browser->entries = RB_ROOT; @@ -345,7 +312,18 @@ static void annotate_browser__calc_percent(struct annotate_browser *browser, list_for_each_entry(pos, ¬es->src->source, node) { struct browser_disasm_line *bpos = disasm_line__browser(pos); - bpos->percent[0] = disasm_line__calc_percent(pos, sym, evsel->idx); + const char *path = NULL; + + if (pos->offset == -1) { + RB_CLEAR_NODE(&bpos->rb_node); + continue; + } + + next = disasm__get_next_ip_line(¬es->src->source, pos); + bpos->percent[0] = disasm__calc_percent(notes, evsel->idx, + pos->offset, next ? next->offset : len, + &path); + if (bpos->percent[0] < 0.01) { RB_CLEAR_NODE(&bpos->rb_node); continue; diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 05e34df5d04..d102716c43a 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -603,8 +603,8 @@ struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disa return NULL; } -static double disasm__calc_percent(struct annotation *notes, int evidx, - s64 offset, s64 end, const char **path) +double disasm__calc_percent(struct annotation *notes, int evidx, s64 offset, + s64 end, const char **path) { struct source_line *src_line = notes->src->lines; double percent = 0.0; diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 68f851e6c68..6f3c16f01ab 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -50,6 +50,8 @@ bool ins__is_jump(const struct ins *ins); bool ins__is_call(const struct ins *ins); int ins__scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops); +struct annotation; + struct disasm_line { struct list_head node; s64 offset; @@ -68,6 +70,8 @@ void disasm_line__free(struct disasm_line *dl); struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disasm_line *pos); int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw); size_t disasm__fprintf(struct list_head *head, FILE *fp); +double disasm__calc_percent(struct annotation *notes, int evidx, s64 offset, + s64 end, const char **path); struct sym_hist { u64 sum; -- cgit v1.2.3-70-g09d2