diff options
| author | Jin Yao <yao.jin@linux.intel.com> | 2017-07-18 08:13:13 -0400 |
|---|---|---|
| committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2017-07-18 22:14:40 -0400 |
| commit | 992c7e9267c12a8e301152c5569028ff8d535322 (patch) | |
| tree | c8dc33d9bfc3ec9fc48abc506ea74ef5e61190a3 | |
| parent | 8d51735fcd2be1791c0bfe2d581d9063281fe7fb (diff) | |
perf util: Create branch.c/.h for common branch functions
Create new util/branch.c and util/branch.h to contain the common branch
functions. Such as:
branch_type_count(): Count the numbers of branch types
branch_type_name() : Return the name of branch type
branch_type_stat_display(): Display branch type statistics info
branch_type_str(): Construct the branch type string.
The branch type is saved in branch_flags.
Change log:
v8: Change PERF_BR_NONE to PERF_BR_UNKNOWN.
v7: Since the common branch type name is changed (e.g. JCC->COND),
this patch is performed the modification accordingly.
v6: Move that multiline conditional code inside {} brackets.
Move branch_type_stat_display() from builtin-report.c to
branch.c.
Move branch_type_str() from callchain.c to branch.c.
v5: It's a new patch in v5 patch series.
Signed-off-by: Yao Jin <yao.jin@linux.intel.com>
Acked-by: Jiri Olsa <jolsa@kernel.org>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Kan Liang <kan.liang@intel.com>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1500379995-6449-6-git-send-email-yao.jin@linux.intel.com
[ Don't use 'index' and 'stat' as names for variables, it shadows global decls in older distros ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
| -rw-r--r-- | tools/perf/util/Build | 1 | ||||
| -rw-r--r-- | tools/perf/util/branch.c | 147 | ||||
| -rw-r--r-- | tools/perf/util/branch.h | 24 | ||||
| -rw-r--r-- | tools/perf/util/event.h | 3 |
4 files changed, 174 insertions, 1 deletions
diff --git a/tools/perf/util/Build b/tools/perf/util/Build index 7580fe4d5d30..8d49a989f193 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build | |||
| @@ -93,6 +93,7 @@ libperf-y += drv_configs.o | |||
| 93 | libperf-y += units.o | 93 | libperf-y += units.o |
| 94 | libperf-y += time-utils.o | 94 | libperf-y += time-utils.o |
| 95 | libperf-y += expr-bison.o | 95 | libperf-y += expr-bison.o |
| 96 | libperf-y += branch.o | ||
| 96 | 97 | ||
| 97 | libperf-$(CONFIG_LIBBPF) += bpf-loader.o | 98 | libperf-$(CONFIG_LIBBPF) += bpf-loader.o |
| 98 | libperf-$(CONFIG_BPF_PROLOGUE) += bpf-prologue.o | 99 | libperf-$(CONFIG_BPF_PROLOGUE) += bpf-prologue.o |
diff --git a/tools/perf/util/branch.c b/tools/perf/util/branch.c new file mode 100644 index 000000000000..a4fce2729e50 --- /dev/null +++ b/tools/perf/util/branch.c | |||
| @@ -0,0 +1,147 @@ | |||
| 1 | #include "perf.h" | ||
| 2 | #include "util/util.h" | ||
| 3 | #include "util/debug.h" | ||
| 4 | #include "util/branch.h" | ||
| 5 | |||
| 6 | static bool cross_area(u64 addr1, u64 addr2, int size) | ||
| 7 | { | ||
| 8 | u64 align1, align2; | ||
| 9 | |||
| 10 | align1 = addr1 & ~(size - 1); | ||
| 11 | align2 = addr2 & ~(size - 1); | ||
| 12 | |||
| 13 | return (align1 != align2) ? true : false; | ||
| 14 | } | ||
| 15 | |||
| 16 | #define AREA_4K 4096 | ||
| 17 | #define AREA_2M (2 * 1024 * 1024) | ||
| 18 | |||
| 19 | void branch_type_count(struct branch_type_stat *st, struct branch_flags *flags, | ||
| 20 | u64 from, u64 to) | ||
| 21 | { | ||
| 22 | if (flags->type == PERF_BR_UNKNOWN || from == 0) | ||
| 23 | return; | ||
| 24 | |||
| 25 | st->counts[flags->type]++; | ||
| 26 | |||
| 27 | if (flags->type == PERF_BR_COND) { | ||
| 28 | if (to > from) | ||
| 29 | st->cond_fwd++; | ||
| 30 | else | ||
| 31 | st->cond_bwd++; | ||
| 32 | } | ||
| 33 | |||
| 34 | if (cross_area(from, to, AREA_2M)) | ||
| 35 | st->cross_2m++; | ||
| 36 | else if (cross_area(from, to, AREA_4K)) | ||
| 37 | st->cross_4k++; | ||
| 38 | } | ||
| 39 | |||
| 40 | const char *branch_type_name(int type) | ||
| 41 | { | ||
| 42 | const char *branch_names[PERF_BR_MAX] = { | ||
| 43 | "N/A", | ||
| 44 | "COND", | ||
| 45 | "UNCOND", | ||
| 46 | "IND", | ||
| 47 | "CALL", | ||
| 48 | "IND_CALL", | ||
| 49 | "RET", | ||
| 50 | "SYSCALL", | ||
| 51 | "SYSRET", | ||
| 52 | "COND_CALL", | ||
| 53 | "COND_RET" | ||
| 54 | }; | ||
| 55 | |||
| 56 | if (type >= 0 && type < PERF_BR_MAX) | ||
| 57 | return branch_names[type]; | ||
| 58 | |||
| 59 | return NULL; | ||
| 60 | } | ||
| 61 | |||
| 62 | void branch_type_stat_display(FILE *fp, struct branch_type_stat *st) | ||
| 63 | { | ||
| 64 | u64 total = 0; | ||
| 65 | int i; | ||
| 66 | |||
| 67 | for (i = 0; i < PERF_BR_MAX; i++) | ||
| 68 | total += st->counts[i]; | ||
| 69 | |||
| 70 | if (total == 0) | ||
| 71 | return; | ||
| 72 | |||
| 73 | fprintf(fp, "\n#"); | ||
| 74 | fprintf(fp, "\n# Branch Statistics:"); | ||
| 75 | fprintf(fp, "\n#"); | ||
| 76 | |||
| 77 | if (st->cond_fwd > 0) { | ||
| 78 | fprintf(fp, "\n%8s: %5.1f%%", | ||
| 79 | "COND_FWD", | ||
| 80 | 100.0 * (double)st->cond_fwd / (double)total); | ||
| 81 | } | ||
| 82 | |||
| 83 | if (st->cond_bwd > 0) { | ||
| 84 | fprintf(fp, "\n%8s: %5.1f%%", | ||
| 85 | "COND_BWD", | ||
| 86 | 100.0 * (double)st->cond_bwd / (double)total); | ||
| 87 | } | ||
| 88 | |||
| 89 | if (st->cross_4k > 0) { | ||
| 90 | fprintf(fp, "\n%8s: %5.1f%%", | ||
| 91 | "CROSS_4K", | ||
| 92 | 100.0 * (double)st->cross_4k / (double)total); | ||
| 93 | } | ||
| 94 | |||
| 95 | if (st->cross_2m > 0) { | ||
| 96 | fprintf(fp, "\n%8s: %5.1f%%", | ||
| 97 | "CROSS_2M", | ||
| 98 | 100.0 * (double)st->cross_2m / (double)total); | ||
| 99 | } | ||
| 100 | |||
| 101 | for (i = 0; i < PERF_BR_MAX; i++) { | ||
| 102 | if (st->counts[i] > 0) | ||
| 103 | fprintf(fp, "\n%8s: %5.1f%%", | ||
| 104 | branch_type_name(i), | ||
| 105 | 100.0 * | ||
| 106 | (double)st->counts[i] / (double)total); | ||
| 107 | } | ||
| 108 | } | ||
| 109 | |||
| 110 | static int count_str_scnprintf(int idx, const char *str, char *bf, int size) | ||
| 111 | { | ||
| 112 | return scnprintf(bf, size, "%s%s", (idx) ? " " : " (", str); | ||
| 113 | } | ||
| 114 | |||
| 115 | int branch_type_str(struct branch_type_stat *st, char *bf, int size) | ||
| 116 | { | ||
| 117 | int i, j = 0, printed = 0; | ||
| 118 | u64 total = 0; | ||
| 119 | |||
| 120 | for (i = 0; i < PERF_BR_MAX; i++) | ||
| 121 | total += st->counts[i]; | ||
| 122 | |||
| 123 | if (total == 0) | ||
| 124 | return 0; | ||
| 125 | |||
| 126 | if (st->cond_fwd > 0) | ||
| 127 | printed += count_str_scnprintf(j++, "COND_FWD", bf + printed, size - printed); | ||
| 128 | |||
| 129 | if (st->cond_bwd > 0) | ||
| 130 | printed += count_str_scnprintf(j++, "COND_BWD", bf + printed, size - printed); | ||
| 131 | |||
| 132 | for (i = 0; i < PERF_BR_MAX; i++) { | ||
| 133 | if (i == PERF_BR_COND) | ||
| 134 | continue; | ||
| 135 | |||
| 136 | if (st->counts[i] > 0) | ||
| 137 | printed += count_str_scnprintf(j++, branch_type_name(i), bf + printed, size - printed); | ||
| 138 | } | ||
| 139 | |||
| 140 | if (st->cross_4k > 0) | ||
| 141 | printed += count_str_scnprintf(j++, "CROSS_4K", bf + printed, size - printed); | ||
| 142 | |||
| 143 | if (st->cross_2m > 0) | ||
| 144 | printed += count_str_scnprintf(j++, "CROSS_2M", bf + printed, size - printed); | ||
| 145 | |||
| 146 | return printed; | ||
| 147 | } | ||
diff --git a/tools/perf/util/branch.h b/tools/perf/util/branch.h new file mode 100644 index 000000000000..686f2b65ba84 --- /dev/null +++ b/tools/perf/util/branch.h | |||
| @@ -0,0 +1,24 @@ | |||
| 1 | #ifndef _PERF_BRANCH_H | ||
| 2 | #define _PERF_BRANCH_H 1 | ||
| 3 | |||
| 4 | #include <stdint.h> | ||
| 5 | #include "../perf.h" | ||
| 6 | |||
| 7 | struct branch_type_stat { | ||
| 8 | u64 counts[PERF_BR_MAX]; | ||
| 9 | u64 cond_fwd; | ||
| 10 | u64 cond_bwd; | ||
| 11 | u64 cross_4k; | ||
| 12 | u64 cross_2m; | ||
| 13 | }; | ||
| 14 | |||
| 15 | struct branch_flags; | ||
| 16 | |||
| 17 | void branch_type_count(struct branch_type_stat *st, struct branch_flags *flags, | ||
| 18 | u64 from, u64 to); | ||
| 19 | |||
| 20 | const char *branch_type_name(int type); | ||
| 21 | void branch_type_stat_display(FILE *fp, struct branch_type_stat *st); | ||
| 22 | int branch_type_str(struct branch_type_stat *st, char *bf, int bfsize); | ||
| 23 | |||
| 24 | #endif /* _PERF_BRANCH_H */ | ||
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 37c5fafb549c..423ac82605f3 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h | |||
| @@ -142,7 +142,8 @@ struct branch_flags { | |||
| 142 | u64 in_tx:1; | 142 | u64 in_tx:1; |
| 143 | u64 abort:1; | 143 | u64 abort:1; |
| 144 | u64 cycles:16; | 144 | u64 cycles:16; |
| 145 | u64 reserved:44; | 145 | u64 type:4; |
| 146 | u64 reserved:40; | ||
| 146 | }; | 147 | }; |
| 147 | 148 | ||
| 148 | struct branch_entry { | 149 | struct branch_entry { |
