1ce1e22b0SJiri Olsa #include <stddef.h> 2ce1e22b0SJiri Olsa #include <stdlib.h> 3ce1e22b0SJiri Olsa #include <string.h> 4ce1e22b0SJiri Olsa #include <errno.h> 554fbad54SJiri Olsa #include <sys/types.h> 654fbad54SJiri Olsa #include <sys/stat.h> 754fbad54SJiri Olsa #include <unistd.h> 854fbad54SJiri Olsa #include <api/fs/fs.h> 9acbe613eSJiri Olsa #include "mem-events.h" 10ce1e22b0SJiri Olsa #include "debug.h" 110c877d75SJiri Olsa #include "symbol.h" 12acbe613eSJiri Olsa 1354fbad54SJiri Olsa #define E(t, n, s) { .tag = t, .name = n, .sysfs_name = s } 14acbe613eSJiri Olsa 15acbe613eSJiri Olsa struct perf_mem_event perf_mem_events[PERF_MEM_EVENTS__MAX] = { 1654fbad54SJiri Olsa E("ldlat-loads", "cpu/mem-loads,ldlat=30/P", "mem-loads"), 1754fbad54SJiri Olsa E("ldlat-stores", "cpu/mem-stores/P", "mem-stores"), 18acbe613eSJiri Olsa }; 1954fbad54SJiri Olsa #undef E 20acbe613eSJiri Olsa 21acbe613eSJiri Olsa #undef E 22ce1e22b0SJiri Olsa 232ba7ac58SJiri Olsa char *perf_mem_events__name(int i) 242ba7ac58SJiri Olsa { 252ba7ac58SJiri Olsa return (char *)perf_mem_events[i].name; 262ba7ac58SJiri Olsa } 272ba7ac58SJiri Olsa 28ce1e22b0SJiri Olsa int perf_mem_events__parse(const char *str) 29ce1e22b0SJiri Olsa { 30ce1e22b0SJiri Olsa char *tok, *saveptr = NULL; 31ce1e22b0SJiri Olsa bool found = false; 32ce1e22b0SJiri Olsa char *buf; 33ce1e22b0SJiri Olsa int j; 34ce1e22b0SJiri Olsa 35ce1e22b0SJiri Olsa /* We need buffer that we know we can write to. */ 36ce1e22b0SJiri Olsa buf = malloc(strlen(str) + 1); 37ce1e22b0SJiri Olsa if (!buf) 38ce1e22b0SJiri Olsa return -ENOMEM; 39ce1e22b0SJiri Olsa 40ce1e22b0SJiri Olsa strcpy(buf, str); 41ce1e22b0SJiri Olsa 42ce1e22b0SJiri Olsa tok = strtok_r((char *)buf, ",", &saveptr); 43ce1e22b0SJiri Olsa 44ce1e22b0SJiri Olsa while (tok) { 45ce1e22b0SJiri Olsa for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) { 46ce1e22b0SJiri Olsa struct perf_mem_event *e = &perf_mem_events[j]; 47ce1e22b0SJiri Olsa 48ce1e22b0SJiri Olsa if (strstr(e->tag, tok)) 49ce1e22b0SJiri Olsa e->record = found = true; 50ce1e22b0SJiri Olsa } 51ce1e22b0SJiri Olsa 52ce1e22b0SJiri Olsa tok = strtok_r(NULL, ",", &saveptr); 53ce1e22b0SJiri Olsa } 54ce1e22b0SJiri Olsa 55ce1e22b0SJiri Olsa free(buf); 56ce1e22b0SJiri Olsa 57ce1e22b0SJiri Olsa if (found) 58ce1e22b0SJiri Olsa return 0; 59ce1e22b0SJiri Olsa 60ce1e22b0SJiri Olsa pr_err("failed: event '%s' not found, use '-e list' to get list of available events\n", str); 61ce1e22b0SJiri Olsa return -1; 62ce1e22b0SJiri Olsa } 6354fbad54SJiri Olsa 6454fbad54SJiri Olsa int perf_mem_events__init(void) 6554fbad54SJiri Olsa { 6654fbad54SJiri Olsa const char *mnt = sysfs__mount(); 6754fbad54SJiri Olsa bool found = false; 6854fbad54SJiri Olsa int j; 6954fbad54SJiri Olsa 7054fbad54SJiri Olsa if (!mnt) 7154fbad54SJiri Olsa return -ENOENT; 7254fbad54SJiri Olsa 7354fbad54SJiri Olsa for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) { 7454fbad54SJiri Olsa char path[PATH_MAX]; 7554fbad54SJiri Olsa struct perf_mem_event *e = &perf_mem_events[j]; 7654fbad54SJiri Olsa struct stat st; 7754fbad54SJiri Olsa 7854fbad54SJiri Olsa scnprintf(path, PATH_MAX, "%s/devices/cpu/events/%s", 7954fbad54SJiri Olsa mnt, e->sysfs_name); 8054fbad54SJiri Olsa 8154fbad54SJiri Olsa if (!stat(path, &st)) 8254fbad54SJiri Olsa e->supported = found = true; 8354fbad54SJiri Olsa } 8454fbad54SJiri Olsa 8554fbad54SJiri Olsa return found ? 0 : -ENOENT; 8654fbad54SJiri Olsa } 870c877d75SJiri Olsa 880c877d75SJiri Olsa static const char * const tlb_access[] = { 890c877d75SJiri Olsa "N/A", 900c877d75SJiri Olsa "HIT", 910c877d75SJiri Olsa "MISS", 920c877d75SJiri Olsa "L1", 930c877d75SJiri Olsa "L2", 940c877d75SJiri Olsa "Walker", 950c877d75SJiri Olsa "Fault", 960c877d75SJiri Olsa }; 970c877d75SJiri Olsa 98b1a5fbeaSJiri Olsa int perf_mem__tlb_scnprintf(char *out, size_t sz, struct mem_info *mem_info) 990c877d75SJiri Olsa { 1000c877d75SJiri Olsa size_t l = 0, i; 1010c877d75SJiri Olsa u64 m = PERF_MEM_TLB_NA; 1020c877d75SJiri Olsa u64 hit, miss; 1030c877d75SJiri Olsa 1040c877d75SJiri Olsa sz -= 1; /* -1 for null termination */ 1050c877d75SJiri Olsa out[0] = '\0'; 1060c877d75SJiri Olsa 1070c877d75SJiri Olsa if (mem_info) 1080c877d75SJiri Olsa m = mem_info->data_src.mem_dtlb; 1090c877d75SJiri Olsa 1100c877d75SJiri Olsa hit = m & PERF_MEM_TLB_HIT; 1110c877d75SJiri Olsa miss = m & PERF_MEM_TLB_MISS; 1120c877d75SJiri Olsa 1130c877d75SJiri Olsa /* already taken care of */ 1140c877d75SJiri Olsa m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS); 1150c877d75SJiri Olsa 1160c877d75SJiri Olsa for (i = 0; m && i < ARRAY_SIZE(tlb_access); i++, m >>= 1) { 1170c877d75SJiri Olsa if (!(m & 0x1)) 1180c877d75SJiri Olsa continue; 1190c877d75SJiri Olsa if (l) { 1200c877d75SJiri Olsa strcat(out, " or "); 1210c877d75SJiri Olsa l += 4; 1220c877d75SJiri Olsa } 123b1a5fbeaSJiri Olsa l += scnprintf(out + l, sz - l, tlb_access[i]); 1240c877d75SJiri Olsa } 1250c877d75SJiri Olsa if (*out == '\0') 126b1a5fbeaSJiri Olsa l += scnprintf(out, sz - l, "N/A"); 1270c877d75SJiri Olsa if (hit) 128b1a5fbeaSJiri Olsa l += scnprintf(out + l, sz - l, " hit"); 1290c877d75SJiri Olsa if (miss) 130b1a5fbeaSJiri Olsa l += scnprintf(out + l, sz - l, " miss"); 131b1a5fbeaSJiri Olsa 132b1a5fbeaSJiri Olsa return l; 1330c877d75SJiri Olsa } 134071e9a1eSJiri Olsa 135071e9a1eSJiri Olsa static const char * const mem_lvl[] = { 136071e9a1eSJiri Olsa "N/A", 137071e9a1eSJiri Olsa "HIT", 138071e9a1eSJiri Olsa "MISS", 139071e9a1eSJiri Olsa "L1", 140071e9a1eSJiri Olsa "LFB", 141071e9a1eSJiri Olsa "L2", 142071e9a1eSJiri Olsa "L3", 143071e9a1eSJiri Olsa "Local RAM", 144071e9a1eSJiri Olsa "Remote RAM (1 hop)", 145071e9a1eSJiri Olsa "Remote RAM (2 hops)", 146071e9a1eSJiri Olsa "Remote Cache (1 hop)", 147071e9a1eSJiri Olsa "Remote Cache (2 hops)", 148071e9a1eSJiri Olsa "I/O", 149071e9a1eSJiri Olsa "Uncached", 150071e9a1eSJiri Olsa }; 151071e9a1eSJiri Olsa 15296907563SJiri Olsa int perf_mem__lvl_scnprintf(char *out, size_t sz, struct mem_info *mem_info) 153071e9a1eSJiri Olsa { 154071e9a1eSJiri Olsa size_t i, l = 0; 155071e9a1eSJiri Olsa u64 m = PERF_MEM_LVL_NA; 156071e9a1eSJiri Olsa u64 hit, miss; 157071e9a1eSJiri Olsa 158071e9a1eSJiri Olsa if (mem_info) 159071e9a1eSJiri Olsa m = mem_info->data_src.mem_lvl; 160071e9a1eSJiri Olsa 161071e9a1eSJiri Olsa sz -= 1; /* -1 for null termination */ 162071e9a1eSJiri Olsa out[0] = '\0'; 163071e9a1eSJiri Olsa 164071e9a1eSJiri Olsa hit = m & PERF_MEM_LVL_HIT; 165071e9a1eSJiri Olsa miss = m & PERF_MEM_LVL_MISS; 166071e9a1eSJiri Olsa 167071e9a1eSJiri Olsa /* already taken care of */ 168071e9a1eSJiri Olsa m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS); 169071e9a1eSJiri Olsa 170071e9a1eSJiri Olsa for (i = 0; m && i < ARRAY_SIZE(mem_lvl); i++, m >>= 1) { 171071e9a1eSJiri Olsa if (!(m & 0x1)) 172071e9a1eSJiri Olsa continue; 173071e9a1eSJiri Olsa if (l) { 174071e9a1eSJiri Olsa strcat(out, " or "); 175071e9a1eSJiri Olsa l += 4; 176071e9a1eSJiri Olsa } 17796907563SJiri Olsa l += scnprintf(out + l, sz - l, mem_lvl[i]); 178071e9a1eSJiri Olsa } 179071e9a1eSJiri Olsa if (*out == '\0') 18096907563SJiri Olsa l += scnprintf(out, sz - l, "N/A"); 181071e9a1eSJiri Olsa if (hit) 18296907563SJiri Olsa l += scnprintf(out + l, sz - l, " hit"); 183071e9a1eSJiri Olsa if (miss) 18496907563SJiri Olsa l += scnprintf(out + l, sz - l, " miss"); 18596907563SJiri Olsa 18696907563SJiri Olsa return l; 187071e9a1eSJiri Olsa } 1882c07af13SJiri Olsa 1892c07af13SJiri Olsa static const char * const snoop_access[] = { 1902c07af13SJiri Olsa "N/A", 1912c07af13SJiri Olsa "None", 1922c07af13SJiri Olsa "Miss", 1932c07af13SJiri Olsa "Hit", 1942c07af13SJiri Olsa "HitM", 1952c07af13SJiri Olsa }; 1962c07af13SJiri Olsa 197149d7507SJiri Olsa int perf_mem__snp_scnprintf(char *out, size_t sz, struct mem_info *mem_info) 1982c07af13SJiri Olsa { 1992c07af13SJiri Olsa size_t i, l = 0; 2002c07af13SJiri Olsa u64 m = PERF_MEM_SNOOP_NA; 2012c07af13SJiri Olsa 2022c07af13SJiri Olsa sz -= 1; /* -1 for null termination */ 2032c07af13SJiri Olsa out[0] = '\0'; 2042c07af13SJiri Olsa 2052c07af13SJiri Olsa if (mem_info) 2062c07af13SJiri Olsa m = mem_info->data_src.mem_snoop; 2072c07af13SJiri Olsa 2082c07af13SJiri Olsa for (i = 0; m && i < ARRAY_SIZE(snoop_access); i++, m >>= 1) { 2092c07af13SJiri Olsa if (!(m & 0x1)) 2102c07af13SJiri Olsa continue; 2112c07af13SJiri Olsa if (l) { 2122c07af13SJiri Olsa strcat(out, " or "); 2132c07af13SJiri Olsa l += 4; 2142c07af13SJiri Olsa } 215149d7507SJiri Olsa l += scnprintf(out + l, sz - l, snoop_access[i]); 2162c07af13SJiri Olsa } 2172c07af13SJiri Olsa 2182c07af13SJiri Olsa if (*out == '\0') 219149d7507SJiri Olsa l += scnprintf(out, sz - l, "N/A"); 220149d7507SJiri Olsa 221149d7507SJiri Olsa return l; 2222c07af13SJiri Olsa } 22369a77275SJiri Olsa 2248b0819c8SJiri Olsa int perf_mem__lck_scnprintf(char *out, size_t sz, struct mem_info *mem_info) 22569a77275SJiri Olsa { 22669a77275SJiri Olsa u64 mask = PERF_MEM_LOCK_NA; 2278b0819c8SJiri Olsa int l; 22869a77275SJiri Olsa 22969a77275SJiri Olsa if (mem_info) 23069a77275SJiri Olsa mask = mem_info->data_src.mem_lock; 23169a77275SJiri Olsa 23269a77275SJiri Olsa if (mask & PERF_MEM_LOCK_NA) 2338b0819c8SJiri Olsa l = scnprintf(out, sz, "N/A"); 23469a77275SJiri Olsa else if (mask & PERF_MEM_LOCK_LOCKED) 2358b0819c8SJiri Olsa l = scnprintf(out, sz, "Yes"); 23669a77275SJiri Olsa else 2378b0819c8SJiri Olsa l = scnprintf(out, sz, "No"); 2388b0819c8SJiri Olsa 2398b0819c8SJiri Olsa return l; 24069a77275SJiri Olsa } 241