1d3300a3cSArnaldo Carvalho de Melo #include "util/map_symbol.h" 2992c7e92SJin Yao #include "util/branch.h" 38520a98dSArnaldo Carvalho de Melo #include <linux/kernel.h> 4992c7e92SJin Yao 5992c7e92SJin Yao static bool cross_area(u64 addr1, u64 addr2, int size) 6992c7e92SJin Yao { 7992c7e92SJin Yao u64 align1, align2; 8992c7e92SJin Yao 9992c7e92SJin Yao align1 = addr1 & ~(size - 1); 10992c7e92SJin Yao align2 = addr2 & ~(size - 1); 11992c7e92SJin Yao 12992c7e92SJin Yao return (align1 != align2) ? true : false; 13992c7e92SJin Yao } 14992c7e92SJin Yao 15992c7e92SJin Yao #define AREA_4K 4096 16992c7e92SJin Yao #define AREA_2M (2 * 1024 * 1024) 17992c7e92SJin Yao 18992c7e92SJin Yao void branch_type_count(struct branch_type_stat *st, struct branch_flags *flags, 19992c7e92SJin Yao u64 from, u64 to) 20992c7e92SJin Yao { 21992c7e92SJin Yao if (flags->type == PERF_BR_UNKNOWN || from == 0) 22992c7e92SJin Yao return; 23992c7e92SJin Yao 24*0ddea8e2SAnshuman Khandual if (flags->type == PERF_BR_EXTEND_ABI) 25*0ddea8e2SAnshuman Khandual st->new_counts[flags->new_type]++; 26*0ddea8e2SAnshuman Khandual else 27992c7e92SJin Yao st->counts[flags->type]++; 28992c7e92SJin Yao 29992c7e92SJin Yao if (flags->type == PERF_BR_COND) { 30992c7e92SJin Yao if (to > from) 31992c7e92SJin Yao st->cond_fwd++; 32992c7e92SJin Yao else 33992c7e92SJin Yao st->cond_bwd++; 34992c7e92SJin Yao } 35992c7e92SJin Yao 36992c7e92SJin Yao if (cross_area(from, to, AREA_2M)) 37992c7e92SJin Yao st->cross_2m++; 38992c7e92SJin Yao else if (cross_area(from, to, AREA_4K)) 39992c7e92SJin Yao st->cross_4k++; 40992c7e92SJin Yao } 41992c7e92SJin Yao 42*0ddea8e2SAnshuman Khandual const char *branch_new_type_name(int new_type) 43*0ddea8e2SAnshuman Khandual { 44*0ddea8e2SAnshuman Khandual const char *branch_new_names[PERF_BR_NEW_MAX] = { 45*0ddea8e2SAnshuman Khandual "FAULT_ALGN", 46*0ddea8e2SAnshuman Khandual "FAULT_DATA", 47*0ddea8e2SAnshuman Khandual "FAULT_INST", 48*0ddea8e2SAnshuman Khandual "ARCH_1", 49*0ddea8e2SAnshuman Khandual "ARCH_2", 50*0ddea8e2SAnshuman Khandual "ARCH_3", 51*0ddea8e2SAnshuman Khandual "ARCH_4", 52*0ddea8e2SAnshuman Khandual "ARCH_5" 53*0ddea8e2SAnshuman Khandual }; 54*0ddea8e2SAnshuman Khandual 55*0ddea8e2SAnshuman Khandual if (new_type >= 0 && new_type < PERF_BR_NEW_MAX) 56*0ddea8e2SAnshuman Khandual return branch_new_names[new_type]; 57*0ddea8e2SAnshuman Khandual 58*0ddea8e2SAnshuman Khandual return NULL; 59*0ddea8e2SAnshuman Khandual } 60*0ddea8e2SAnshuman Khandual 61992c7e92SJin Yao const char *branch_type_name(int type) 62992c7e92SJin Yao { 63992c7e92SJin Yao const char *branch_names[PERF_BR_MAX] = { 64992c7e92SJin Yao "N/A", 65992c7e92SJin Yao "COND", 66992c7e92SJin Yao "UNCOND", 67992c7e92SJin Yao "IND", 68992c7e92SJin Yao "CALL", 69992c7e92SJin Yao "IND_CALL", 70992c7e92SJin Yao "RET", 71992c7e92SJin Yao "SYSCALL", 72992c7e92SJin Yao "SYSRET", 73992c7e92SJin Yao "COND_CALL", 74cedd3614SAnshuman Khandual "COND_RET", 75cedd3614SAnshuman Khandual "ERET", 761c96b6e4SAnshuman Khandual "IRQ", 771c96b6e4SAnshuman Khandual "SERROR", 78*0ddea8e2SAnshuman Khandual "NO_TX", 79*0ddea8e2SAnshuman Khandual "", // Needed for PERF_BR_EXTEND_ABI that ends up triggering some compiler warnings about NULL deref 80992c7e92SJin Yao }; 81992c7e92SJin Yao 82992c7e92SJin Yao if (type >= 0 && type < PERF_BR_MAX) 83992c7e92SJin Yao return branch_names[type]; 84992c7e92SJin Yao 85992c7e92SJin Yao return NULL; 86992c7e92SJin Yao } 87992c7e92SJin Yao 88*0ddea8e2SAnshuman Khandual const char *get_branch_type(struct branch_entry *e) 89*0ddea8e2SAnshuman Khandual { 90*0ddea8e2SAnshuman Khandual if (e->flags.type == PERF_BR_UNKNOWN) 91*0ddea8e2SAnshuman Khandual return ""; 92*0ddea8e2SAnshuman Khandual 93*0ddea8e2SAnshuman Khandual if (e->flags.type == PERF_BR_EXTEND_ABI) 94*0ddea8e2SAnshuman Khandual return branch_new_type_name(e->flags.new_type); 95*0ddea8e2SAnshuman Khandual 96*0ddea8e2SAnshuman Khandual return branch_type_name(e->flags.type); 97*0ddea8e2SAnshuman Khandual } 98*0ddea8e2SAnshuman Khandual 99992c7e92SJin Yao void branch_type_stat_display(FILE *fp, struct branch_type_stat *st) 100992c7e92SJin Yao { 101992c7e92SJin Yao u64 total = 0; 102992c7e92SJin Yao int i; 103992c7e92SJin Yao 104992c7e92SJin Yao for (i = 0; i < PERF_BR_MAX; i++) 105992c7e92SJin Yao total += st->counts[i]; 106992c7e92SJin Yao 107992c7e92SJin Yao if (total == 0) 108992c7e92SJin Yao return; 109992c7e92SJin Yao 110992c7e92SJin Yao fprintf(fp, "\n#"); 111992c7e92SJin Yao fprintf(fp, "\n# Branch Statistics:"); 112992c7e92SJin Yao fprintf(fp, "\n#"); 113992c7e92SJin Yao 114992c7e92SJin Yao if (st->cond_fwd > 0) { 115992c7e92SJin Yao fprintf(fp, "\n%8s: %5.1f%%", 116992c7e92SJin Yao "COND_FWD", 117992c7e92SJin Yao 100.0 * (double)st->cond_fwd / (double)total); 118992c7e92SJin Yao } 119992c7e92SJin Yao 120992c7e92SJin Yao if (st->cond_bwd > 0) { 121992c7e92SJin Yao fprintf(fp, "\n%8s: %5.1f%%", 122992c7e92SJin Yao "COND_BWD", 123992c7e92SJin Yao 100.0 * (double)st->cond_bwd / (double)total); 124992c7e92SJin Yao } 125992c7e92SJin Yao 126992c7e92SJin Yao if (st->cross_4k > 0) { 127992c7e92SJin Yao fprintf(fp, "\n%8s: %5.1f%%", 128992c7e92SJin Yao "CROSS_4K", 129992c7e92SJin Yao 100.0 * (double)st->cross_4k / (double)total); 130992c7e92SJin Yao } 131992c7e92SJin Yao 132992c7e92SJin Yao if (st->cross_2m > 0) { 133992c7e92SJin Yao fprintf(fp, "\n%8s: %5.1f%%", 134992c7e92SJin Yao "CROSS_2M", 135992c7e92SJin Yao 100.0 * (double)st->cross_2m / (double)total); 136992c7e92SJin Yao } 137992c7e92SJin Yao 138992c7e92SJin Yao for (i = 0; i < PERF_BR_MAX; i++) { 139992c7e92SJin Yao if (st->counts[i] > 0) 140992c7e92SJin Yao fprintf(fp, "\n%8s: %5.1f%%", 141992c7e92SJin Yao branch_type_name(i), 142992c7e92SJin Yao 100.0 * 143992c7e92SJin Yao (double)st->counts[i] / (double)total); 144992c7e92SJin Yao } 145*0ddea8e2SAnshuman Khandual 146*0ddea8e2SAnshuman Khandual for (i = 0; i < PERF_BR_NEW_MAX; i++) { 147*0ddea8e2SAnshuman Khandual if (st->new_counts[i] > 0) 148*0ddea8e2SAnshuman Khandual fprintf(fp, "\n%8s: %5.1f%%", 149*0ddea8e2SAnshuman Khandual branch_new_type_name(i), 150*0ddea8e2SAnshuman Khandual 100.0 * 151*0ddea8e2SAnshuman Khandual (double)st->new_counts[i] / (double)total); 152*0ddea8e2SAnshuman Khandual } 153*0ddea8e2SAnshuman Khandual 154992c7e92SJin Yao } 155992c7e92SJin Yao 156992c7e92SJin Yao static int count_str_scnprintf(int idx, const char *str, char *bf, int size) 157992c7e92SJin Yao { 158992c7e92SJin Yao return scnprintf(bf, size, "%s%s", (idx) ? " " : " (", str); 159992c7e92SJin Yao } 160992c7e92SJin Yao 161992c7e92SJin Yao int branch_type_str(struct branch_type_stat *st, char *bf, int size) 162992c7e92SJin Yao { 163992c7e92SJin Yao int i, j = 0, printed = 0; 164992c7e92SJin Yao u64 total = 0; 165992c7e92SJin Yao 166992c7e92SJin Yao for (i = 0; i < PERF_BR_MAX; i++) 167992c7e92SJin Yao total += st->counts[i]; 168992c7e92SJin Yao 169*0ddea8e2SAnshuman Khandual for (i = 0; i < PERF_BR_NEW_MAX; i++) 170*0ddea8e2SAnshuman Khandual total += st->new_counts[i]; 171*0ddea8e2SAnshuman Khandual 172992c7e92SJin Yao if (total == 0) 173992c7e92SJin Yao return 0; 174992c7e92SJin Yao 175992c7e92SJin Yao if (st->cond_fwd > 0) 176992c7e92SJin Yao printed += count_str_scnprintf(j++, "COND_FWD", bf + printed, size - printed); 177992c7e92SJin Yao 178992c7e92SJin Yao if (st->cond_bwd > 0) 179992c7e92SJin Yao printed += count_str_scnprintf(j++, "COND_BWD", bf + printed, size - printed); 180992c7e92SJin Yao 181992c7e92SJin Yao for (i = 0; i < PERF_BR_MAX; i++) { 182992c7e92SJin Yao if (i == PERF_BR_COND) 183992c7e92SJin Yao continue; 184992c7e92SJin Yao 185992c7e92SJin Yao if (st->counts[i] > 0) 186992c7e92SJin Yao printed += count_str_scnprintf(j++, branch_type_name(i), bf + printed, size - printed); 187992c7e92SJin Yao } 188992c7e92SJin Yao 189*0ddea8e2SAnshuman Khandual for (i = 0; i < PERF_BR_NEW_MAX; i++) { 190*0ddea8e2SAnshuman Khandual if (st->new_counts[i] > 0) 191*0ddea8e2SAnshuman Khandual printed += count_str_scnprintf(j++, branch_new_type_name(i), bf + printed, size - printed); 192*0ddea8e2SAnshuman Khandual } 193*0ddea8e2SAnshuman Khandual 194992c7e92SJin Yao if (st->cross_4k > 0) 195992c7e92SJin Yao printed += count_str_scnprintf(j++, "CROSS_4K", bf + printed, size - printed); 196992c7e92SJin Yao 197992c7e92SJin Yao if (st->cross_2m > 0) 198992c7e92SJin Yao printed += count_str_scnprintf(j++, "CROSS_2M", bf + printed, size - printed); 199992c7e92SJin Yao 200992c7e92SJin Yao return printed; 201992c7e92SJin Yao } 202