perf tools: Introduce perf_mem__snp_scnprintf function
[cascardo/linux.git] / tools / perf / util / mem-events.c
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 "mem-events.h"
10 #include "debug.h"
11 #include "symbol.h"
12
13 #define E(t, n, s) { .tag = t, .name = n, .sysfs_name = s }
14
15 struct perf_mem_event perf_mem_events[PERF_MEM_EVENTS__MAX] = {
16         E("ldlat-loads",        "cpu/mem-loads,ldlat=30/P",     "mem-loads"),
17         E("ldlat-stores",       "cpu/mem-stores/P",             "mem-stores"),
18 };
19 #undef E
20
21 #undef E
22
23 char *perf_mem_events__name(int i)
24 {
25         return (char *)perf_mem_events[i].name;
26 }
27
28 int perf_mem_events__parse(const char *str)
29 {
30         char *tok, *saveptr = NULL;
31         bool found = false;
32         char *buf;
33         int j;
34
35         /* We need buffer that we know we can write to. */
36         buf = malloc(strlen(str) + 1);
37         if (!buf)
38                 return -ENOMEM;
39
40         strcpy(buf, str);
41
42         tok = strtok_r((char *)buf, ",", &saveptr);
43
44         while (tok) {
45                 for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
46                         struct perf_mem_event *e = &perf_mem_events[j];
47
48                         if (strstr(e->tag, tok))
49                                 e->record = found = true;
50                 }
51
52                 tok = strtok_r(NULL, ",", &saveptr);
53         }
54
55         free(buf);
56
57         if (found)
58                 return 0;
59
60         pr_err("failed: event '%s' not found, use '-e list' to get list of available events\n", str);
61         return -1;
62 }
63
64 int perf_mem_events__init(void)
65 {
66         const char *mnt = sysfs__mount();
67         bool found = false;
68         int j;
69
70         if (!mnt)
71                 return -ENOENT;
72
73         for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
74                 char path[PATH_MAX];
75                 struct perf_mem_event *e = &perf_mem_events[j];
76                 struct stat st;
77
78                 scnprintf(path, PATH_MAX, "%s/devices/cpu/events/%s",
79                           mnt, e->sysfs_name);
80
81                 if (!stat(path, &st))
82                         e->supported = found = true;
83         }
84
85         return found ? 0 : -ENOENT;
86 }
87
88 static const char * const tlb_access[] = {
89         "N/A",
90         "HIT",
91         "MISS",
92         "L1",
93         "L2",
94         "Walker",
95         "Fault",
96 };
97
98 void perf_mem__tlb_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
99 {
100         size_t l = 0, i;
101         u64 m = PERF_MEM_TLB_NA;
102         u64 hit, miss;
103
104         sz -= 1; /* -1 for null termination */
105         out[0] = '\0';
106
107         if (mem_info)
108                 m = mem_info->data_src.mem_dtlb;
109
110         hit = m & PERF_MEM_TLB_HIT;
111         miss = m & PERF_MEM_TLB_MISS;
112
113         /* already taken care of */
114         m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS);
115
116         for (i = 0; m && i < ARRAY_SIZE(tlb_access); i++, m >>= 1) {
117                 if (!(m & 0x1))
118                         continue;
119                 if (l) {
120                         strcat(out, " or ");
121                         l += 4;
122                 }
123                 strncat(out, tlb_access[i], sz - l);
124                 l += strlen(tlb_access[i]);
125         }
126         if (*out == '\0')
127                 strcpy(out, "N/A");
128         if (hit)
129                 strncat(out, " hit", sz - l);
130         if (miss)
131                 strncat(out, " miss", sz - l);
132 }
133
134 static const char * const mem_lvl[] = {
135         "N/A",
136         "HIT",
137         "MISS",
138         "L1",
139         "LFB",
140         "L2",
141         "L3",
142         "Local RAM",
143         "Remote RAM (1 hop)",
144         "Remote RAM (2 hops)",
145         "Remote Cache (1 hop)",
146         "Remote Cache (2 hops)",
147         "I/O",
148         "Uncached",
149 };
150
151 void perf_mem__lvl_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
152 {
153         size_t i, l = 0;
154         u64 m =  PERF_MEM_LVL_NA;
155         u64 hit, miss;
156
157         if (mem_info)
158                 m  = mem_info->data_src.mem_lvl;
159
160         sz -= 1; /* -1 for null termination */
161         out[0] = '\0';
162
163         hit = m & PERF_MEM_LVL_HIT;
164         miss = m & PERF_MEM_LVL_MISS;
165
166         /* already taken care of */
167         m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS);
168
169         for (i = 0; m && i < ARRAY_SIZE(mem_lvl); i++, m >>= 1) {
170                 if (!(m & 0x1))
171                         continue;
172                 if (l) {
173                         strcat(out, " or ");
174                         l += 4;
175                 }
176                 strncat(out, mem_lvl[i], sz - l);
177                 l += strlen(mem_lvl[i]);
178         }
179         if (*out == '\0')
180                 strcpy(out, "N/A");
181         if (hit)
182                 strncat(out, " hit", sz - l);
183         if (miss)
184                 strncat(out, " miss", sz - l);
185 }
186
187 static const char * const snoop_access[] = {
188         "N/A",
189         "None",
190         "Miss",
191         "Hit",
192         "HitM",
193 };
194
195 void perf_mem__snp_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
196 {
197         size_t i, l = 0;
198         u64 m = PERF_MEM_SNOOP_NA;
199
200         sz -= 1; /* -1 for null termination */
201         out[0] = '\0';
202
203         if (mem_info)
204                 m = mem_info->data_src.mem_snoop;
205
206         for (i = 0; m && i < ARRAY_SIZE(snoop_access); i++, m >>= 1) {
207                 if (!(m & 0x1))
208                         continue;
209                 if (l) {
210                         strcat(out, " or ");
211                         l += 4;
212                 }
213                 strncat(out, snoop_access[i], sz - l);
214                 l += strlen(snoop_access[i]);
215         }
216
217         if (*out == '\0')
218                 strcpy(out, "N/A");
219 }