1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 2ce1e22b0SJiri Olsa #include <stddef.h> 3ce1e22b0SJiri Olsa #include <stdlib.h> 4ce1e22b0SJiri Olsa #include <string.h> 5ce1e22b0SJiri Olsa #include <errno.h> 654fbad54SJiri Olsa #include <sys/types.h> 754fbad54SJiri Olsa #include <sys/stat.h> 854fbad54SJiri Olsa #include <unistd.h> 954fbad54SJiri Olsa #include <api/fs/fs.h> 10877a7a11SArnaldo Carvalho de Melo #include <linux/kernel.h> 11d3300a3cSArnaldo Carvalho de Melo #include "map_symbol.h" 12acbe613eSJiri Olsa #include "mem-events.h" 13ce1e22b0SJiri Olsa #include "debug.h" 140c877d75SJiri Olsa #include "symbol.h" 15e7ce8d11SJin Yao #include "pmu.h" 16e7ce8d11SJin Yao #include "pmu-hybrid.h" 17acbe613eSJiri Olsa 18b0d745b3SJiri Olsa unsigned int perf_mem_events__loads_ldlat = 30; 19b0d745b3SJiri Olsa 2054fbad54SJiri Olsa #define E(t, n, s) { .tag = t, .name = n, .sysfs_name = s } 21acbe613eSJiri Olsa 22eaf6aaeeSLeo Yan static struct perf_mem_event perf_mem_events[PERF_MEM_EVENTS__MAX] = { 23f9f16dfbSLeo Yan E("ldlat-loads", "cpu/mem-loads,ldlat=%u/P", "cpu/events/mem-loads"), 24f9f16dfbSLeo Yan E("ldlat-stores", "cpu/mem-stores/P", "cpu/events/mem-stores"), 254ba2452cSLeo Yan E(NULL, NULL, NULL), 26acbe613eSJiri Olsa }; 2754fbad54SJiri Olsa #undef E 28acbe613eSJiri Olsa 29b0d745b3SJiri Olsa static char mem_loads_name[100]; 30b0d745b3SJiri Olsa static bool mem_loads_name__init; 31b0d745b3SJiri Olsa 32eaf6aaeeSLeo Yan struct perf_mem_event * __weak perf_mem_events__ptr(int i) 33eaf6aaeeSLeo Yan { 34eaf6aaeeSLeo Yan if (i >= PERF_MEM_EVENTS__MAX) 35eaf6aaeeSLeo Yan return NULL; 36eaf6aaeeSLeo Yan 37eaf6aaeeSLeo Yan return &perf_mem_events[i]; 38eaf6aaeeSLeo Yan } 39eaf6aaeeSLeo Yan 40d2f327acSJin Yao char * __weak perf_mem_events__name(int i, char *pmu_name __maybe_unused) 412ba7ac58SJiri Olsa { 42eaf6aaeeSLeo Yan struct perf_mem_event *e = perf_mem_events__ptr(i); 43eaf6aaeeSLeo Yan 44eaf6aaeeSLeo Yan if (!e) 45eaf6aaeeSLeo Yan return NULL; 46eaf6aaeeSLeo Yan 47b0d745b3SJiri Olsa if (i == PERF_MEM_EVENTS__LOAD) { 48b0d745b3SJiri Olsa if (!mem_loads_name__init) { 49b0d745b3SJiri Olsa mem_loads_name__init = true; 50b0d745b3SJiri Olsa scnprintf(mem_loads_name, sizeof(mem_loads_name), 51eaf6aaeeSLeo Yan e->name, perf_mem_events__loads_ldlat); 52b0d745b3SJiri Olsa } 53b0d745b3SJiri Olsa return mem_loads_name; 54b0d745b3SJiri Olsa } 55b0d745b3SJiri Olsa 56eaf6aaeeSLeo Yan return (char *)e->name; 572ba7ac58SJiri Olsa } 582ba7ac58SJiri Olsa 592a57d408SKan Liang __weak bool is_mem_loads_aux_event(struct evsel *leader __maybe_unused) 602a57d408SKan Liang { 612a57d408SKan Liang return false; 622a57d408SKan Liang } 632a57d408SKan Liang 64ce1e22b0SJiri Olsa int perf_mem_events__parse(const char *str) 65ce1e22b0SJiri Olsa { 66ce1e22b0SJiri Olsa char *tok, *saveptr = NULL; 67ce1e22b0SJiri Olsa bool found = false; 68ce1e22b0SJiri Olsa char *buf; 69ce1e22b0SJiri Olsa int j; 70ce1e22b0SJiri Olsa 71ce1e22b0SJiri Olsa /* We need buffer that we know we can write to. */ 72ce1e22b0SJiri Olsa buf = malloc(strlen(str) + 1); 73ce1e22b0SJiri Olsa if (!buf) 74ce1e22b0SJiri Olsa return -ENOMEM; 75ce1e22b0SJiri Olsa 76ce1e22b0SJiri Olsa strcpy(buf, str); 77ce1e22b0SJiri Olsa 78ce1e22b0SJiri Olsa tok = strtok_r((char *)buf, ",", &saveptr); 79ce1e22b0SJiri Olsa 80ce1e22b0SJiri Olsa while (tok) { 81ce1e22b0SJiri Olsa for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) { 82eaf6aaeeSLeo Yan struct perf_mem_event *e = perf_mem_events__ptr(j); 83ce1e22b0SJiri Olsa 844ba2452cSLeo Yan if (!e->tag) 854ba2452cSLeo Yan continue; 864ba2452cSLeo Yan 87ce1e22b0SJiri Olsa if (strstr(e->tag, tok)) 88ce1e22b0SJiri Olsa e->record = found = true; 89ce1e22b0SJiri Olsa } 90ce1e22b0SJiri Olsa 91ce1e22b0SJiri Olsa tok = strtok_r(NULL, ",", &saveptr); 92ce1e22b0SJiri Olsa } 93ce1e22b0SJiri Olsa 94ce1e22b0SJiri Olsa free(buf); 95ce1e22b0SJiri Olsa 96ce1e22b0SJiri Olsa if (found) 97ce1e22b0SJiri Olsa return 0; 98ce1e22b0SJiri Olsa 99ce1e22b0SJiri Olsa pr_err("failed: event '%s' not found, use '-e list' to get list of available events\n", str); 100ce1e22b0SJiri Olsa return -1; 101ce1e22b0SJiri Olsa } 10254fbad54SJiri Olsa 103e7ce8d11SJin Yao static bool perf_mem_event__supported(const char *mnt, char *sysfs_name) 104e7ce8d11SJin Yao { 105e7ce8d11SJin Yao char path[PATH_MAX]; 106e7ce8d11SJin Yao struct stat st; 107e7ce8d11SJin Yao 108e7ce8d11SJin Yao scnprintf(path, PATH_MAX, "%s/devices/%s", mnt, sysfs_name); 109e7ce8d11SJin Yao return !stat(path, &st); 110e7ce8d11SJin Yao } 111e7ce8d11SJin Yao 11254fbad54SJiri Olsa int perf_mem_events__init(void) 11354fbad54SJiri Olsa { 11454fbad54SJiri Olsa const char *mnt = sysfs__mount(); 11554fbad54SJiri Olsa bool found = false; 11654fbad54SJiri Olsa int j; 11754fbad54SJiri Olsa 11854fbad54SJiri Olsa if (!mnt) 11954fbad54SJiri Olsa return -ENOENT; 12054fbad54SJiri Olsa 12154fbad54SJiri Olsa for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) { 122eaf6aaeeSLeo Yan struct perf_mem_event *e = perf_mem_events__ptr(j); 123e7ce8d11SJin Yao struct perf_pmu *pmu; 124e7ce8d11SJin Yao char sysfs_name[100]; 12554fbad54SJiri Olsa 1264ba2452cSLeo Yan /* 1274ba2452cSLeo Yan * If the event entry isn't valid, skip initialization 1284ba2452cSLeo Yan * and "e->supported" will keep false. 1294ba2452cSLeo Yan */ 1304ba2452cSLeo Yan if (!e->tag) 1314ba2452cSLeo Yan continue; 1324ba2452cSLeo Yan 133e7ce8d11SJin Yao if (!perf_pmu__has_hybrid()) { 134e7ce8d11SJin Yao scnprintf(sysfs_name, sizeof(sysfs_name), 135e7ce8d11SJin Yao e->sysfs_name, "cpu"); 136e7ce8d11SJin Yao e->supported = perf_mem_event__supported(mnt, sysfs_name); 137e7ce8d11SJin Yao } else { 138e7ce8d11SJin Yao perf_pmu__for_each_hybrid_pmu(pmu) { 139e7ce8d11SJin Yao scnprintf(sysfs_name, sizeof(sysfs_name), 140e7ce8d11SJin Yao e->sysfs_name, pmu->name); 141e7ce8d11SJin Yao e->supported |= perf_mem_event__supported(mnt, sysfs_name); 142e7ce8d11SJin Yao } 143e7ce8d11SJin Yao } 14454fbad54SJiri Olsa 145e7ce8d11SJin Yao if (e->supported) 146e7ce8d11SJin Yao found = true; 14754fbad54SJiri Olsa } 14854fbad54SJiri Olsa 14954fbad54SJiri Olsa return found ? 0 : -ENOENT; 15054fbad54SJiri Olsa } 1510c877d75SJiri Olsa 152b027cc6fSIan Rogers void perf_mem_events__list(void) 153b027cc6fSIan Rogers { 154b027cc6fSIan Rogers int j; 155b027cc6fSIan Rogers 156b027cc6fSIan Rogers for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) { 157eaf6aaeeSLeo Yan struct perf_mem_event *e = perf_mem_events__ptr(j); 158b027cc6fSIan Rogers 159b027cc6fSIan Rogers fprintf(stderr, "%-13s%-*s%s\n", 1604ba2452cSLeo Yan e->tag ?: "", 161b027cc6fSIan Rogers verbose > 0 ? 25 : 0, 162d2f327acSJin Yao verbose > 0 ? perf_mem_events__name(j, NULL) : "", 163b027cc6fSIan Rogers e->supported ? ": available" : ""); 164b027cc6fSIan Rogers } 165b027cc6fSIan Rogers } 166b027cc6fSIan Rogers 1674a9086adSJin Yao static void perf_mem_events__print_unsupport_hybrid(struct perf_mem_event *e, 1684a9086adSJin Yao int idx) 1694a9086adSJin Yao { 1704a9086adSJin Yao const char *mnt = sysfs__mount(); 1714a9086adSJin Yao char sysfs_name[100]; 1724a9086adSJin Yao struct perf_pmu *pmu; 1734a9086adSJin Yao 1744a9086adSJin Yao perf_pmu__for_each_hybrid_pmu(pmu) { 1754a9086adSJin Yao scnprintf(sysfs_name, sizeof(sysfs_name), e->sysfs_name, 1764a9086adSJin Yao pmu->name); 1774a9086adSJin Yao if (!perf_mem_event__supported(mnt, sysfs_name)) { 1784a9086adSJin Yao pr_err("failed: event '%s' not supported\n", 1794a9086adSJin Yao perf_mem_events__name(idx, pmu->name)); 1804a9086adSJin Yao } 1814a9086adSJin Yao } 1824a9086adSJin Yao } 1834a9086adSJin Yao 1844a9086adSJin Yao int perf_mem_events__record_args(const char **rec_argv, int *argv_nr, 1854a9086adSJin Yao char **rec_tmp, int *tmp_nr) 1864a9086adSJin Yao { 1874a9086adSJin Yao int i = *argv_nr, k = 0; 1884a9086adSJin Yao struct perf_mem_event *e; 1894a9086adSJin Yao struct perf_pmu *pmu; 1904a9086adSJin Yao char *s; 1914a9086adSJin Yao 1924a9086adSJin Yao for (int j = 0; j < PERF_MEM_EVENTS__MAX; j++) { 1934a9086adSJin Yao e = perf_mem_events__ptr(j); 1944a9086adSJin Yao if (!e->record) 1954a9086adSJin Yao continue; 1964a9086adSJin Yao 1974a9086adSJin Yao if (!perf_pmu__has_hybrid()) { 1984a9086adSJin Yao if (!e->supported) { 1994a9086adSJin Yao pr_err("failed: event '%s' not supported\n", 2004a9086adSJin Yao perf_mem_events__name(j, NULL)); 2014a9086adSJin Yao return -1; 2024a9086adSJin Yao } 2034a9086adSJin Yao 2044a9086adSJin Yao rec_argv[i++] = "-e"; 2054a9086adSJin Yao rec_argv[i++] = perf_mem_events__name(j, NULL); 2064a9086adSJin Yao } else { 2074a9086adSJin Yao if (!e->supported) { 2084a9086adSJin Yao perf_mem_events__print_unsupport_hybrid(e, j); 2094a9086adSJin Yao return -1; 2104a9086adSJin Yao } 2114a9086adSJin Yao 2124a9086adSJin Yao perf_pmu__for_each_hybrid_pmu(pmu) { 2134a9086adSJin Yao rec_argv[i++] = "-e"; 2144a9086adSJin Yao s = perf_mem_events__name(j, pmu->name); 2154a9086adSJin Yao if (s) { 2164a9086adSJin Yao s = strdup(s); 2174a9086adSJin Yao if (!s) 2184a9086adSJin Yao return -1; 2194a9086adSJin Yao 2204a9086adSJin Yao rec_argv[i++] = s; 2214a9086adSJin Yao rec_tmp[k++] = s; 2224a9086adSJin Yao } 2234a9086adSJin Yao } 2244a9086adSJin Yao } 2254a9086adSJin Yao } 2264a9086adSJin Yao 2274a9086adSJin Yao *argv_nr = i; 2284a9086adSJin Yao *tmp_nr = k; 2294a9086adSJin Yao return 0; 2304a9086adSJin Yao } 2314a9086adSJin Yao 2320c877d75SJiri Olsa static const char * const tlb_access[] = { 2330c877d75SJiri Olsa "N/A", 2340c877d75SJiri Olsa "HIT", 2350c877d75SJiri Olsa "MISS", 2360c877d75SJiri Olsa "L1", 2370c877d75SJiri Olsa "L2", 2380c877d75SJiri Olsa "Walker", 2390c877d75SJiri Olsa "Fault", 2400c877d75SJiri Olsa }; 2410c877d75SJiri Olsa 242b1a5fbeaSJiri Olsa int perf_mem__tlb_scnprintf(char *out, size_t sz, struct mem_info *mem_info) 2430c877d75SJiri Olsa { 2440c877d75SJiri Olsa size_t l = 0, i; 2450c877d75SJiri Olsa u64 m = PERF_MEM_TLB_NA; 2460c877d75SJiri Olsa u64 hit, miss; 2470c877d75SJiri Olsa 2480c877d75SJiri Olsa sz -= 1; /* -1 for null termination */ 2490c877d75SJiri Olsa out[0] = '\0'; 2500c877d75SJiri Olsa 2510c877d75SJiri Olsa if (mem_info) 2520c877d75SJiri Olsa m = mem_info->data_src.mem_dtlb; 2530c877d75SJiri Olsa 2540c877d75SJiri Olsa hit = m & PERF_MEM_TLB_HIT; 2550c877d75SJiri Olsa miss = m & PERF_MEM_TLB_MISS; 2560c877d75SJiri Olsa 2570c877d75SJiri Olsa /* already taken care of */ 2580c877d75SJiri Olsa m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS); 2590c877d75SJiri Olsa 2600c877d75SJiri Olsa for (i = 0; m && i < ARRAY_SIZE(tlb_access); i++, m >>= 1) { 2610c877d75SJiri Olsa if (!(m & 0x1)) 2620c877d75SJiri Olsa continue; 2630c877d75SJiri Olsa if (l) { 2640c877d75SJiri Olsa strcat(out, " or "); 2650c877d75SJiri Olsa l += 4; 2660c877d75SJiri Olsa } 267b1a5fbeaSJiri Olsa l += scnprintf(out + l, sz - l, tlb_access[i]); 2680c877d75SJiri Olsa } 2690c877d75SJiri Olsa if (*out == '\0') 270b1a5fbeaSJiri Olsa l += scnprintf(out, sz - l, "N/A"); 2710c877d75SJiri Olsa if (hit) 272b1a5fbeaSJiri Olsa l += scnprintf(out + l, sz - l, " hit"); 2730c877d75SJiri Olsa if (miss) 274b1a5fbeaSJiri Olsa l += scnprintf(out + l, sz - l, " miss"); 275b1a5fbeaSJiri Olsa 276b1a5fbeaSJiri Olsa return l; 2770c877d75SJiri Olsa } 278071e9a1eSJiri Olsa 279071e9a1eSJiri Olsa static const char * const mem_lvl[] = { 280071e9a1eSJiri Olsa "N/A", 281071e9a1eSJiri Olsa "HIT", 282071e9a1eSJiri Olsa "MISS", 283071e9a1eSJiri Olsa "L1", 284071e9a1eSJiri Olsa "LFB", 285071e9a1eSJiri Olsa "L2", 286071e9a1eSJiri Olsa "L3", 287071e9a1eSJiri Olsa "Local RAM", 288071e9a1eSJiri Olsa "Remote RAM (1 hop)", 289071e9a1eSJiri Olsa "Remote RAM (2 hops)", 290071e9a1eSJiri Olsa "Remote Cache (1 hop)", 291071e9a1eSJiri Olsa "Remote Cache (2 hops)", 292071e9a1eSJiri Olsa "I/O", 293071e9a1eSJiri Olsa "Uncached", 294071e9a1eSJiri Olsa }; 295071e9a1eSJiri Olsa 29652839e65SAndi Kleen static const char * const mem_lvlnum[] = { 29752839e65SAndi Kleen [PERF_MEM_LVLNUM_ANY_CACHE] = "Any cache", 29852839e65SAndi Kleen [PERF_MEM_LVLNUM_LFB] = "LFB", 29952839e65SAndi Kleen [PERF_MEM_LVLNUM_RAM] = "RAM", 30052839e65SAndi Kleen [PERF_MEM_LVLNUM_PMEM] = "PMEM", 30152839e65SAndi Kleen [PERF_MEM_LVLNUM_NA] = "N/A", 30252839e65SAndi Kleen }; 30352839e65SAndi Kleen 304cae1d759SKajol Jain static const char * const mem_hops[] = { 305cae1d759SKajol Jain "N/A", 306cae1d759SKajol Jain /* 307cae1d759SKajol Jain * While printing, 'Remote' will be added to represent 308cae1d759SKajol Jain * 'Remote core, same node' accesses as remote field need 309cae1d759SKajol Jain * to be set with mem_hops field. 310cae1d759SKajol Jain */ 311cae1d759SKajol Jain "core, same node", 3127fbddf40SKajol Jain "node, same socket", 3137fbddf40SKajol Jain "socket, same board", 3147fbddf40SKajol Jain "board", 315cae1d759SKajol Jain }; 316cae1d759SKajol Jain 317fdefc375SLeo Yan static int perf_mem__op_scnprintf(char *out, size_t sz, struct mem_info *mem_info) 318fdefc375SLeo Yan { 319fdefc375SLeo Yan u64 op = PERF_MEM_LOCK_NA; 320fdefc375SLeo Yan int l; 321fdefc375SLeo Yan 322fdefc375SLeo Yan if (mem_info) 323fdefc375SLeo Yan op = mem_info->data_src.mem_op; 324fdefc375SLeo Yan 325fdefc375SLeo Yan if (op & PERF_MEM_OP_NA) 326fdefc375SLeo Yan l = scnprintf(out, sz, "N/A"); 327fdefc375SLeo Yan else if (op & PERF_MEM_OP_LOAD) 328fdefc375SLeo Yan l = scnprintf(out, sz, "LOAD"); 329fdefc375SLeo Yan else if (op & PERF_MEM_OP_STORE) 330fdefc375SLeo Yan l = scnprintf(out, sz, "STORE"); 331fdefc375SLeo Yan else if (op & PERF_MEM_OP_PFETCH) 332fdefc375SLeo Yan l = scnprintf(out, sz, "PFETCH"); 333fdefc375SLeo Yan else if (op & PERF_MEM_OP_EXEC) 334fdefc375SLeo Yan l = scnprintf(out, sz, "EXEC"); 335fdefc375SLeo Yan else 336fdefc375SLeo Yan l = scnprintf(out, sz, "No"); 337fdefc375SLeo Yan 338fdefc375SLeo Yan return l; 339fdefc375SLeo Yan } 340fdefc375SLeo Yan 34196907563SJiri Olsa int perf_mem__lvl_scnprintf(char *out, size_t sz, struct mem_info *mem_info) 342071e9a1eSJiri Olsa { 343071e9a1eSJiri Olsa size_t i, l = 0; 344071e9a1eSJiri Olsa u64 m = PERF_MEM_LVL_NA; 345071e9a1eSJiri Olsa u64 hit, miss; 3467fbddf40SKajol Jain int printed = 0; 347071e9a1eSJiri Olsa 348071e9a1eSJiri Olsa if (mem_info) 349071e9a1eSJiri Olsa m = mem_info->data_src.mem_lvl; 350071e9a1eSJiri Olsa 351071e9a1eSJiri Olsa sz -= 1; /* -1 for null termination */ 352071e9a1eSJiri Olsa out[0] = '\0'; 353071e9a1eSJiri Olsa 354071e9a1eSJiri Olsa hit = m & PERF_MEM_LVL_HIT; 355071e9a1eSJiri Olsa miss = m & PERF_MEM_LVL_MISS; 356071e9a1eSJiri Olsa 357071e9a1eSJiri Olsa /* already taken care of */ 358071e9a1eSJiri Olsa m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS); 359071e9a1eSJiri Olsa 36052839e65SAndi Kleen if (mem_info && mem_info->data_src.mem_remote) { 36152839e65SAndi Kleen strcat(out, "Remote "); 36252839e65SAndi Kleen l += 7; 36352839e65SAndi Kleen } 36452839e65SAndi Kleen 3657fbddf40SKajol Jain /* 3667fbddf40SKajol Jain * Incase mem_hops field is set, we can skip printing data source via 3677fbddf40SKajol Jain * PERF_MEM_LVL namespace. 3687fbddf40SKajol Jain */ 3697fbddf40SKajol Jain if (mem_info && mem_info->data_src.mem_hops) { 370cae1d759SKajol Jain l += scnprintf(out + l, sz - l, "%s ", mem_hops[mem_info->data_src.mem_hops]); 3717fbddf40SKajol Jain } else { 372071e9a1eSJiri Olsa for (i = 0; m && i < ARRAY_SIZE(mem_lvl); i++, m >>= 1) { 373071e9a1eSJiri Olsa if (!(m & 0x1)) 374071e9a1eSJiri Olsa continue; 37552839e65SAndi Kleen if (printed++) { 376071e9a1eSJiri Olsa strcat(out, " or "); 377071e9a1eSJiri Olsa l += 4; 378071e9a1eSJiri Olsa } 37996907563SJiri Olsa l += scnprintf(out + l, sz - l, mem_lvl[i]); 380071e9a1eSJiri Olsa } 3817fbddf40SKajol Jain } 38252839e65SAndi Kleen 38352839e65SAndi Kleen if (mem_info && mem_info->data_src.mem_lvl_num) { 38452839e65SAndi Kleen int lvl = mem_info->data_src.mem_lvl_num; 38552839e65SAndi Kleen if (printed++) { 38652839e65SAndi Kleen strcat(out, " or "); 38752839e65SAndi Kleen l += 4; 38852839e65SAndi Kleen } 38952839e65SAndi Kleen if (mem_lvlnum[lvl]) 39052839e65SAndi Kleen l += scnprintf(out + l, sz - l, mem_lvlnum[lvl]); 39152839e65SAndi Kleen else 39252839e65SAndi Kleen l += scnprintf(out + l, sz - l, "L%d", lvl); 39352839e65SAndi Kleen } 39452839e65SAndi Kleen 39552839e65SAndi Kleen if (l == 0) 39652839e65SAndi Kleen l += scnprintf(out + l, sz - l, "N/A"); 397071e9a1eSJiri Olsa if (hit) 39896907563SJiri Olsa l += scnprintf(out + l, sz - l, " hit"); 399071e9a1eSJiri Olsa if (miss) 40096907563SJiri Olsa l += scnprintf(out + l, sz - l, " miss"); 40196907563SJiri Olsa 40296907563SJiri Olsa return l; 403071e9a1eSJiri Olsa } 4042c07af13SJiri Olsa 4052c07af13SJiri Olsa static const char * const snoop_access[] = { 4062c07af13SJiri Olsa "N/A", 4072c07af13SJiri Olsa "None", 4082c07af13SJiri Olsa "Hit", 409166ebdd2SAndi Kleen "Miss", 4102c07af13SJiri Olsa "HitM", 4112c07af13SJiri Olsa }; 4122c07af13SJiri Olsa 413149d7507SJiri Olsa int perf_mem__snp_scnprintf(char *out, size_t sz, struct mem_info *mem_info) 4142c07af13SJiri Olsa { 4152c07af13SJiri Olsa size_t i, l = 0; 4162c07af13SJiri Olsa u64 m = PERF_MEM_SNOOP_NA; 4172c07af13SJiri Olsa 4182c07af13SJiri Olsa sz -= 1; /* -1 for null termination */ 4192c07af13SJiri Olsa out[0] = '\0'; 4202c07af13SJiri Olsa 4212c07af13SJiri Olsa if (mem_info) 4222c07af13SJiri Olsa m = mem_info->data_src.mem_snoop; 4232c07af13SJiri Olsa 4242c07af13SJiri Olsa for (i = 0; m && i < ARRAY_SIZE(snoop_access); i++, m >>= 1) { 4252c07af13SJiri Olsa if (!(m & 0x1)) 4262c07af13SJiri Olsa continue; 4272c07af13SJiri Olsa if (l) { 4282c07af13SJiri Olsa strcat(out, " or "); 4292c07af13SJiri Olsa l += 4; 4302c07af13SJiri Olsa } 431149d7507SJiri Olsa l += scnprintf(out + l, sz - l, snoop_access[i]); 4322c07af13SJiri Olsa } 43352839e65SAndi Kleen if (mem_info && 43452839e65SAndi Kleen (mem_info->data_src.mem_snoopx & PERF_MEM_SNOOPX_FWD)) { 43552839e65SAndi Kleen if (l) { 43652839e65SAndi Kleen strcat(out, " or "); 43752839e65SAndi Kleen l += 4; 43852839e65SAndi Kleen } 43952839e65SAndi Kleen l += scnprintf(out + l, sz - l, "Fwd"); 44052839e65SAndi Kleen } 4412c07af13SJiri Olsa 4422c07af13SJiri Olsa if (*out == '\0') 443149d7507SJiri Olsa l += scnprintf(out, sz - l, "N/A"); 444149d7507SJiri Olsa 445149d7507SJiri Olsa return l; 4462c07af13SJiri Olsa } 44769a77275SJiri Olsa 4488b0819c8SJiri Olsa int perf_mem__lck_scnprintf(char *out, size_t sz, struct mem_info *mem_info) 44969a77275SJiri Olsa { 45069a77275SJiri Olsa u64 mask = PERF_MEM_LOCK_NA; 4518b0819c8SJiri Olsa int l; 45269a77275SJiri Olsa 45369a77275SJiri Olsa if (mem_info) 45469a77275SJiri Olsa mask = mem_info->data_src.mem_lock; 45569a77275SJiri Olsa 45669a77275SJiri Olsa if (mask & PERF_MEM_LOCK_NA) 4578b0819c8SJiri Olsa l = scnprintf(out, sz, "N/A"); 45869a77275SJiri Olsa else if (mask & PERF_MEM_LOCK_LOCKED) 4598b0819c8SJiri Olsa l = scnprintf(out, sz, "Yes"); 46069a77275SJiri Olsa else 4618b0819c8SJiri Olsa l = scnprintf(out, sz, "No"); 4628b0819c8SJiri Olsa 4638b0819c8SJiri Olsa return l; 46469a77275SJiri Olsa } 465c19ac912SJiri Olsa 466a054c298SKan Liang int perf_mem__blk_scnprintf(char *out, size_t sz, struct mem_info *mem_info) 467a054c298SKan Liang { 468a054c298SKan Liang size_t l = 0; 469a054c298SKan Liang u64 mask = PERF_MEM_BLK_NA; 470a054c298SKan Liang 471a054c298SKan Liang sz -= 1; /* -1 for null termination */ 472a054c298SKan Liang out[0] = '\0'; 473a054c298SKan Liang 474a054c298SKan Liang if (mem_info) 475a054c298SKan Liang mask = mem_info->data_src.mem_blk; 476a054c298SKan Liang 477a054c298SKan Liang if (!mask || (mask & PERF_MEM_BLK_NA)) { 478a054c298SKan Liang l += scnprintf(out + l, sz - l, " N/A"); 479a054c298SKan Liang return l; 480a054c298SKan Liang } 481a054c298SKan Liang if (mask & PERF_MEM_BLK_DATA) 482a054c298SKan Liang l += scnprintf(out + l, sz - l, " Data"); 483a054c298SKan Liang if (mask & PERF_MEM_BLK_ADDR) 484a054c298SKan Liang l += scnprintf(out + l, sz - l, " Addr"); 485a054c298SKan Liang 486a054c298SKan Liang return l; 487a054c298SKan Liang } 488a054c298SKan Liang 489c19ac912SJiri Olsa int perf_script__meminfo_scnprintf(char *out, size_t sz, struct mem_info *mem_info) 490c19ac912SJiri Olsa { 491c19ac912SJiri Olsa int i = 0; 492c19ac912SJiri Olsa 493fdefc375SLeo Yan i += scnprintf(out, sz, "|OP "); 494fdefc375SLeo Yan i += perf_mem__op_scnprintf(out + i, sz - i, mem_info); 495fdefc375SLeo Yan i += scnprintf(out + i, sz - i, "|LVL "); 496fdefc375SLeo Yan i += perf_mem__lvl_scnprintf(out + i, sz, mem_info); 497c19ac912SJiri Olsa i += scnprintf(out + i, sz - i, "|SNP "); 498c19ac912SJiri Olsa i += perf_mem__snp_scnprintf(out + i, sz - i, mem_info); 499c19ac912SJiri Olsa i += scnprintf(out + i, sz - i, "|TLB "); 500c19ac912SJiri Olsa i += perf_mem__tlb_scnprintf(out + i, sz - i, mem_info); 501c19ac912SJiri Olsa i += scnprintf(out + i, sz - i, "|LCK "); 502c19ac912SJiri Olsa i += perf_mem__lck_scnprintf(out + i, sz - i, mem_info); 503a054c298SKan Liang i += scnprintf(out + i, sz - i, "|BLK "); 504a054c298SKan Liang i += perf_mem__blk_scnprintf(out + i, sz - i, mem_info); 505c19ac912SJiri Olsa 506c19ac912SJiri Olsa return i; 507c19ac912SJiri Olsa } 508aadddd68SJiri Olsa 509aadddd68SJiri Olsa int c2c_decode_stats(struct c2c_stats *stats, struct mem_info *mi) 510aadddd68SJiri Olsa { 511aadddd68SJiri Olsa union perf_mem_data_src *data_src = &mi->data_src; 512aadddd68SJiri Olsa u64 daddr = mi->daddr.addr; 513aadddd68SJiri Olsa u64 op = data_src->mem_op; 514aadddd68SJiri Olsa u64 lvl = data_src->mem_lvl; 515aadddd68SJiri Olsa u64 snoop = data_src->mem_snoop; 516aadddd68SJiri Olsa u64 lock = data_src->mem_lock; 517d9d5d767SKan Liang u64 blk = data_src->mem_blk; 51812c15302SJiri Olsa /* 51912c15302SJiri Olsa * Skylake might report unknown remote level via this 52012c15302SJiri Olsa * bit, consider it when evaluating remote HITMs. 521cae1d759SKajol Jain * 522cae1d759SKajol Jain * Incase of power, remote field can also be used to denote cache 523cae1d759SKajol Jain * accesses from the another core of same node. Hence, setting 524cae1d759SKajol Jain * mrem only when HOPS is zero along with set remote field. 52512c15302SJiri Olsa */ 526cae1d759SKajol Jain bool mrem = (data_src->mem_remote && !data_src->mem_hops); 527aadddd68SJiri Olsa int err = 0; 528aadddd68SJiri Olsa 529dba8ab93SJiri Olsa #define HITM_INC(__f) \ 530dba8ab93SJiri Olsa do { \ 531dba8ab93SJiri Olsa stats->__f++; \ 532dba8ab93SJiri Olsa stats->tot_hitm++; \ 533dba8ab93SJiri Olsa } while (0) 534dba8ab93SJiri Olsa 535aadddd68SJiri Olsa #define P(a, b) PERF_MEM_##a##_##b 536aadddd68SJiri Olsa 537aadddd68SJiri Olsa stats->nr_entries++; 538aadddd68SJiri Olsa 539aadddd68SJiri Olsa if (lock & P(LOCK, LOCKED)) stats->locks++; 540aadddd68SJiri Olsa 541d9d5d767SKan Liang if (blk & P(BLK, DATA)) stats->blk_data++; 542d9d5d767SKan Liang if (blk & P(BLK, ADDR)) stats->blk_addr++; 543d9d5d767SKan Liang 544aadddd68SJiri Olsa if (op & P(OP, LOAD)) { 545aadddd68SJiri Olsa /* load */ 546aadddd68SJiri Olsa stats->load++; 547aadddd68SJiri Olsa 548aadddd68SJiri Olsa if (!daddr) { 549aadddd68SJiri Olsa stats->ld_noadrs++; 550aadddd68SJiri Olsa return -1; 551aadddd68SJiri Olsa } 552aadddd68SJiri Olsa 553aadddd68SJiri Olsa if (lvl & P(LVL, HIT)) { 554aadddd68SJiri Olsa if (lvl & P(LVL, UNC)) stats->ld_uncache++; 555aadddd68SJiri Olsa if (lvl & P(LVL, IO)) stats->ld_io++; 556aadddd68SJiri Olsa if (lvl & P(LVL, LFB)) stats->ld_fbhit++; 557aadddd68SJiri Olsa if (lvl & P(LVL, L1 )) stats->ld_l1hit++; 558aadddd68SJiri Olsa if (lvl & P(LVL, L2 )) stats->ld_l2hit++; 559aadddd68SJiri Olsa if (lvl & P(LVL, L3 )) { 560aadddd68SJiri Olsa if (snoop & P(SNOOP, HITM)) 561dba8ab93SJiri Olsa HITM_INC(lcl_hitm); 562aadddd68SJiri Olsa else 563aadddd68SJiri Olsa stats->ld_llchit++; 564aadddd68SJiri Olsa } 565aadddd68SJiri Olsa 566aadddd68SJiri Olsa if (lvl & P(LVL, LOC_RAM)) { 567aadddd68SJiri Olsa stats->lcl_dram++; 568aadddd68SJiri Olsa if (snoop & P(SNOOP, HIT)) 569aadddd68SJiri Olsa stats->ld_shared++; 570aadddd68SJiri Olsa else 571aadddd68SJiri Olsa stats->ld_excl++; 572aadddd68SJiri Olsa } 573aadddd68SJiri Olsa 574aadddd68SJiri Olsa if ((lvl & P(LVL, REM_RAM1)) || 57512c15302SJiri Olsa (lvl & P(LVL, REM_RAM2)) || 57612c15302SJiri Olsa mrem) { 577aadddd68SJiri Olsa stats->rmt_dram++; 578aadddd68SJiri Olsa if (snoop & P(SNOOP, HIT)) 579aadddd68SJiri Olsa stats->ld_shared++; 580aadddd68SJiri Olsa else 581aadddd68SJiri Olsa stats->ld_excl++; 582aadddd68SJiri Olsa } 583aadddd68SJiri Olsa } 584aadddd68SJiri Olsa 585aadddd68SJiri Olsa if ((lvl & P(LVL, REM_CCE1)) || 58612c15302SJiri Olsa (lvl & P(LVL, REM_CCE2)) || 58712c15302SJiri Olsa mrem) { 588aadddd68SJiri Olsa if (snoop & P(SNOOP, HIT)) 589aadddd68SJiri Olsa stats->rmt_hit++; 590aadddd68SJiri Olsa else if (snoop & P(SNOOP, HITM)) 591dba8ab93SJiri Olsa HITM_INC(rmt_hitm); 592aadddd68SJiri Olsa } 593aadddd68SJiri Olsa 594aadddd68SJiri Olsa if ((lvl & P(LVL, MISS))) 595aadddd68SJiri Olsa stats->ld_miss++; 596aadddd68SJiri Olsa 597aadddd68SJiri Olsa } else if (op & P(OP, STORE)) { 598aadddd68SJiri Olsa /* store */ 599aadddd68SJiri Olsa stats->store++; 600aadddd68SJiri Olsa 601aadddd68SJiri Olsa if (!daddr) { 602aadddd68SJiri Olsa stats->st_noadrs++; 603aadddd68SJiri Olsa return -1; 604aadddd68SJiri Olsa } 605aadddd68SJiri Olsa 606aadddd68SJiri Olsa if (lvl & P(LVL, HIT)) { 607aadddd68SJiri Olsa if (lvl & P(LVL, UNC)) stats->st_uncache++; 608aadddd68SJiri Olsa if (lvl & P(LVL, L1 )) stats->st_l1hit++; 609aadddd68SJiri Olsa } 610aadddd68SJiri Olsa if (lvl & P(LVL, MISS)) 611aadddd68SJiri Olsa if (lvl & P(LVL, L1)) stats->st_l1miss++; 612*98450637SLeo Yan if (lvl & P(LVL, NA)) 613*98450637SLeo Yan stats->st_na++; 614aadddd68SJiri Olsa } else { 615aadddd68SJiri Olsa /* unparsable data_src? */ 616aadddd68SJiri Olsa stats->noparse++; 617aadddd68SJiri Olsa return -1; 618aadddd68SJiri Olsa } 619aadddd68SJiri Olsa 620d46a4cdfSArnaldo Carvalho de Melo if (!mi->daddr.ms.map || !mi->iaddr.ms.map) { 621aadddd68SJiri Olsa stats->nomap++; 622aadddd68SJiri Olsa return -1; 623aadddd68SJiri Olsa } 624aadddd68SJiri Olsa 625aadddd68SJiri Olsa #undef P 626dba8ab93SJiri Olsa #undef HITM_INC 627aadddd68SJiri Olsa return err; 628aadddd68SJiri Olsa } 6290a9a24ccSJiri Olsa 6300a9a24ccSJiri Olsa void c2c_add_stats(struct c2c_stats *stats, struct c2c_stats *add) 6310a9a24ccSJiri Olsa { 6320a9a24ccSJiri Olsa stats->nr_entries += add->nr_entries; 6330a9a24ccSJiri Olsa 6340a9a24ccSJiri Olsa stats->locks += add->locks; 6350a9a24ccSJiri Olsa stats->store += add->store; 6360a9a24ccSJiri Olsa stats->st_uncache += add->st_uncache; 6370a9a24ccSJiri Olsa stats->st_noadrs += add->st_noadrs; 6380a9a24ccSJiri Olsa stats->st_l1hit += add->st_l1hit; 6390a9a24ccSJiri Olsa stats->st_l1miss += add->st_l1miss; 640*98450637SLeo Yan stats->st_na += add->st_na; 6410a9a24ccSJiri Olsa stats->load += add->load; 6420a9a24ccSJiri Olsa stats->ld_excl += add->ld_excl; 6430a9a24ccSJiri Olsa stats->ld_shared += add->ld_shared; 6440a9a24ccSJiri Olsa stats->ld_uncache += add->ld_uncache; 6450a9a24ccSJiri Olsa stats->ld_io += add->ld_io; 6460a9a24ccSJiri Olsa stats->ld_miss += add->ld_miss; 6470a9a24ccSJiri Olsa stats->ld_noadrs += add->ld_noadrs; 6480a9a24ccSJiri Olsa stats->ld_fbhit += add->ld_fbhit; 6490a9a24ccSJiri Olsa stats->ld_l1hit += add->ld_l1hit; 6500a9a24ccSJiri Olsa stats->ld_l2hit += add->ld_l2hit; 6510a9a24ccSJiri Olsa stats->ld_llchit += add->ld_llchit; 6520a9a24ccSJiri Olsa stats->lcl_hitm += add->lcl_hitm; 6530a9a24ccSJiri Olsa stats->rmt_hitm += add->rmt_hitm; 654dba8ab93SJiri Olsa stats->tot_hitm += add->tot_hitm; 6550a9a24ccSJiri Olsa stats->rmt_hit += add->rmt_hit; 6560a9a24ccSJiri Olsa stats->lcl_dram += add->lcl_dram; 6570a9a24ccSJiri Olsa stats->rmt_dram += add->rmt_dram; 658d9d5d767SKan Liang stats->blk_data += add->blk_data; 659d9d5d767SKan Liang stats->blk_addr += add->blk_addr; 6600a9a24ccSJiri Olsa stats->nomap += add->nomap; 6610a9a24ccSJiri Olsa stats->noparse += add->noparse; 6620a9a24ccSJiri Olsa } 663