Linux Perf
mem-events.c
Go to the documentation of this file.
1 // SPDX-License-Identifier: GPL-2.0
2 #include <stddef.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <errno.h>
6 #include <sys/types.h>
7 #include <sys/stat.h>
8 #include <unistd.h>
9 #include <api/fs/fs.h>
10 #include <linux/kernel.h>
11 #include "mem-events.h"
12 #include "debug.h"
13 #include "symbol.h"
14 #include "sort.h"
15 
16 unsigned int perf_mem_events__loads_ldlat = 30;
17 
18 #define E(t, n, s) { .tag = t, .name = n, .sysfs_name = s }
19 
21  E("ldlat-loads", "cpu/mem-loads,ldlat=%u/P", "mem-loads"),
22  E("ldlat-stores", "cpu/mem-stores/P", "mem-stores"),
23 };
24 #undef E
25 
26 #undef E
27 
28 static char mem_loads_name[100];
30 
32 {
33  if (i == PERF_MEM_EVENTS__LOAD) {
34  if (!mem_loads_name__init) {
35  mem_loads_name__init = true;
36  scnprintf(mem_loads_name, sizeof(mem_loads_name),
37  perf_mem_events[i].name,
39  }
40  return mem_loads_name;
41  }
42 
43  return (char *)perf_mem_events[i].name;
44 }
45 
46 int perf_mem_events__parse(const char *str)
47 {
48  char *tok, *saveptr = NULL;
49  bool found = false;
50  char *buf;
51  int j;
52 
53  /* We need buffer that we know we can write to. */
54  buf = malloc(strlen(str) + 1);
55  if (!buf)
56  return -ENOMEM;
57 
58  strcpy(buf, str);
59 
60  tok = strtok_r((char *)buf, ",", &saveptr);
61 
62  while (tok) {
63  for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
64  struct perf_mem_event *e = &perf_mem_events[j];
65 
66  if (strstr(e->tag, tok))
67  e->record = found = true;
68  }
69 
70  tok = strtok_r(NULL, ",", &saveptr);
71  }
72 
73  free(buf);
74 
75  if (found)
76  return 0;
77 
78  pr_err("failed: event '%s' not found, use '-e list' to get list of available events\n", str);
79  return -1;
80 }
81 
83 {
84  const char *mnt = sysfs__mount();
85  bool found = false;
86  int j;
87 
88  if (!mnt)
89  return -ENOENT;
90 
91  for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
92  char path[PATH_MAX];
93  struct perf_mem_event *e = &perf_mem_events[j];
94  struct stat st;
95 
96  scnprintf(path, PATH_MAX, "%s/devices/cpu/events/%s",
97  mnt, e->sysfs_name);
98 
99  if (!stat(path, &st))
100  e->supported = found = true;
101  }
102 
103  return found ? 0 : -ENOENT;
104 }
105 
106 static const char * const tlb_access[] = {
107  "N/A",
108  "HIT",
109  "MISS",
110  "L1",
111  "L2",
112  "Walker",
113  "Fault",
114 };
115 
116 int perf_mem__tlb_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
117 {
118  size_t l = 0, i;
119  u64 m = PERF_MEM_TLB_NA;
120  u64 hit, miss;
121 
122  sz -= 1; /* -1 for null termination */
123  out[0] = '\0';
124 
125  if (mem_info)
126  m = mem_info->data_src.mem_dtlb;
127 
128  hit = m & PERF_MEM_TLB_HIT;
129  miss = m & PERF_MEM_TLB_MISS;
130 
131  /* already taken care of */
132  m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS);
133 
134  for (i = 0; m && i < ARRAY_SIZE(tlb_access); i++, m >>= 1) {
135  if (!(m & 0x1))
136  continue;
137  if (l) {
138  strcat(out, " or ");
139  l += 4;
140  }
141  l += scnprintf(out + l, sz - l, tlb_access[i]);
142  }
143  if (*out == '\0')
144  l += scnprintf(out, sz - l, "N/A");
145  if (hit)
146  l += scnprintf(out + l, sz - l, " hit");
147  if (miss)
148  l += scnprintf(out + l, sz - l, " miss");
149 
150  return l;
151 }
152 
153 static const char * const mem_lvl[] = {
154  "N/A",
155  "HIT",
156  "MISS",
157  "L1",
158  "LFB",
159  "L2",
160  "L3",
161  "Local RAM",
162  "Remote RAM (1 hop)",
163  "Remote RAM (2 hops)",
164  "Remote Cache (1 hop)",
165  "Remote Cache (2 hops)",
166  "I/O",
167  "Uncached",
168 };
169 
170 static const char * const mem_lvlnum[] = {
171  [PERF_MEM_LVLNUM_ANY_CACHE] = "Any cache",
172  [PERF_MEM_LVLNUM_LFB] = "LFB",
173  [PERF_MEM_LVLNUM_RAM] = "RAM",
174  [PERF_MEM_LVLNUM_PMEM] = "PMEM",
175  [PERF_MEM_LVLNUM_NA] = "N/A",
176 };
177 
178 int perf_mem__lvl_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
179 {
180  size_t i, l = 0;
181  u64 m = PERF_MEM_LVL_NA;
182  u64 hit, miss;
183  int printed;
184 
185  if (mem_info)
186  m = mem_info->data_src.mem_lvl;
187 
188  sz -= 1; /* -1 for null termination */
189  out[0] = '\0';
190 
191  hit = m & PERF_MEM_LVL_HIT;
192  miss = m & PERF_MEM_LVL_MISS;
193 
194  /* already taken care of */
195  m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS);
196 
197 
198  if (mem_info && mem_info->data_src.mem_remote) {
199  strcat(out, "Remote ");
200  l += 7;
201  }
202 
203  printed = 0;
204  for (i = 0; m && i < ARRAY_SIZE(mem_lvl); i++, m >>= 1) {
205  if (!(m & 0x1))
206  continue;
207  if (printed++) {
208  strcat(out, " or ");
209  l += 4;
210  }
211  l += scnprintf(out + l, sz - l, mem_lvl[i]);
212  }
213 
214  if (mem_info && mem_info->data_src.mem_lvl_num) {
215  int lvl = mem_info->data_src.mem_lvl_num;
216  if (printed++) {
217  strcat(out, " or ");
218  l += 4;
219  }
220  if (mem_lvlnum[lvl])
221  l += scnprintf(out + l, sz - l, mem_lvlnum[lvl]);
222  else
223  l += scnprintf(out + l, sz - l, "L%d", lvl);
224  }
225 
226  if (l == 0)
227  l += scnprintf(out + l, sz - l, "N/A");
228  if (hit)
229  l += scnprintf(out + l, sz - l, " hit");
230  if (miss)
231  l += scnprintf(out + l, sz - l, " miss");
232 
233  return l;
234 }
235 
236 static const char * const snoop_access[] = {
237  "N/A",
238  "None",
239  "Hit",
240  "Miss",
241  "HitM",
242 };
243 
244 int perf_mem__snp_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
245 {
246  size_t i, l = 0;
247  u64 m = PERF_MEM_SNOOP_NA;
248 
249  sz -= 1; /* -1 for null termination */
250  out[0] = '\0';
251 
252  if (mem_info)
253  m = mem_info->data_src.mem_snoop;
254 
255  for (i = 0; m && i < ARRAY_SIZE(snoop_access); i++, m >>= 1) {
256  if (!(m & 0x1))
257  continue;
258  if (l) {
259  strcat(out, " or ");
260  l += 4;
261  }
262  l += scnprintf(out + l, sz - l, snoop_access[i]);
263  }
264  if (mem_info &&
265  (mem_info->data_src.mem_snoopx & PERF_MEM_SNOOPX_FWD)) {
266  if (l) {
267  strcat(out, " or ");
268  l += 4;
269  }
270  l += scnprintf(out + l, sz - l, "Fwd");
271  }
272 
273  if (*out == '\0')
274  l += scnprintf(out, sz - l, "N/A");
275 
276  return l;
277 }
278 
279 int perf_mem__lck_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
280 {
281  u64 mask = PERF_MEM_LOCK_NA;
282  int l;
283 
284  if (mem_info)
285  mask = mem_info->data_src.mem_lock;
286 
287  if (mask & PERF_MEM_LOCK_NA)
288  l = scnprintf(out, sz, "N/A");
289  else if (mask & PERF_MEM_LOCK_LOCKED)
290  l = scnprintf(out, sz, "Yes");
291  else
292  l = scnprintf(out, sz, "No");
293 
294  return l;
295 }
296 
297 int perf_script__meminfo_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
298 {
299  int i = 0;
300 
301  i += perf_mem__lvl_scnprintf(out, sz, mem_info);
302  i += scnprintf(out + i, sz - i, "|SNP ");
303  i += perf_mem__snp_scnprintf(out + i, sz - i, mem_info);
304  i += scnprintf(out + i, sz - i, "|TLB ");
305  i += perf_mem__tlb_scnprintf(out + i, sz - i, mem_info);
306  i += scnprintf(out + i, sz - i, "|LCK ");
307  i += perf_mem__lck_scnprintf(out + i, sz - i, mem_info);
308 
309  return i;
310 }
311 
312 int c2c_decode_stats(struct c2c_stats *stats, struct mem_info *mi)
313 {
314  union perf_mem_data_src *data_src = &mi->data_src;
315  u64 daddr = mi->daddr.addr;
316  u64 op = data_src->mem_op;
317  u64 lvl = data_src->mem_lvl;
318  u64 snoop = data_src->mem_snoop;
319  u64 lock = data_src->mem_lock;
320  /*
321  * Skylake might report unknown remote level via this
322  * bit, consider it when evaluating remote HITMs.
323  */
324  bool mrem = data_src->mem_remote;
325  int err = 0;
326 
327 #define HITM_INC(__f) \
328 do { \
329  stats->__f++; \
330  stats->tot_hitm++; \
331 } while (0)
332 
333 #define P(a, b) PERF_MEM_##a##_##b
334 
335  stats->nr_entries++;
336 
337  if (lock & P(LOCK, LOCKED)) stats->locks++;
338 
339  if (op & P(OP, LOAD)) {
340  /* load */
341  stats->load++;
342 
343  if (!daddr) {
344  stats->ld_noadrs++;
345  return -1;
346  }
347 
348  if (lvl & P(LVL, HIT)) {
349  if (lvl & P(LVL, UNC)) stats->ld_uncache++;
350  if (lvl & P(LVL, IO)) stats->ld_io++;
351  if (lvl & P(LVL, LFB)) stats->ld_fbhit++;
352  if (lvl & P(LVL, L1 )) stats->ld_l1hit++;
353  if (lvl & P(LVL, L2 )) stats->ld_l2hit++;
354  if (lvl & P(LVL, L3 )) {
355  if (snoop & P(SNOOP, HITM))
356  HITM_INC(lcl_hitm);
357  else
358  stats->ld_llchit++;
359  }
360 
361  if (lvl & P(LVL, LOC_RAM)) {
362  stats->lcl_dram++;
363  if (snoop & P(SNOOP, HIT))
364  stats->ld_shared++;
365  else
366  stats->ld_excl++;
367  }
368 
369  if ((lvl & P(LVL, REM_RAM1)) ||
370  (lvl & P(LVL, REM_RAM2)) ||
371  mrem) {
372  stats->rmt_dram++;
373  if (snoop & P(SNOOP, HIT))
374  stats->ld_shared++;
375  else
376  stats->ld_excl++;
377  }
378  }
379 
380  if ((lvl & P(LVL, REM_CCE1)) ||
381  (lvl & P(LVL, REM_CCE2)) ||
382  mrem) {
383  if (snoop & P(SNOOP, HIT))
384  stats->rmt_hit++;
385  else if (snoop & P(SNOOP, HITM))
386  HITM_INC(rmt_hitm);
387  }
388 
389  if ((lvl & P(LVL, MISS)))
390  stats->ld_miss++;
391 
392  } else if (op & P(OP, STORE)) {
393  /* store */
394  stats->store++;
395 
396  if (!daddr) {
397  stats->st_noadrs++;
398  return -1;
399  }
400 
401  if (lvl & P(LVL, HIT)) {
402  if (lvl & P(LVL, UNC)) stats->st_uncache++;
403  if (lvl & P(LVL, L1 )) stats->st_l1hit++;
404  }
405  if (lvl & P(LVL, MISS))
406  if (lvl & P(LVL, L1)) stats->st_l1miss++;
407  } else {
408  /* unparsable data_src? */
409  stats->noparse++;
410  return -1;
411  }
412 
413  if (!mi->daddr.map || !mi->iaddr.map) {
414  stats->nomap++;
415  return -1;
416  }
417 
418 #undef P
419 #undef HITM_INC
420  return err;
421 }
422 
423 void c2c_add_stats(struct c2c_stats *stats, struct c2c_stats *add)
424 {
425  stats->nr_entries += add->nr_entries;
426 
427  stats->locks += add->locks;
428  stats->store += add->store;
429  stats->st_uncache += add->st_uncache;
430  stats->st_noadrs += add->st_noadrs;
431  stats->st_l1hit += add->st_l1hit;
432  stats->st_l1miss += add->st_l1miss;
433  stats->load += add->load;
434  stats->ld_excl += add->ld_excl;
435  stats->ld_shared += add->ld_shared;
436  stats->ld_uncache += add->ld_uncache;
437  stats->ld_io += add->ld_io;
438  stats->ld_miss += add->ld_miss;
439  stats->ld_noadrs += add->ld_noadrs;
440  stats->ld_fbhit += add->ld_fbhit;
441  stats->ld_l1hit += add->ld_l1hit;
442  stats->ld_l2hit += add->ld_l2hit;
443  stats->ld_llchit += add->ld_llchit;
444  stats->lcl_hitm += add->lcl_hitm;
445  stats->rmt_hitm += add->rmt_hitm;
446  stats->tot_hitm += add->tot_hitm;
447  stats->rmt_hit += add->rmt_hit;
448  stats->lcl_dram += add->lcl_dram;
449  stats->rmt_dram += add->rmt_dram;
450  stats->nomap += add->nomap;
451  stats->noparse += add->noparse;
452 }
struct map * map
Definition: symbol.h:185
u32 ld_noadrs
Definition: mem-events.h:56
u32 st_l1miss
Definition: mem-events.h:49
#define E(t, n, s)
Definition: mem-events.c:18
u32 ld_io
Definition: mem-events.h:54
u32 ld_llchit
Definition: mem-events.h:60
u32 rmt_dram
Definition: mem-events.h:66
int int err
Definition: 5sec.c:44
u32 ld_miss
Definition: mem-events.h:55
static const char *const mem_lvl[]
Definition: mem-events.c:153
int perf_mem_events__init(void)
Definition: mem-events.c:82
u32 st_noadrs
Definition: mem-events.h:47
u32 ld_shared
Definition: mem-events.h:52
struct addr_map_symbol daddr
Definition: symbol.h:202
u32 ld_uncache
Definition: mem-events.h:53
u32 nr_entries
Definition: mem-events.h:42
u32 lcl_dram
Definition: mem-events.h:65
u32 tot_hitm
Definition: mem-events.h:63
u32 ld_l2hit
Definition: mem-events.h:59
unsigned int perf_mem_events__loads_ldlat
Definition: mem-events.c:16
#define pr_err(fmt,...)
Definition: json.h:21
#define HITM_INC(__f)
int perf_mem__snp_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
Definition: mem-events.c:244
void * malloc(YYSIZE_T)
int perf_mem__lvl_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
Definition: mem-events.c:178
u32 nomap
Definition: mem-events.h:67
char * perf_mem_events__name(int i)
Definition: mem-events.c:31
#define P(a, b)
const char * name
int perf_mem__tlb_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
Definition: mem-events.c:116
static const char *const snoop_access[]
Definition: mem-events.c:236
u32 ld_l1hit
Definition: mem-events.h:58
u32 st_uncache
Definition: mem-events.h:46
#define PATH_MAX
Definition: jevents.c:1042
static int str(yyscan_t scanner, int token)
union perf_mem_data_src data_src
Definition: symbol.h:203
int perf_mem__lck_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
Definition: mem-events.c:279
static bool mem_loads_name__init
Definition: mem-events.c:29
int perf_script__meminfo_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
Definition: mem-events.c:297
u32 ld_fbhit
Definition: mem-events.h:57
u32 load
Definition: mem-events.h:50
static const char *const mem_lvlnum[]
Definition: mem-events.c:170
Definition: stat.h:10
int perf_mem_events__parse(const char *str)
Definition: mem-events.c:46
const char * sysfs_name
Definition: mem-events.h:16
u32 rmt_hitm
Definition: mem-events.h:62
static char mem_loads_name[100]
Definition: mem-events.c:28
void free(void *)
u32 rmt_hit
Definition: mem-events.h:64
u32 ld_excl
Definition: mem-events.h:51
const char * tag
Definition: mem-events.h:14
struct addr_map_symbol iaddr
Definition: symbol.h:201
u32 lcl_hitm
Definition: mem-events.h:61
u32 noparse
Definition: mem-events.h:68
u32 st_l1hit
Definition: mem-events.h:48
u32 locks
Definition: mem-events.h:44
static const char *const tlb_access[]
Definition: mem-events.c:106
const char * name
Definition: mem-events.h:15
int c2c_decode_stats(struct c2c_stats *stats, struct mem_info *mi)
Definition: mem-events.c:312
u32 store
Definition: mem-events.h:45
struct perf_mem_event perf_mem_events[PERF_MEM_EVENTS__MAX]
Definition: mem-events.c:20
void c2c_add_stats(struct c2c_stats *stats, struct c2c_stats *add)
Definition: mem-events.c:423