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

~ [ 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