1 #include "util/util.h" 2 #include "util/debug.h" 3 #include "util/map_symbol.h" 4 #include "util/branch.h" 5 #include <linux/kernel.h> 6 7 static bool cross_area(u64 addr1, u64 addr2, int size) 8 { 9 u64 align1, align2; 10 11 align1 = addr1 & ~(size - 1); 12 align2 = addr2 & ~(size - 1); 13 14 return (align1 != align2) ? true : false; 15 } 16 17 #define AREA_4K 4096 18 #define AREA_2M (2 * 1024 * 1024) 19 20 void branch_type_count(struct branch_type_stat *st, struct branch_flags *flags, 21 u64 from, u64 to) 22 { 23 if (flags->type == PERF_BR_UNKNOWN || from == 0) 24 return; 25 26 st->counts[flags->type]++; 27 28 if (flags->type == PERF_BR_COND) { 29 if (to > from) 30 st->cond_fwd++; 31 else 32 st->cond_bwd++; 33 } 34 35 if (cross_area(from, to, AREA_2M)) 36 st->cross_2m++; 37 else if (cross_area(from, to, AREA_4K)) 38 st->cross_4k++; 39 } 40 41 const char *branch_type_name(int type) 42 { 43 const char *branch_names[PERF_BR_MAX] = { 44 "N/A", 45 "COND", 46 "UNCOND", 47 "IND", 48 "CALL", 49 "IND_CALL", 50 "RET", 51 "SYSCALL", 52 "SYSRET", 53 "COND_CALL", 54 "COND_RET" 55 }; 56 57 if (type >= 0 && type < PERF_BR_MAX) 58 return branch_names[type]; 59 60 return NULL; 61 } 62 63 void branch_type_stat_display(FILE *fp, struct branch_type_stat *st) 64 { 65 u64 total = 0; 66 int i; 67 68 for (i = 0; i < PERF_BR_MAX; i++) 69 total += st->counts[i]; 70 71 if (total == 0) 72 return; 73 74 fprintf(fp, "\n#"); 75 fprintf(fp, "\n# Branch Statistics:"); 76 fprintf(fp, "\n#"); 77 78 if (st->cond_fwd > 0) { 79 fprintf(fp, "\n%8s: %5.1f%%", 80 "COND_FWD", 81 100.0 * (double)st->cond_fwd / (double)total); 82 } 83 84 if (st->cond_bwd > 0) { 85 fprintf(fp, "\n%8s: %5.1f%%", 86 "COND_BWD", 87 100.0 * (double)st->cond_bwd / (double)total); 88 } 89 90 if (st->cross_4k > 0) { 91 fprintf(fp, "\n%8s: %5.1f%%", 92 "CROSS_4K", 93 100.0 * (double)st->cross_4k / (double)total); 94 } 95 96 if (st->cross_2m > 0) { 97 fprintf(fp, "\n%8s: %5.1f%%", 98 "CROSS_2M", 99 100.0 * (double)st->cross_2m / (double)total); 100 } 101 102 for (i = 0; i < PERF_BR_MAX; i++) { 103 if (st->counts[i] > 0) 104 fprintf(fp, "\n%8s: %5.1f%%", 105 branch_type_name(i), 106 100.0 * 107 (double)st->counts[i] / (double)total); 108 } 109 } 110 111 static int count_str_scnprintf(int idx, const char *str, char *bf, int size) 112 { 113 return scnprintf(bf, size, "%s%s", (idx) ? " " : " (", str); 114 } 115 116 int branch_type_str(struct branch_type_stat *st, char *bf, int size) 117 { 118 int i, j = 0, printed = 0; 119 u64 total = 0; 120 121 for (i = 0; i < PERF_BR_MAX; i++) 122 total += st->counts[i]; 123 124 if (total == 0) 125 return 0; 126 127 if (st->cond_fwd > 0) 128 printed += count_str_scnprintf(j++, "COND_FWD", bf + printed, size - printed); 129 130 if (st->cond_bwd > 0) 131 printed += count_str_scnprintf(j++, "COND_BWD", bf + printed, size - printed); 132 133 for (i = 0; i < PERF_BR_MAX; i++) { 134 if (i == PERF_BR_COND) 135 continue; 136 137 if (st->counts[i] > 0) 138 printed += count_str_scnprintf(j++, branch_type_name(i), bf + printed, size - printed); 139 } 140 141 if (st->cross_4k > 0) 142 printed += count_str_scnprintf(j++, "CROSS_4K", bf + printed, size - printed); 143 144 if (st->cross_2m > 0) 145 printed += count_str_scnprintf(j++, "CROSS_2M", bf + printed, size - printed); 146 147 return printed; 148 } 149