~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/perf/util/mem-events.c

Version: ~ [ linux-5.15-rc5 ] ~ [ linux-5.14.11 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.72 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.152 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.210 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.250 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.286 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.288 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.18.140 ] ~ [ linux-3.16.85 ] ~ [ linux-3.14.79 ] ~ [ linux-3.12.74 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 "map_symbol.h"
 12 #include "mem-events.h"
 13 #include "debug.h"
 14 #include "symbol.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 
 20 struct perf_mem_event perf_mem_events[PERF_MEM_EVENTS__MAX] = {
 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];
 29 static bool mem_loads_name__init;
 30 
 31 char * __weak perf_mem_events__name(int i)
 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,
 38                                   perf_mem_events__loads_ldlat);
 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 
 82 int perf_mem_events__init(void)
 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.ms.map || !mi->iaddr.ms.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 }
453 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp