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"
161eaf496eSIan Rogers #include "pmus.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
perf_mem_events__ptr(int i)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
perf_mem_events__name(int i,const char * pmu_name __maybe_unused)40c091ee90SIan Rogers const char * __weak perf_mem_events__name(int i, const 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
56c091ee90SIan Rogers return e->name;
572ba7ac58SJiri Olsa }
582ba7ac58SJiri Olsa
is_mem_loads_aux_event(struct evsel * leader __maybe_unused)592a57d408SKan Liang __weak bool is_mem_loads_aux_event(struct evsel *leader __maybe_unused)
602a57d408SKan Liang {
612a57d408SKan Liang return false;
622a57d408SKan Liang }
632a57d408SKan Liang
perf_mem_events__parse(const char * str)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
perf_mem_event__supported(const char * mnt,struct perf_pmu * pmu,struct perf_mem_event * e)103*9cc93a61SKan Liang static bool perf_mem_event__supported(const char *mnt, struct perf_pmu *pmu,
104*9cc93a61SKan Liang struct perf_mem_event *e)
105e7ce8d11SJin Yao {
106*9cc93a61SKan Liang char sysfs_name[100];
107e7ce8d11SJin Yao char path[PATH_MAX];
108e7ce8d11SJin Yao struct stat st;
109e7ce8d11SJin Yao
110*9cc93a61SKan Liang scnprintf(sysfs_name, sizeof(sysfs_name), e->sysfs_name, pmu->name);
111e7ce8d11SJin Yao scnprintf(path, PATH_MAX, "%s/devices/%s", mnt, sysfs_name);
112e7ce8d11SJin Yao return !stat(path, &st);
113e7ce8d11SJin Yao }
114e7ce8d11SJin Yao
perf_mem_events__init(void)11554fbad54SJiri Olsa int perf_mem_events__init(void)
11654fbad54SJiri Olsa {
11754fbad54SJiri Olsa const char *mnt = sysfs__mount();
11854fbad54SJiri Olsa bool found = false;
11954fbad54SJiri Olsa int j;
12054fbad54SJiri Olsa
12154fbad54SJiri Olsa if (!mnt)
12254fbad54SJiri Olsa return -ENOENT;
12354fbad54SJiri Olsa
12454fbad54SJiri Olsa for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
125eaf6aaeeSLeo Yan struct perf_mem_event *e = perf_mem_events__ptr(j);
12694f9eb95SIan Rogers struct perf_pmu *pmu = NULL;
12754fbad54SJiri Olsa
1284ba2452cSLeo Yan /*
1294ba2452cSLeo Yan * If the event entry isn't valid, skip initialization
1304ba2452cSLeo Yan * and "e->supported" will keep false.
1314ba2452cSLeo Yan */
1324ba2452cSLeo Yan if (!e->tag)
1334ba2452cSLeo Yan continue;
1344ba2452cSLeo Yan
1355752c20fSRavi Bangoria /*
1365752c20fSRavi Bangoria * Scan all PMUs not just core ones, since perf mem/c2c on
1375752c20fSRavi Bangoria * platforms like AMD uses IBS OP PMU which is independent
1385752c20fSRavi Bangoria * of core PMU.
1395752c20fSRavi Bangoria */
1405752c20fSRavi Bangoria while ((pmu = perf_pmus__scan(pmu)) != NULL) {
141*9cc93a61SKan Liang e->supported |= perf_mem_event__supported(mnt, pmu, e);
142*9cc93a61SKan Liang if (e->supported) {
143e7ce8d11SJin Yao found = true;
144*9cc93a61SKan Liang break;
145*9cc93a61SKan Liang }
146*9cc93a61SKan Liang }
14754fbad54SJiri Olsa }
14854fbad54SJiri Olsa
14954fbad54SJiri Olsa return found ? 0 : -ENOENT;
15054fbad54SJiri Olsa }
1510c877d75SJiri Olsa
perf_mem_events__list(void)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
1592c5f652cSRavi Bangoria fprintf(stderr, "%-*s%-*s%s",
1602c5f652cSRavi Bangoria e->tag ? 13 : 0,
1614ba2452cSLeo Yan e->tag ? : "",
1622c5f652cSRavi Bangoria e->tag && verbose > 0 ? 25 : 0,
1632c5f652cSRavi Bangoria e->tag && verbose > 0 ? perf_mem_events__name(j, NULL) : "",
1642c5f652cSRavi Bangoria e->supported ? ": available\n" : "");
165b027cc6fSIan Rogers }
166b027cc6fSIan Rogers }
167b027cc6fSIan Rogers
perf_mem_events__print_unsupport_hybrid(struct perf_mem_event * e,int idx)1684a9086adSJin Yao static void perf_mem_events__print_unsupport_hybrid(struct perf_mem_event *e,
1694a9086adSJin Yao int idx)
1704a9086adSJin Yao {
1714a9086adSJin Yao const char *mnt = sysfs__mount();
172abe9544eSIan Rogers struct perf_pmu *pmu = NULL;
1734a9086adSJin Yao
1745752c20fSRavi Bangoria while ((pmu = perf_pmus__scan(pmu)) != NULL) {
175*9cc93a61SKan Liang if (!perf_mem_event__supported(mnt, pmu, e)) {
1764a9086adSJin Yao pr_err("failed: event '%s' not supported\n",
1774a9086adSJin Yao perf_mem_events__name(idx, pmu->name));
1784a9086adSJin Yao }
1794a9086adSJin Yao }
1804a9086adSJin Yao }
1814a9086adSJin Yao
perf_mem_events__record_args(const char ** rec_argv,int * argv_nr,char ** rec_tmp,int * tmp_nr)1824a9086adSJin Yao int perf_mem_events__record_args(const char **rec_argv, int *argv_nr,
1834a9086adSJin Yao char **rec_tmp, int *tmp_nr)
1844a9086adSJin Yao {
185*9cc93a61SKan Liang const char *mnt = sysfs__mount();
1864a9086adSJin Yao int i = *argv_nr, k = 0;
1874a9086adSJin Yao struct perf_mem_event *e;
1884a9086adSJin Yao
1894a9086adSJin Yao for (int j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
1904a9086adSJin Yao e = perf_mem_events__ptr(j);
1914a9086adSJin Yao if (!e->record)
1924a9086adSJin Yao continue;
1934a9086adSJin Yao
1945752c20fSRavi Bangoria if (perf_pmus__num_mem_pmus() == 1) {
1954a9086adSJin Yao if (!e->supported) {
1964a9086adSJin Yao pr_err("failed: event '%s' not supported\n",
1974a9086adSJin Yao perf_mem_events__name(j, NULL));
1984a9086adSJin Yao return -1;
1994a9086adSJin Yao }
2004a9086adSJin Yao
2014a9086adSJin Yao rec_argv[i++] = "-e";
2024a9086adSJin Yao rec_argv[i++] = perf_mem_events__name(j, NULL);
2034a9086adSJin Yao } else {
204650b4198SIan Rogers struct perf_pmu *pmu = NULL;
205650b4198SIan Rogers
2064a9086adSJin Yao if (!e->supported) {
2074a9086adSJin Yao perf_mem_events__print_unsupport_hybrid(e, j);
2084a9086adSJin Yao return -1;
2094a9086adSJin Yao }
2104a9086adSJin Yao
2115752c20fSRavi Bangoria while ((pmu = perf_pmus__scan(pmu)) != NULL) {
212c091ee90SIan Rogers const char *s = perf_mem_events__name(j, pmu->name);
213c091ee90SIan Rogers
214*9cc93a61SKan Liang if (!perf_mem_event__supported(mnt, pmu, e))
215*9cc93a61SKan Liang continue;
216*9cc93a61SKan Liang
2174a9086adSJin Yao rec_argv[i++] = "-e";
2184a9086adSJin Yao if (s) {
219c091ee90SIan Rogers char *copy = strdup(s);
220c091ee90SIan Rogers if (!copy)
2214a9086adSJin Yao return -1;
2224a9086adSJin Yao
223c091ee90SIan Rogers rec_argv[i++] = copy;
224c091ee90SIan Rogers rec_tmp[k++] = copy;
2254a9086adSJin Yao }
2264a9086adSJin Yao }
2274a9086adSJin Yao }
2284a9086adSJin Yao }
2294a9086adSJin Yao
2304a9086adSJin Yao *argv_nr = i;
2314a9086adSJin Yao *tmp_nr = k;
2324a9086adSJin Yao return 0;
2334a9086adSJin Yao }
2344a9086adSJin Yao
2350c877d75SJiri Olsa static const char * const tlb_access[] = {
2360c877d75SJiri Olsa "N/A",
2370c877d75SJiri Olsa "HIT",
2380c877d75SJiri Olsa "MISS",
2390c877d75SJiri Olsa "L1",
2400c877d75SJiri Olsa "L2",
2410c877d75SJiri Olsa "Walker",
2420c877d75SJiri Olsa "Fault",
2430c877d75SJiri Olsa };
2440c877d75SJiri Olsa
perf_mem__tlb_scnprintf(char * out,size_t sz,struct mem_info * mem_info)245b1a5fbeaSJiri Olsa int perf_mem__tlb_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
2460c877d75SJiri Olsa {
2470c877d75SJiri Olsa size_t l = 0, i;
2480c877d75SJiri Olsa u64 m = PERF_MEM_TLB_NA;
2490c877d75SJiri Olsa u64 hit, miss;
2500c877d75SJiri Olsa
2510c877d75SJiri Olsa sz -= 1; /* -1 for null termination */
2520c877d75SJiri Olsa out[0] = '\0';
2530c877d75SJiri Olsa
2540c877d75SJiri Olsa if (mem_info)
2550c877d75SJiri Olsa m = mem_info->data_src.mem_dtlb;
2560c877d75SJiri Olsa
2570c877d75SJiri Olsa hit = m & PERF_MEM_TLB_HIT;
2580c877d75SJiri Olsa miss = m & PERF_MEM_TLB_MISS;
2590c877d75SJiri Olsa
2600c877d75SJiri Olsa /* already taken care of */
2610c877d75SJiri Olsa m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS);
2620c877d75SJiri Olsa
2630c877d75SJiri Olsa for (i = 0; m && i < ARRAY_SIZE(tlb_access); i++, m >>= 1) {
2640c877d75SJiri Olsa if (!(m & 0x1))
2650c877d75SJiri Olsa continue;
2660c877d75SJiri Olsa if (l) {
2670c877d75SJiri Olsa strcat(out, " or ");
2680c877d75SJiri Olsa l += 4;
2690c877d75SJiri Olsa }
270b1a5fbeaSJiri Olsa l += scnprintf(out + l, sz - l, tlb_access[i]);
2710c877d75SJiri Olsa }
2720c877d75SJiri Olsa if (*out == '\0')
273b1a5fbeaSJiri Olsa l += scnprintf(out, sz - l, "N/A");
2740c877d75SJiri Olsa if (hit)
275b1a5fbeaSJiri Olsa l += scnprintf(out + l, sz - l, " hit");
2760c877d75SJiri Olsa if (miss)
277b1a5fbeaSJiri Olsa l += scnprintf(out + l, sz - l, " miss");
278b1a5fbeaSJiri Olsa
279b1a5fbeaSJiri Olsa return l;
2800c877d75SJiri Olsa }
281071e9a1eSJiri Olsa
282071e9a1eSJiri Olsa static const char * const mem_lvl[] = {
283071e9a1eSJiri Olsa "N/A",
284071e9a1eSJiri Olsa "HIT",
285071e9a1eSJiri Olsa "MISS",
286071e9a1eSJiri Olsa "L1",
287c72de116SRavi Bangoria "LFB/MAB",
288071e9a1eSJiri Olsa "L2",
289071e9a1eSJiri Olsa "L3",
290071e9a1eSJiri Olsa "Local RAM",
291071e9a1eSJiri Olsa "Remote RAM (1 hop)",
292071e9a1eSJiri Olsa "Remote RAM (2 hops)",
293071e9a1eSJiri Olsa "Remote Cache (1 hop)",
294071e9a1eSJiri Olsa "Remote Cache (2 hops)",
295071e9a1eSJiri Olsa "I/O",
296071e9a1eSJiri Olsa "Uncached",
297071e9a1eSJiri Olsa };
298071e9a1eSJiri Olsa
29952839e65SAndi Kleen static const char * const mem_lvlnum[] = {
300d5fa7e9dSRavi Bangoria [PERF_MEM_LVLNUM_UNC] = "Uncached",
301923396f6SRavi Bangoria [PERF_MEM_LVLNUM_CXL] = "CXL",
302923396f6SRavi Bangoria [PERF_MEM_LVLNUM_IO] = "I/O",
30352839e65SAndi Kleen [PERF_MEM_LVLNUM_ANY_CACHE] = "Any cache",
304c72de116SRavi Bangoria [PERF_MEM_LVLNUM_LFB] = "LFB/MAB",
30552839e65SAndi Kleen [PERF_MEM_LVLNUM_RAM] = "RAM",
30652839e65SAndi Kleen [PERF_MEM_LVLNUM_PMEM] = "PMEM",
30752839e65SAndi Kleen [PERF_MEM_LVLNUM_NA] = "N/A",
30852839e65SAndi Kleen };
30952839e65SAndi Kleen
310cae1d759SKajol Jain static const char * const mem_hops[] = {
311cae1d759SKajol Jain "N/A",
312cae1d759SKajol Jain /*
313cae1d759SKajol Jain * While printing, 'Remote' will be added to represent
314cae1d759SKajol Jain * 'Remote core, same node' accesses as remote field need
315cae1d759SKajol Jain * to be set with mem_hops field.
316cae1d759SKajol Jain */
317cae1d759SKajol Jain "core, same node",
3187fbddf40SKajol Jain "node, same socket",
3197fbddf40SKajol Jain "socket, same board",
3207fbddf40SKajol Jain "board",
321cae1d759SKajol Jain };
322cae1d759SKajol Jain
perf_mem__op_scnprintf(char * out,size_t sz,struct mem_info * mem_info)323fdefc375SLeo Yan static int perf_mem__op_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
324fdefc375SLeo Yan {
325fdefc375SLeo Yan u64 op = PERF_MEM_LOCK_NA;
326fdefc375SLeo Yan int l;
327fdefc375SLeo Yan
328fdefc375SLeo Yan if (mem_info)
329fdefc375SLeo Yan op = mem_info->data_src.mem_op;
330fdefc375SLeo Yan
331fdefc375SLeo Yan if (op & PERF_MEM_OP_NA)
332fdefc375SLeo Yan l = scnprintf(out, sz, "N/A");
333fdefc375SLeo Yan else if (op & PERF_MEM_OP_LOAD)
334fdefc375SLeo Yan l = scnprintf(out, sz, "LOAD");
335fdefc375SLeo Yan else if (op & PERF_MEM_OP_STORE)
336fdefc375SLeo Yan l = scnprintf(out, sz, "STORE");
337fdefc375SLeo Yan else if (op & PERF_MEM_OP_PFETCH)
338fdefc375SLeo Yan l = scnprintf(out, sz, "PFETCH");
339fdefc375SLeo Yan else if (op & PERF_MEM_OP_EXEC)
340fdefc375SLeo Yan l = scnprintf(out, sz, "EXEC");
341fdefc375SLeo Yan else
342fdefc375SLeo Yan l = scnprintf(out, sz, "No");
343fdefc375SLeo Yan
344fdefc375SLeo Yan return l;
345fdefc375SLeo Yan }
346fdefc375SLeo Yan
perf_mem__lvl_scnprintf(char * out,size_t sz,struct mem_info * mem_info)34796907563SJiri Olsa int perf_mem__lvl_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
348071e9a1eSJiri Olsa {
349ddeac198SRavi Bangoria union perf_mem_data_src data_src;
3507fbddf40SKajol Jain int printed = 0;
351ddeac198SRavi Bangoria size_t l = 0;
352ddeac198SRavi Bangoria size_t i;
353ddeac198SRavi Bangoria int lvl;
354ddeac198SRavi Bangoria char hit_miss[5] = {0};
355071e9a1eSJiri Olsa
356071e9a1eSJiri Olsa sz -= 1; /* -1 for null termination */
357071e9a1eSJiri Olsa out[0] = '\0';
358071e9a1eSJiri Olsa
359ddeac198SRavi Bangoria if (!mem_info)
360ddeac198SRavi Bangoria goto na;
361071e9a1eSJiri Olsa
362ddeac198SRavi Bangoria data_src = mem_info->data_src;
363071e9a1eSJiri Olsa
364ddeac198SRavi Bangoria if (data_src.mem_lvl & PERF_MEM_LVL_HIT)
365ddeac198SRavi Bangoria memcpy(hit_miss, "hit", 3);
366ddeac198SRavi Bangoria else if (data_src.mem_lvl & PERF_MEM_LVL_MISS)
367ddeac198SRavi Bangoria memcpy(hit_miss, "miss", 4);
368ddeac198SRavi Bangoria
369ddeac198SRavi Bangoria lvl = data_src.mem_lvl_num;
370ddeac198SRavi Bangoria if (lvl && lvl != PERF_MEM_LVLNUM_NA) {
371ddeac198SRavi Bangoria if (data_src.mem_remote) {
37252839e65SAndi Kleen strcat(out, "Remote ");
37352839e65SAndi Kleen l += 7;
37452839e65SAndi Kleen }
37552839e65SAndi Kleen
376ddeac198SRavi Bangoria if (data_src.mem_hops)
377ddeac198SRavi Bangoria l += scnprintf(out + l, sz - l, "%s ", mem_hops[data_src.mem_hops]);
378ddeac198SRavi Bangoria
379ddeac198SRavi Bangoria if (mem_lvlnum[lvl])
380ddeac198SRavi Bangoria l += scnprintf(out + l, sz - l, mem_lvlnum[lvl]);
381ddeac198SRavi Bangoria else
382ddeac198SRavi Bangoria l += scnprintf(out + l, sz - l, "L%d", lvl);
383ddeac198SRavi Bangoria
384ddeac198SRavi Bangoria l += scnprintf(out + l, sz - l, " %s", hit_miss);
385ddeac198SRavi Bangoria return l;
386ddeac198SRavi Bangoria }
387ddeac198SRavi Bangoria
388ddeac198SRavi Bangoria lvl = data_src.mem_lvl;
389ddeac198SRavi Bangoria if (!lvl)
390ddeac198SRavi Bangoria goto na;
391ddeac198SRavi Bangoria
392ddeac198SRavi Bangoria lvl &= ~(PERF_MEM_LVL_NA | PERF_MEM_LVL_HIT | PERF_MEM_LVL_MISS);
393ddeac198SRavi Bangoria if (!lvl)
394ddeac198SRavi Bangoria goto na;
395ddeac198SRavi Bangoria
396ddeac198SRavi Bangoria for (i = 0; lvl && i < ARRAY_SIZE(mem_lvl); i++, lvl >>= 1) {
397ddeac198SRavi Bangoria if (!(lvl & 0x1))
398071e9a1eSJiri Olsa continue;
39952839e65SAndi Kleen if (printed++) {
400071e9a1eSJiri Olsa strcat(out, " or ");
401071e9a1eSJiri Olsa l += 4;
402071e9a1eSJiri Olsa }
40396907563SJiri Olsa l += scnprintf(out + l, sz - l, mem_lvl[i]);
404071e9a1eSJiri Olsa }
40552839e65SAndi Kleen
406ddeac198SRavi Bangoria if (printed) {
407ddeac198SRavi Bangoria l += scnprintf(out + l, sz - l, " %s", hit_miss);
40896907563SJiri Olsa return l;
409071e9a1eSJiri Olsa }
4102c07af13SJiri Olsa
411ddeac198SRavi Bangoria na:
412ddeac198SRavi Bangoria strcat(out, "N/A");
413ddeac198SRavi Bangoria return 3;
414ddeac198SRavi Bangoria }
415ddeac198SRavi Bangoria
4162c07af13SJiri Olsa static const char * const snoop_access[] = {
4172c07af13SJiri Olsa "N/A",
4182c07af13SJiri Olsa "None",
4192c07af13SJiri Olsa "Hit",
420166ebdd2SAndi Kleen "Miss",
4212c07af13SJiri Olsa "HitM",
4222c07af13SJiri Olsa };
4232c07af13SJiri Olsa
424f78d6250SLeo Yan static const char * const snoopx_access[] = {
425f78d6250SLeo Yan "Fwd",
426f78d6250SLeo Yan "Peer",
427f78d6250SLeo Yan };
428f78d6250SLeo Yan
perf_mem__snp_scnprintf(char * out,size_t sz,struct mem_info * mem_info)429149d7507SJiri Olsa int perf_mem__snp_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
4302c07af13SJiri Olsa {
4312c07af13SJiri Olsa size_t i, l = 0;
4322c07af13SJiri Olsa u64 m = PERF_MEM_SNOOP_NA;
4332c07af13SJiri Olsa
4342c07af13SJiri Olsa sz -= 1; /* -1 for null termination */
4352c07af13SJiri Olsa out[0] = '\0';
4362c07af13SJiri Olsa
4372c07af13SJiri Olsa if (mem_info)
4382c07af13SJiri Olsa m = mem_info->data_src.mem_snoop;
4392c07af13SJiri Olsa
4402c07af13SJiri Olsa for (i = 0; m && i < ARRAY_SIZE(snoop_access); i++, m >>= 1) {
4412c07af13SJiri Olsa if (!(m & 0x1))
4422c07af13SJiri Olsa continue;
4432c07af13SJiri Olsa if (l) {
4442c07af13SJiri Olsa strcat(out, " or ");
4452c07af13SJiri Olsa l += 4;
4462c07af13SJiri Olsa }
447149d7507SJiri Olsa l += scnprintf(out + l, sz - l, snoop_access[i]);
4482c07af13SJiri Olsa }
449f78d6250SLeo Yan
450f78d6250SLeo Yan m = 0;
451f78d6250SLeo Yan if (mem_info)
452f78d6250SLeo Yan m = mem_info->data_src.mem_snoopx;
453f78d6250SLeo Yan
454f78d6250SLeo Yan for (i = 0; m && i < ARRAY_SIZE(snoopx_access); i++, m >>= 1) {
455f78d6250SLeo Yan if (!(m & 0x1))
456f78d6250SLeo Yan continue;
457f78d6250SLeo Yan
45852839e65SAndi Kleen if (l) {
45952839e65SAndi Kleen strcat(out, " or ");
46052839e65SAndi Kleen l += 4;
46152839e65SAndi Kleen }
462f78d6250SLeo Yan l += scnprintf(out + l, sz - l, snoopx_access[i]);
46352839e65SAndi Kleen }
4642c07af13SJiri Olsa
4652c07af13SJiri Olsa if (*out == '\0')
466149d7507SJiri Olsa l += scnprintf(out, sz - l, "N/A");
467149d7507SJiri Olsa
468149d7507SJiri Olsa return l;
4692c07af13SJiri Olsa }
47069a77275SJiri Olsa
perf_mem__lck_scnprintf(char * out,size_t sz,struct mem_info * mem_info)4718b0819c8SJiri Olsa int perf_mem__lck_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
47269a77275SJiri Olsa {
47369a77275SJiri Olsa u64 mask = PERF_MEM_LOCK_NA;
4748b0819c8SJiri Olsa int l;
47569a77275SJiri Olsa
47669a77275SJiri Olsa if (mem_info)
47769a77275SJiri Olsa mask = mem_info->data_src.mem_lock;
47869a77275SJiri Olsa
47969a77275SJiri Olsa if (mask & PERF_MEM_LOCK_NA)
4808b0819c8SJiri Olsa l = scnprintf(out, sz, "N/A");
48169a77275SJiri Olsa else if (mask & PERF_MEM_LOCK_LOCKED)
4828b0819c8SJiri Olsa l = scnprintf(out, sz, "Yes");
48369a77275SJiri Olsa else
4848b0819c8SJiri Olsa l = scnprintf(out, sz, "No");
4858b0819c8SJiri Olsa
4868b0819c8SJiri Olsa return l;
48769a77275SJiri Olsa }
488c19ac912SJiri Olsa
perf_mem__blk_scnprintf(char * out,size_t sz,struct mem_info * mem_info)489a054c298SKan Liang int perf_mem__blk_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
490a054c298SKan Liang {
491a054c298SKan Liang size_t l = 0;
492a054c298SKan Liang u64 mask = PERF_MEM_BLK_NA;
493a054c298SKan Liang
494a054c298SKan Liang sz -= 1; /* -1 for null termination */
495a054c298SKan Liang out[0] = '\0';
496a054c298SKan Liang
497a054c298SKan Liang if (mem_info)
498a054c298SKan Liang mask = mem_info->data_src.mem_blk;
499a054c298SKan Liang
500a054c298SKan Liang if (!mask || (mask & PERF_MEM_BLK_NA)) {
501a054c298SKan Liang l += scnprintf(out + l, sz - l, " N/A");
502a054c298SKan Liang return l;
503a054c298SKan Liang }
504a054c298SKan Liang if (mask & PERF_MEM_BLK_DATA)
505a054c298SKan Liang l += scnprintf(out + l, sz - l, " Data");
506a054c298SKan Liang if (mask & PERF_MEM_BLK_ADDR)
507a054c298SKan Liang l += scnprintf(out + l, sz - l, " Addr");
508a054c298SKan Liang
509a054c298SKan Liang return l;
510a054c298SKan Liang }
511a054c298SKan Liang
perf_script__meminfo_scnprintf(char * out,size_t sz,struct mem_info * mem_info)512c19ac912SJiri Olsa int perf_script__meminfo_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
513c19ac912SJiri Olsa {
514c19ac912SJiri Olsa int i = 0;
515c19ac912SJiri Olsa
516fdefc375SLeo Yan i += scnprintf(out, sz, "|OP ");
517fdefc375SLeo Yan i += perf_mem__op_scnprintf(out + i, sz - i, mem_info);
518fdefc375SLeo Yan i += scnprintf(out + i, sz - i, "|LVL ");
519fdefc375SLeo Yan i += perf_mem__lvl_scnprintf(out + i, sz, mem_info);
520c19ac912SJiri Olsa i += scnprintf(out + i, sz - i, "|SNP ");
521c19ac912SJiri Olsa i += perf_mem__snp_scnprintf(out + i, sz - i, mem_info);
522c19ac912SJiri Olsa i += scnprintf(out + i, sz - i, "|TLB ");
523c19ac912SJiri Olsa i += perf_mem__tlb_scnprintf(out + i, sz - i, mem_info);
524c19ac912SJiri Olsa i += scnprintf(out + i, sz - i, "|LCK ");
525c19ac912SJiri Olsa i += perf_mem__lck_scnprintf(out + i, sz - i, mem_info);
526a054c298SKan Liang i += scnprintf(out + i, sz - i, "|BLK ");
527a054c298SKan Liang i += perf_mem__blk_scnprintf(out + i, sz - i, mem_info);
528c19ac912SJiri Olsa
529c19ac912SJiri Olsa return i;
530c19ac912SJiri Olsa }
531aadddd68SJiri Olsa
c2c_decode_stats(struct c2c_stats * stats,struct mem_info * mi)532aadddd68SJiri Olsa int c2c_decode_stats(struct c2c_stats *stats, struct mem_info *mi)
533aadddd68SJiri Olsa {
534aadddd68SJiri Olsa union perf_mem_data_src *data_src = &mi->data_src;
535aadddd68SJiri Olsa u64 daddr = mi->daddr.addr;
536aadddd68SJiri Olsa u64 op = data_src->mem_op;
537aadddd68SJiri Olsa u64 lvl = data_src->mem_lvl;
538aadddd68SJiri Olsa u64 snoop = data_src->mem_snoop;
539e843dec5SLeo Yan u64 snoopx = data_src->mem_snoopx;
540aadddd68SJiri Olsa u64 lock = data_src->mem_lock;
541d9d5d767SKan Liang u64 blk = data_src->mem_blk;
54212c15302SJiri Olsa /*
54312c15302SJiri Olsa * Skylake might report unknown remote level via this
54412c15302SJiri Olsa * bit, consider it when evaluating remote HITMs.
545cae1d759SKajol Jain *
546cae1d759SKajol Jain * Incase of power, remote field can also be used to denote cache
547cae1d759SKajol Jain * accesses from the another core of same node. Hence, setting
548cae1d759SKajol Jain * mrem only when HOPS is zero along with set remote field.
54912c15302SJiri Olsa */
550cae1d759SKajol Jain bool mrem = (data_src->mem_remote && !data_src->mem_hops);
551aadddd68SJiri Olsa int err = 0;
552aadddd68SJiri Olsa
553dba8ab93SJiri Olsa #define HITM_INC(__f) \
554dba8ab93SJiri Olsa do { \
555dba8ab93SJiri Olsa stats->__f++; \
556dba8ab93SJiri Olsa stats->tot_hitm++; \
557dba8ab93SJiri Olsa } while (0)
558dba8ab93SJiri Olsa
559e843dec5SLeo Yan #define PEER_INC(__f) \
560e843dec5SLeo Yan do { \
561e843dec5SLeo Yan stats->__f++; \
562e843dec5SLeo Yan stats->tot_peer++; \
563e843dec5SLeo Yan } while (0)
564e843dec5SLeo Yan
565aadddd68SJiri Olsa #define P(a, b) PERF_MEM_##a##_##b
566aadddd68SJiri Olsa
567aadddd68SJiri Olsa stats->nr_entries++;
568aadddd68SJiri Olsa
569aadddd68SJiri Olsa if (lock & P(LOCK, LOCKED)) stats->locks++;
570aadddd68SJiri Olsa
571d9d5d767SKan Liang if (blk & P(BLK, DATA)) stats->blk_data++;
572d9d5d767SKan Liang if (blk & P(BLK, ADDR)) stats->blk_addr++;
573d9d5d767SKan Liang
574aadddd68SJiri Olsa if (op & P(OP, LOAD)) {
575aadddd68SJiri Olsa /* load */
576aadddd68SJiri Olsa stats->load++;
577aadddd68SJiri Olsa
578aadddd68SJiri Olsa if (!daddr) {
579aadddd68SJiri Olsa stats->ld_noadrs++;
580aadddd68SJiri Olsa return -1;
581aadddd68SJiri Olsa }
582aadddd68SJiri Olsa
583aadddd68SJiri Olsa if (lvl & P(LVL, HIT)) {
584aadddd68SJiri Olsa if (lvl & P(LVL, UNC)) stats->ld_uncache++;
585aadddd68SJiri Olsa if (lvl & P(LVL, IO)) stats->ld_io++;
586aadddd68SJiri Olsa if (lvl & P(LVL, LFB)) stats->ld_fbhit++;
587aadddd68SJiri Olsa if (lvl & P(LVL, L1 )) stats->ld_l1hit++;
588e843dec5SLeo Yan if (lvl & P(LVL, L2)) {
589e843dec5SLeo Yan stats->ld_l2hit++;
590e843dec5SLeo Yan
591e843dec5SLeo Yan if (snoopx & P(SNOOPX, PEER))
592e843dec5SLeo Yan PEER_INC(lcl_peer);
593e843dec5SLeo Yan }
594aadddd68SJiri Olsa if (lvl & P(LVL, L3 )) {
595aadddd68SJiri Olsa if (snoop & P(SNOOP, HITM))
596dba8ab93SJiri Olsa HITM_INC(lcl_hitm);
597aadddd68SJiri Olsa else
598aadddd68SJiri Olsa stats->ld_llchit++;
599e843dec5SLeo Yan
600e843dec5SLeo Yan if (snoopx & P(SNOOPX, PEER))
601e843dec5SLeo Yan PEER_INC(lcl_peer);
602aadddd68SJiri Olsa }
603aadddd68SJiri Olsa
604aadddd68SJiri Olsa if (lvl & P(LVL, LOC_RAM)) {
605aadddd68SJiri Olsa stats->lcl_dram++;
606aadddd68SJiri Olsa if (snoop & P(SNOOP, HIT))
607aadddd68SJiri Olsa stats->ld_shared++;
608aadddd68SJiri Olsa else
609aadddd68SJiri Olsa stats->ld_excl++;
610aadddd68SJiri Olsa }
611aadddd68SJiri Olsa
612aadddd68SJiri Olsa if ((lvl & P(LVL, REM_RAM1)) ||
61312c15302SJiri Olsa (lvl & P(LVL, REM_RAM2)) ||
61412c15302SJiri Olsa mrem) {
615aadddd68SJiri Olsa stats->rmt_dram++;
616aadddd68SJiri Olsa if (snoop & P(SNOOP, HIT))
617aadddd68SJiri Olsa stats->ld_shared++;
618aadddd68SJiri Olsa else
619aadddd68SJiri Olsa stats->ld_excl++;
620aadddd68SJiri Olsa }
621aadddd68SJiri Olsa }
622aadddd68SJiri Olsa
623aadddd68SJiri Olsa if ((lvl & P(LVL, REM_CCE1)) ||
62412c15302SJiri Olsa (lvl & P(LVL, REM_CCE2)) ||
62512c15302SJiri Olsa mrem) {
626e843dec5SLeo Yan if (snoop & P(SNOOP, HIT)) {
627aadddd68SJiri Olsa stats->rmt_hit++;
628e843dec5SLeo Yan } else if (snoop & P(SNOOP, HITM)) {
629dba8ab93SJiri Olsa HITM_INC(rmt_hitm);
630e843dec5SLeo Yan } else if (snoopx & P(SNOOPX, PEER)) {
631e843dec5SLeo Yan stats->rmt_hit++;
632e843dec5SLeo Yan PEER_INC(rmt_peer);
633e843dec5SLeo Yan }
634aadddd68SJiri Olsa }
635aadddd68SJiri Olsa
636aadddd68SJiri Olsa if ((lvl & P(LVL, MISS)))
637aadddd68SJiri Olsa stats->ld_miss++;
638aadddd68SJiri Olsa
639aadddd68SJiri Olsa } else if (op & P(OP, STORE)) {
640aadddd68SJiri Olsa /* store */
641aadddd68SJiri Olsa stats->store++;
642aadddd68SJiri Olsa
643aadddd68SJiri Olsa if (!daddr) {
644aadddd68SJiri Olsa stats->st_noadrs++;
645aadddd68SJiri Olsa return -1;
646aadddd68SJiri Olsa }
647aadddd68SJiri Olsa
648aadddd68SJiri Olsa if (lvl & P(LVL, HIT)) {
649aadddd68SJiri Olsa if (lvl & P(LVL, UNC)) stats->st_uncache++;
650aadddd68SJiri Olsa if (lvl & P(LVL, L1 )) stats->st_l1hit++;
651aadddd68SJiri Olsa }
652aadddd68SJiri Olsa if (lvl & P(LVL, MISS))
653aadddd68SJiri Olsa if (lvl & P(LVL, L1)) stats->st_l1miss++;
65498450637SLeo Yan if (lvl & P(LVL, NA))
65598450637SLeo Yan stats->st_na++;
656aadddd68SJiri Olsa } else {
657aadddd68SJiri Olsa /* unparsable data_src? */
658aadddd68SJiri Olsa stats->noparse++;
659aadddd68SJiri Olsa return -1;
660aadddd68SJiri Olsa }
661aadddd68SJiri Olsa
662d46a4cdfSArnaldo Carvalho de Melo if (!mi->daddr.ms.map || !mi->iaddr.ms.map) {
663aadddd68SJiri Olsa stats->nomap++;
664aadddd68SJiri Olsa return -1;
665aadddd68SJiri Olsa }
666aadddd68SJiri Olsa
667aadddd68SJiri Olsa #undef P
668dba8ab93SJiri Olsa #undef HITM_INC
669aadddd68SJiri Olsa return err;
670aadddd68SJiri Olsa }
6710a9a24ccSJiri Olsa
c2c_add_stats(struct c2c_stats * stats,struct c2c_stats * add)6720a9a24ccSJiri Olsa void c2c_add_stats(struct c2c_stats *stats, struct c2c_stats *add)
6730a9a24ccSJiri Olsa {
6740a9a24ccSJiri Olsa stats->nr_entries += add->nr_entries;
6750a9a24ccSJiri Olsa
6760a9a24ccSJiri Olsa stats->locks += add->locks;
6770a9a24ccSJiri Olsa stats->store += add->store;
6780a9a24ccSJiri Olsa stats->st_uncache += add->st_uncache;
6790a9a24ccSJiri Olsa stats->st_noadrs += add->st_noadrs;
6800a9a24ccSJiri Olsa stats->st_l1hit += add->st_l1hit;
6810a9a24ccSJiri Olsa stats->st_l1miss += add->st_l1miss;
68298450637SLeo Yan stats->st_na += add->st_na;
6830a9a24ccSJiri Olsa stats->load += add->load;
6840a9a24ccSJiri Olsa stats->ld_excl += add->ld_excl;
6850a9a24ccSJiri Olsa stats->ld_shared += add->ld_shared;
6860a9a24ccSJiri Olsa stats->ld_uncache += add->ld_uncache;
6870a9a24ccSJiri Olsa stats->ld_io += add->ld_io;
6880a9a24ccSJiri Olsa stats->ld_miss += add->ld_miss;
6890a9a24ccSJiri Olsa stats->ld_noadrs += add->ld_noadrs;
6900a9a24ccSJiri Olsa stats->ld_fbhit += add->ld_fbhit;
6910a9a24ccSJiri Olsa stats->ld_l1hit += add->ld_l1hit;
6920a9a24ccSJiri Olsa stats->ld_l2hit += add->ld_l2hit;
6930a9a24ccSJiri Olsa stats->ld_llchit += add->ld_llchit;
6940a9a24ccSJiri Olsa stats->lcl_hitm += add->lcl_hitm;
6950a9a24ccSJiri Olsa stats->rmt_hitm += add->rmt_hitm;
696dba8ab93SJiri Olsa stats->tot_hitm += add->tot_hitm;
697e843dec5SLeo Yan stats->lcl_peer += add->lcl_peer;
698e843dec5SLeo Yan stats->rmt_peer += add->rmt_peer;
699e843dec5SLeo Yan stats->tot_peer += add->tot_peer;
7000a9a24ccSJiri Olsa stats->rmt_hit += add->rmt_hit;
7010a9a24ccSJiri Olsa stats->lcl_dram += add->lcl_dram;
7020a9a24ccSJiri Olsa stats->rmt_dram += add->rmt_dram;
703d9d5d767SKan Liang stats->blk_data += add->blk_data;
704d9d5d767SKan Liang stats->blk_addr += add->blk_addr;
7050a9a24ccSJiri Olsa stats->nomap += add->nomap;
7060a9a24ccSJiri Olsa stats->noparse += add->noparse;
7070a9a24ccSJiri Olsa }
708