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 int 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 l += scnprintf(out + l, sz - l, tlb_access[i]); 124 } 125 if (*out == '\0') 126 l += scnprintf(out, sz - l, "N/A"); 127 if (hit) 128 l += scnprintf(out + l, sz - l, " hit"); 129 if (miss) 130 l += scnprintf(out + l, sz - l, " miss"); 131 132 return l; 133 } 134 135 static 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 152 int 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 l += scnprintf(out + l, sz - l, mem_lvl[i]); 178 } 179 if (*out == '\0') 180 l += scnprintf(out, sz - l, "N/A"); 181 if (hit) 182 l += scnprintf(out + l, sz - l, " hit"); 183 if (miss) 184 l += scnprintf(out + l, sz - l, " miss"); 185 186 return l; 187 } 188 189 static const char * const snoop_access[] = { 190 "N/A", 191 "None", 192 "Miss", 193 "Hit", 194 "HitM", 195 }; 196 197 int perf_mem__snp_scnprintf(char *out, size_t sz, struct mem_info *mem_info) 198 { 199 size_t i, l = 0; 200 u64 m = PERF_MEM_SNOOP_NA; 201 202 sz -= 1; /* -1 for null termination */ 203 out[0] = '\0'; 204 205 if (mem_info) 206 m = mem_info->data_src.mem_snoop; 207 208 for (i = 0; m && i < ARRAY_SIZE(snoop_access); i++, m >>= 1) { 209 if (!(m & 0x1)) 210 continue; 211 if (l) { 212 strcat(out, " or "); 213 l += 4; 214 } 215 l += scnprintf(out + l, sz - l, snoop_access[i]); 216 } 217 218 if (*out == '\0') 219 l += scnprintf(out, sz - l, "N/A"); 220 221 return l; 222 } 223 224 int perf_mem__lck_scnprintf(char *out, size_t sz, struct mem_info *mem_info) 225 { 226 u64 mask = PERF_MEM_LOCK_NA; 227 int l; 228 229 if (mem_info) 230 mask = mem_info->data_src.mem_lock; 231 232 if (mask & PERF_MEM_LOCK_NA) 233 l = scnprintf(out, sz, "N/A"); 234 else if (mask & PERF_MEM_LOCK_LOCKED) 235 l = scnprintf(out, sz, "Yes"); 236 else 237 l = scnprintf(out, sz, "No"); 238 239 return l; 240 } 241 242 int perf_script__meminfo_scnprintf(char *out, size_t sz, struct mem_info *mem_info) 243 { 244 int i = 0; 245 246 i += perf_mem__lvl_scnprintf(out, sz, mem_info); 247 i += scnprintf(out + i, sz - i, "|SNP "); 248 i += perf_mem__snp_scnprintf(out + i, sz - i, mem_info); 249 i += scnprintf(out + i, sz - i, "|TLB "); 250 i += perf_mem__tlb_scnprintf(out + i, sz - i, mem_info); 251 i += scnprintf(out + i, sz - i, "|LCK "); 252 i += perf_mem__lck_scnprintf(out + i, sz - i, mem_info); 253 254 return i; 255 } 256