1 #include "util/map_symbol.h" 2 #include "util/branch.h" 3 #include <linux/kernel.h> 4 5 static bool cross_area(u64 addr1, u64 addr2, int size) 6 { 7 u64 align1, align2; 8 9 align1 = addr1 & ~(size - 1); 10 align2 = addr2 & ~(size - 1); 11 12 return (align1 != align2) ? true : false; 13 } 14 15 #define AREA_4K 4096 16 #define AREA_2M (2 * 1024 * 1024) 17 18 void branch_type_count(struct branch_type_stat *st, struct branch_flags *flags, 19 u64 from, u64 to) 20 { 21 if (flags->type == PERF_BR_UNKNOWN || from == 0) 22 return; 23 24 st->counts[flags->type]++; 25 26 if (flags->type == PERF_BR_COND) { 27 if (to > from) 28 st->cond_fwd++; 29 else 30 st->cond_bwd++; 31 } 32 33 if (cross_area(from, to, AREA_2M)) 34 st->cross_2m++; 35 else if (cross_area(from, to, AREA_4K)) 36 st->cross_4k++; 37 } 38 39 const char *branch_type_name(int type) 40 { 41 const char *branch_names[PERF_BR_MAX] = { 42 "N/A", 43 "COND", 44 "UNCOND", 45 "IND", 46 "CALL", 47 "IND_CALL", 48 "RET", 49 "SYSCALL", 50 "SYSRET", 51 "COND_CALL", 52 "COND_RET", 53 "ERET", 54 "IRQ" 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