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