1 // SPDX-License-Identifier: GPL-2.0
10 #include <linux/kernel.h>
11 #include "mem-events.h"
15 unsigned int perf_mem_events__loads_ldlat = 30;
17 #define E(t, n, s) { .tag = t, .name = n, .sysfs_name = s }
19 struct perf_mem_event perf_mem_events[PERF_MEM_EVENTS__MAX] = {
20 E("ldlat-loads", "cpu/mem-loads,ldlat=%u/P", "mem-loads"),
21 E("ldlat-stores", "cpu/mem-stores/P", "mem-stores"),
27 static char mem_loads_name[100];
28 static bool mem_loads_name__init;
30 char * __weak perf_mem_events__name(int i)
32 if (i == PERF_MEM_EVENTS__LOAD) {
33 if (!mem_loads_name__init) {
34 mem_loads_name__init = true;
35 scnprintf(mem_loads_name, sizeof(mem_loads_name),
36 perf_mem_events[i].name,
37 perf_mem_events__loads_ldlat);
39 return mem_loads_name;
42 return (char *)perf_mem_events[i].name;
45 int perf_mem_events__parse(const char *str)
47 char *tok, *saveptr = NULL;
52 /* We need buffer that we know we can write to. */
53 buf = malloc(strlen(str) + 1);
59 tok = strtok_r((char *)buf, ",", &saveptr);
62 for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
63 struct perf_mem_event *e = &perf_mem_events[j];
65 if (strstr(e->tag, tok))
66 e->record = found = true;
69 tok = strtok_r(NULL, ",", &saveptr);
77 pr_err("failed: event '%s' not found, use '-e list' to get list of available events\n", str);
81 int perf_mem_events__init(void)
83 const char *mnt = sysfs__mount();
90 for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
92 struct perf_mem_event *e = &perf_mem_events[j];
95 scnprintf(path, PATH_MAX, "%s/devices/cpu/events/%s",
99 e->supported = found = true;
102 return found ? 0 : -ENOENT;
105 static const char * const tlb_access[] = {
115 int perf_mem__tlb_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
118 u64 m = PERF_MEM_TLB_NA;
121 sz -= 1; /* -1 for null termination */
125 m = mem_info->data_src.mem_dtlb;
127 hit = m & PERF_MEM_TLB_HIT;
128 miss = m & PERF_MEM_TLB_MISS;
130 /* already taken care of */
131 m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS);
133 for (i = 0; m && i < ARRAY_SIZE(tlb_access); i++, m >>= 1) {
140 l += scnprintf(out + l, sz - l, tlb_access[i]);
143 l += scnprintf(out, sz - l, "N/A");
145 l += scnprintf(out + l, sz - l, " hit");
147 l += scnprintf(out + l, sz - l, " miss");
152 static const char * const mem_lvl[] = {
161 "Remote RAM (1 hop)",
162 "Remote RAM (2 hops)",
163 "Remote Cache (1 hop)",
164 "Remote Cache (2 hops)",
169 static const char * const mem_lvlnum[] = {
170 [PERF_MEM_LVLNUM_ANY_CACHE] = "Any cache",
171 [PERF_MEM_LVLNUM_LFB] = "LFB",
172 [PERF_MEM_LVLNUM_RAM] = "RAM",
173 [PERF_MEM_LVLNUM_PMEM] = "PMEM",
174 [PERF_MEM_LVLNUM_NA] = "N/A",
177 int perf_mem__lvl_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
180 u64 m = PERF_MEM_LVL_NA;
185 m = mem_info->data_src.mem_lvl;
187 sz -= 1; /* -1 for null termination */
190 hit = m & PERF_MEM_LVL_HIT;
191 miss = m & PERF_MEM_LVL_MISS;
193 /* already taken care of */
194 m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS);
197 if (mem_info && mem_info->data_src.mem_remote) {
198 strcat(out, "Remote ");
203 for (i = 0; m && i < ARRAY_SIZE(mem_lvl); i++, m >>= 1) {
210 l += scnprintf(out + l, sz - l, mem_lvl[i]);
213 if (mem_info && mem_info->data_src.mem_lvl_num) {
214 int lvl = mem_info->data_src.mem_lvl_num;
220 l += scnprintf(out + l, sz - l, mem_lvlnum[lvl]);
222 l += scnprintf(out + l, sz - l, "L%d", lvl);
226 l += scnprintf(out + l, sz - l, "N/A");
228 l += scnprintf(out + l, sz - l, " hit");
230 l += scnprintf(out + l, sz - l, " miss");
235 static const char * const snoop_access[] = {
243 int perf_mem__snp_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
246 u64 m = PERF_MEM_SNOOP_NA;
248 sz -= 1; /* -1 for null termination */
252 m = mem_info->data_src.mem_snoop;
254 for (i = 0; m && i < ARRAY_SIZE(snoop_access); i++, m >>= 1) {
261 l += scnprintf(out + l, sz - l, snoop_access[i]);
264 (mem_info->data_src.mem_snoopx & PERF_MEM_SNOOPX_FWD)) {
269 l += scnprintf(out + l, sz - l, "Fwd");
273 l += scnprintf(out, sz - l, "N/A");
278 int perf_mem__lck_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
280 u64 mask = PERF_MEM_LOCK_NA;
284 mask = mem_info->data_src.mem_lock;
286 if (mask & PERF_MEM_LOCK_NA)
287 l = scnprintf(out, sz, "N/A");
288 else if (mask & PERF_MEM_LOCK_LOCKED)
289 l = scnprintf(out, sz, "Yes");
291 l = scnprintf(out, sz, "No");
296 int perf_script__meminfo_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
300 i += perf_mem__lvl_scnprintf(out, sz, mem_info);
301 i += scnprintf(out + i, sz - i, "|SNP ");
302 i += perf_mem__snp_scnprintf(out + i, sz - i, mem_info);
303 i += scnprintf(out + i, sz - i, "|TLB ");
304 i += perf_mem__tlb_scnprintf(out + i, sz - i, mem_info);
305 i += scnprintf(out + i, sz - i, "|LCK ");
306 i += perf_mem__lck_scnprintf(out + i, sz - i, mem_info);
311 int c2c_decode_stats(struct c2c_stats *stats, struct mem_info *mi)
313 union perf_mem_data_src *data_src = &mi->data_src;
314 u64 daddr = mi->daddr.addr;
315 u64 op = data_src->mem_op;
316 u64 lvl = data_src->mem_lvl;
317 u64 snoop = data_src->mem_snoop;
318 u64 lock = data_src->mem_lock;
320 * Skylake might report unknown remote level via this
321 * bit, consider it when evaluating remote HITMs.
323 bool mrem = data_src->mem_remote;
326 #define HITM_INC(__f) \
332 #define P(a, b) PERF_MEM_##a##_##b
336 if (lock & P(LOCK, LOCKED)) stats->locks++;
338 if (op & P(OP, LOAD)) {
347 if (lvl & P(LVL, HIT)) {
348 if (lvl & P(LVL, UNC)) stats->ld_uncache++;
349 if (lvl & P(LVL, IO)) stats->ld_io++;
350 if (lvl & P(LVL, LFB)) stats->ld_fbhit++;
351 if (lvl & P(LVL, L1 )) stats->ld_l1hit++;
352 if (lvl & P(LVL, L2 )) stats->ld_l2hit++;
353 if (lvl & P(LVL, L3 )) {
354 if (snoop & P(SNOOP, HITM))
360 if (lvl & P(LVL, LOC_RAM)) {
362 if (snoop & P(SNOOP, HIT))
368 if ((lvl & P(LVL, REM_RAM1)) ||
369 (lvl & P(LVL, REM_RAM2)) ||
372 if (snoop & P(SNOOP, HIT))
379 if ((lvl & P(LVL, REM_CCE1)) ||
380 (lvl & P(LVL, REM_CCE2)) ||
382 if (snoop & P(SNOOP, HIT))
384 else if (snoop & P(SNOOP, HITM))
388 if ((lvl & P(LVL, MISS)))
391 } else if (op & P(OP, STORE)) {
400 if (lvl & P(LVL, HIT)) {
401 if (lvl & P(LVL, UNC)) stats->st_uncache++;
402 if (lvl & P(LVL, L1 )) stats->st_l1hit++;
404 if (lvl & P(LVL, MISS))
405 if (lvl & P(LVL, L1)) stats->st_l1miss++;
407 /* unparsable data_src? */
412 if (!mi->daddr.map || !mi->iaddr.map) {
422 void c2c_add_stats(struct c2c_stats *stats, struct c2c_stats *add)
424 stats->nr_entries += add->nr_entries;
426 stats->locks += add->locks;
427 stats->store += add->store;
428 stats->st_uncache += add->st_uncache;
429 stats->st_noadrs += add->st_noadrs;
430 stats->st_l1hit += add->st_l1hit;
431 stats->st_l1miss += add->st_l1miss;
432 stats->load += add->load;
433 stats->ld_excl += add->ld_excl;
434 stats->ld_shared += add->ld_shared;
435 stats->ld_uncache += add->ld_uncache;
436 stats->ld_io += add->ld_io;
437 stats->ld_miss += add->ld_miss;
438 stats->ld_noadrs += add->ld_noadrs;
439 stats->ld_fbhit += add->ld_fbhit;
440 stats->ld_l1hit += add->ld_l1hit;
441 stats->ld_l2hit += add->ld_l2hit;
442 stats->ld_llchit += add->ld_llchit;
443 stats->lcl_hitm += add->lcl_hitm;
444 stats->rmt_hitm += add->rmt_hitm;
445 stats->tot_hitm += add->tot_hitm;
446 stats->rmt_hit += add->rmt_hit;
447 stats->lcl_dram += add->lcl_dram;
448 stats->rmt_dram += add->rmt_dram;
449 stats->nomap += add->nomap;
450 stats->noparse += add->noparse;