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 }; 54 55 if (type >= 0 && type < PERF_BR_MAX) 56 return branch_names[type]; 57 58 return NULL; 59 } 60 61 void branch_type_stat_display(FILE *fp, struct branch_type_stat *st) 62 { 63 u64 total = 0; 64 int i; 65 66 for (i = 0; i < PERF_BR_MAX; i++) 67 total += st->counts[i]; 68 69 if (total == 0) 70 return; 71 72 fprintf(fp, "\n#"); 73 fprintf(fp, "\n# Branch Statistics:"); 74 fprintf(fp, "\n#"); 75 76 if (st->cond_fwd > 0) { 77 fprintf(fp, "\n%8s: %5.1f%%", 78 "COND_FWD", 79 100.0 * (double)st->cond_fwd / (double)total); 80 } 81 82 if (st->cond_bwd > 0) { 83 fprintf(fp, "\n%8s: %5.1f%%", 84 "COND_BWD", 85 100.0 * (double)st->cond_bwd / (double)total); 86 } 87 88 if (st->cross_4k > 0) { 89 fprintf(fp, "\n%8s: %5.1f%%", 90 "CROSS_4K", 91 100.0 * (double)st->cross_4k / (double)total); 92 } 93 94 if (st->cross_2m > 0) { 95 fprintf(fp, "\n%8s: %5.1f%%", 96 "CROSS_2M", 97 100.0 * (double)st->cross_2m / (double)total); 98 } 99 100 for (i = 0; i < PERF_BR_MAX; i++) { 101 if (st->counts[i] > 0) 102 fprintf(fp, "\n%8s: %5.1f%%", 103 branch_type_name(i), 104 100.0 * 105 (double)st->counts[i] / (double)total); 106 } 107 } 108 109 static int count_str_scnprintf(int idx, const char *str, char *bf, int size) 110 { 111 return scnprintf(bf, size, "%s%s", (idx) ? " " : " (", str); 112 } 113 114 int branch_type_str(struct branch_type_stat *st, char *bf, int size) 115 { 116 int i, j = 0, printed = 0; 117 u64 total = 0; 118 119 for (i = 0; i < PERF_BR_MAX; i++) 120 total += st->counts[i]; 121 122 if (total == 0) 123 return 0; 124 125 if (st->cond_fwd > 0) 126 printed += count_str_scnprintf(j++, "COND_FWD", bf + printed, size - printed); 127 128 if (st->cond_bwd > 0) 129 printed += count_str_scnprintf(j++, "COND_BWD", bf + printed, size - printed); 130 131 for (i = 0; i < PERF_BR_MAX; i++) { 132 if (i == PERF_BR_COND) 133 continue; 134 135 if (st->counts[i] > 0) 136 printed += count_str_scnprintf(j++, branch_type_name(i), bf + printed, size - printed); 137 } 138 139 if (st->cross_4k > 0) 140 printed += count_str_scnprintf(j++, "CROSS_4K", bf + printed, size - printed); 141 142 if (st->cross_2m > 0) 143 printed += count_str_scnprintf(j++, "CROSS_2M", bf + printed, size - printed); 144 145 return printed; 146 } 147