blob: 9844e3e36c1d6874cbd9814dc7c9d62961344ce3 [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
98void 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}
Jiri Olsa071e9a12016-02-24 09:46:47 +0100133
134static 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
151void 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}
Jiri Olsa2c07af12016-02-24 09:46:48 +0100186
187static const char * const snoop_access[] = {
188 "N/A",
189 "None",
190 "Miss",
191 "Hit",
192 "HitM",
193};
194
195void 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}
Jiri Olsa69a77272016-02-24 09:46:49 +0100220
221void perf_mem__lck_scnprintf(char *out, size_t sz __maybe_unused,
222 struct mem_info *mem_info)
223{
224 u64 mask = PERF_MEM_LOCK_NA;
225
226 if (mem_info)
227 mask = mem_info->data_src.mem_lock;
228
229 if (mask & PERF_MEM_LOCK_NA)
230 strncat(out, "N/A", 3);
231 else if (mask & PERF_MEM_LOCK_LOCKED)
232 strncat(out, "Yes", 3);
233 else
234 strncat(out, "No", 2);
235}