blob: b58d32e1c80ade21ec3a33e0af5098e99db0f187 [file] [log] [blame]
Jiri Olsace1e22b2016-02-15 09:34:35 +01001#include <stddef.h>
2#include <stdlib.h>
3#include <string.h>
4#include <errno.h>
Jiri Olsa54fbad52016-02-24 09:46:42 +01005#include <sys/types.h>
6#include <sys/stat.h>
7#include <unistd.h>
8#include <api/fs/fs.h>
Jiri Olsaacbe6132016-02-15 09:34:34 +01009#include "mem-events.h"
Jiri Olsace1e22b2016-02-15 09:34:35 +010010#include "debug.h"
Jiri Olsa0c877d72016-02-24 09:46:46 +010011#include "symbol.h"
Jiri Olsaacbe6132016-02-15 09:34:34 +010012
Jiri Olsa54fbad52016-02-24 09:46:42 +010013#define E(t, n, s) { .tag = t, .name = n, .sysfs_name = s }
Jiri Olsaacbe6132016-02-15 09:34:34 +010014
15struct perf_mem_event perf_mem_events[PERF_MEM_EVENTS__MAX] = {
Jiri Olsa54fbad52016-02-24 09:46:42 +010016 E("ldlat-loads", "cpu/mem-loads,ldlat=30/P", "mem-loads"),
17 E("ldlat-stores", "cpu/mem-stores/P", "mem-stores"),
Jiri Olsaacbe6132016-02-15 09:34:34 +010018};
Jiri Olsa54fbad52016-02-24 09:46:42 +010019#undef E
Jiri Olsaacbe6132016-02-15 09:34:34 +010020
21#undef E
Jiri Olsace1e22b2016-02-15 09:34:35 +010022
Jiri Olsa2ba7ac52016-02-24 09:46:43 +010023char *perf_mem_events__name(int i)
24{
25 return (char *)perf_mem_events[i].name;
26}
27
Jiri Olsace1e22b2016-02-15 09:34:35 +010028int 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}
Jiri Olsa54fbad52016-02-24 09:46:42 +010063
64int 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}
Jiri Olsa0c877d72016-02-24 09:46:46 +010087
88static const char * const tlb_access[] = {
89 "N/A",
90 "HIT",
91 "MISS",
92 "L1",
93 "L2",
94 "Walker",
95 "Fault",
96};
97
Jiri Olsab1a5fbea2016-02-24 09:46:50 +010098int perf_mem__tlb_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
Jiri Olsa0c877d72016-02-24 09:46:46 +010099{
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 }
Jiri Olsab1a5fbea2016-02-24 09:46:50 +0100123 l += scnprintf(out + l, sz - l, tlb_access[i]);
Jiri Olsa0c877d72016-02-24 09:46:46 +0100124 }
125 if (*out == '\0')
Jiri Olsab1a5fbea2016-02-24 09:46:50 +0100126 l += scnprintf(out, sz - l, "N/A");
Jiri Olsa0c877d72016-02-24 09:46:46 +0100127 if (hit)
Jiri Olsab1a5fbea2016-02-24 09:46:50 +0100128 l += scnprintf(out + l, sz - l, " hit");
Jiri Olsa0c877d72016-02-24 09:46:46 +0100129 if (miss)
Jiri Olsab1a5fbea2016-02-24 09:46:50 +0100130 l += scnprintf(out + l, sz - l, " miss");
131
132 return l;
Jiri Olsa0c877d72016-02-24 09:46:46 +0100133}
Jiri Olsa071e9a12016-02-24 09:46:47 +0100134
135static const char * const mem_lvl[] = {
136 "N/A",
137 "HIT",
138 "MISS",
139 "L1",
140 "LFB",
141 "L2",
142 "L3",
143 "Local RAM",
144 "Remote RAM (1 hop)",
145 "Remote RAM (2 hops)",
146 "Remote Cache (1 hop)",
147 "Remote Cache (2 hops)",
148 "I/O",
149 "Uncached",
150};
151
152void perf_mem__lvl_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
153{
154 size_t i, l = 0;
155 u64 m = PERF_MEM_LVL_NA;
156 u64 hit, miss;
157
158 if (mem_info)
159 m = mem_info->data_src.mem_lvl;
160
161 sz -= 1; /* -1 for null termination */
162 out[0] = '\0';
163
164 hit = m & PERF_MEM_LVL_HIT;
165 miss = m & PERF_MEM_LVL_MISS;
166
167 /* already taken care of */
168 m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS);
169
170 for (i = 0; m && i < ARRAY_SIZE(mem_lvl); i++, m >>= 1) {
171 if (!(m & 0x1))
172 continue;
173 if (l) {
174 strcat(out, " or ");
175 l += 4;
176 }
177 strncat(out, mem_lvl[i], sz - l);
178 l += strlen(mem_lvl[i]);
179 }
180 if (*out == '\0')
181 strcpy(out, "N/A");
182 if (hit)
183 strncat(out, " hit", sz - l);
184 if (miss)
185 strncat(out, " miss", sz - l);
186}
Jiri Olsa2c07af12016-02-24 09:46:48 +0100187
188static const char * const snoop_access[] = {
189 "N/A",
190 "None",
191 "Miss",
192 "Hit",
193 "HitM",
194};
195
196void perf_mem__snp_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
197{
198 size_t i, l = 0;
199 u64 m = PERF_MEM_SNOOP_NA;
200
201 sz -= 1; /* -1 for null termination */
202 out[0] = '\0';
203
204 if (mem_info)
205 m = mem_info->data_src.mem_snoop;
206
207 for (i = 0; m && i < ARRAY_SIZE(snoop_access); i++, m >>= 1) {
208 if (!(m & 0x1))
209 continue;
210 if (l) {
211 strcat(out, " or ");
212 l += 4;
213 }
214 strncat(out, snoop_access[i], sz - l);
215 l += strlen(snoop_access[i]);
216 }
217
218 if (*out == '\0')
219 strcpy(out, "N/A");
220}
Jiri Olsa69a77272016-02-24 09:46:49 +0100221
222void perf_mem__lck_scnprintf(char *out, size_t sz __maybe_unused,
223 struct mem_info *mem_info)
224{
225 u64 mask = PERF_MEM_LOCK_NA;
226
227 if (mem_info)
228 mask = mem_info->data_src.mem_lock;
229
230 if (mask & PERF_MEM_LOCK_NA)
231 strncat(out, "N/A", 3);
232 else if (mask & PERF_MEM_LOCK_LOCKED)
233 strncat(out, "Yes", 3);
234 else
235 strncat(out, "No", 2);
236}