123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271 |
- #include <stddef.h>
- #include <stdlib.h>
- #include <string.h>
- #include <errno.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <unistd.h>
- #include <api/fs/fs.h>
- #include "mem-events.h"
- #include "debug.h"
- #include "symbol.h"
- unsigned int perf_mem_events__loads_ldlat = 30;
- #define E(t, n, s) { .tag = t, .name = n, .sysfs_name = s }
- struct perf_mem_event perf_mem_events[PERF_MEM_EVENTS__MAX] = {
- E("ldlat-loads", "cpu/mem-loads,ldlat=%u/P", "mem-loads"),
- E("ldlat-stores", "cpu/mem-stores/P", "mem-stores"),
- };
- #undef E
- #undef E
- static char mem_loads_name[100];
- static bool mem_loads_name__init;
- char *perf_mem_events__name(int i)
- {
- if (i == PERF_MEM_EVENTS__LOAD) {
- if (!mem_loads_name__init) {
- mem_loads_name__init = true;
- scnprintf(mem_loads_name, sizeof(mem_loads_name),
- perf_mem_events[i].name,
- perf_mem_events__loads_ldlat);
- }
- return mem_loads_name;
- }
- return (char *)perf_mem_events[i].name;
- }
- int perf_mem_events__parse(const char *str)
- {
- char *tok, *saveptr = NULL;
- bool found = false;
- char *buf;
- int j;
- /* We need buffer that we know we can write to. */
- buf = malloc(strlen(str) + 1);
- if (!buf)
- return -ENOMEM;
- strcpy(buf, str);
- tok = strtok_r((char *)buf, ",", &saveptr);
- while (tok) {
- for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
- struct perf_mem_event *e = &perf_mem_events[j];
- if (strstr(e->tag, tok))
- e->record = found = true;
- }
- tok = strtok_r(NULL, ",", &saveptr);
- }
- free(buf);
- if (found)
- return 0;
- pr_err("failed: event '%s' not found, use '-e list' to get list of available events\n", str);
- return -1;
- }
- int perf_mem_events__init(void)
- {
- const char *mnt = sysfs__mount();
- bool found = false;
- int j;
- if (!mnt)
- return -ENOENT;
- for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
- char path[PATH_MAX];
- struct perf_mem_event *e = &perf_mem_events[j];
- struct stat st;
- scnprintf(path, PATH_MAX, "%s/devices/cpu/events/%s",
- mnt, e->sysfs_name);
- if (!stat(path, &st))
- e->supported = found = true;
- }
- return found ? 0 : -ENOENT;
- }
- static const char * const tlb_access[] = {
- "N/A",
- "HIT",
- "MISS",
- "L1",
- "L2",
- "Walker",
- "Fault",
- };
- int perf_mem__tlb_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
- {
- size_t l = 0, i;
- u64 m = PERF_MEM_TLB_NA;
- u64 hit, miss;
- sz -= 1; /* -1 for null termination */
- out[0] = '\0';
- if (mem_info)
- m = mem_info->data_src.mem_dtlb;
- hit = m & PERF_MEM_TLB_HIT;
- miss = m & PERF_MEM_TLB_MISS;
- /* already taken care of */
- m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS);
- for (i = 0; m && i < ARRAY_SIZE(tlb_access); i++, m >>= 1) {
- if (!(m & 0x1))
- continue;
- if (l) {
- strcat(out, " or ");
- l += 4;
- }
- l += scnprintf(out + l, sz - l, tlb_access[i]);
- }
- if (*out == '\0')
- l += scnprintf(out, sz - l, "N/A");
- if (hit)
- l += scnprintf(out + l, sz - l, " hit");
- if (miss)
- l += scnprintf(out + l, sz - l, " miss");
- return l;
- }
- static const char * const mem_lvl[] = {
- "N/A",
- "HIT",
- "MISS",
- "L1",
- "LFB",
- "L2",
- "L3",
- "Local RAM",
- "Remote RAM (1 hop)",
- "Remote RAM (2 hops)",
- "Remote Cache (1 hop)",
- "Remote Cache (2 hops)",
- "I/O",
- "Uncached",
- };
- int perf_mem__lvl_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
- {
- size_t i, l = 0;
- u64 m = PERF_MEM_LVL_NA;
- u64 hit, miss;
- if (mem_info)
- m = mem_info->data_src.mem_lvl;
- sz -= 1; /* -1 for null termination */
- out[0] = '\0';
- hit = m & PERF_MEM_LVL_HIT;
- miss = m & PERF_MEM_LVL_MISS;
- /* already taken care of */
- m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS);
- for (i = 0; m && i < ARRAY_SIZE(mem_lvl); i++, m >>= 1) {
- if (!(m & 0x1))
- continue;
- if (l) {
- strcat(out, " or ");
- l += 4;
- }
- l += scnprintf(out + l, sz - l, mem_lvl[i]);
- }
- if (*out == '\0')
- l += scnprintf(out, sz - l, "N/A");
- if (hit)
- l += scnprintf(out + l, sz - l, " hit");
- if (miss)
- l += scnprintf(out + l, sz - l, " miss");
- return l;
- }
- static const char * const snoop_access[] = {
- "N/A",
- "None",
- "Miss",
- "Hit",
- "HitM",
- };
- int perf_mem__snp_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
- {
- size_t i, l = 0;
- u64 m = PERF_MEM_SNOOP_NA;
- sz -= 1; /* -1 for null termination */
- out[0] = '\0';
- if (mem_info)
- m = mem_info->data_src.mem_snoop;
- for (i = 0; m && i < ARRAY_SIZE(snoop_access); i++, m >>= 1) {
- if (!(m & 0x1))
- continue;
- if (l) {
- strcat(out, " or ");
- l += 4;
- }
- l += scnprintf(out + l, sz - l, snoop_access[i]);
- }
- if (*out == '\0')
- l += scnprintf(out, sz - l, "N/A");
- return l;
- }
- int perf_mem__lck_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
- {
- u64 mask = PERF_MEM_LOCK_NA;
- int l;
- if (mem_info)
- mask = mem_info->data_src.mem_lock;
- if (mask & PERF_MEM_LOCK_NA)
- l = scnprintf(out, sz, "N/A");
- else if (mask & PERF_MEM_LOCK_LOCKED)
- l = scnprintf(out, sz, "Yes");
- else
- l = scnprintf(out, sz, "No");
- return l;
- }
- int perf_script__meminfo_scnprintf(char *out, size_t sz, struct mem_info *mem_info)
- {
- int i = 0;
- i += perf_mem__lvl_scnprintf(out, sz, mem_info);
- i += scnprintf(out + i, sz - i, "|SNP ");
- i += perf_mem__snp_scnprintf(out + i, sz - i, mem_info);
- i += scnprintf(out + i, sz - i, "|TLB ");
- i += perf_mem__tlb_scnprintf(out + i, sz - i, mem_info);
- i += scnprintf(out + i, sz - i, "|LCK ");
- i += perf_mem__lck_scnprintf(out + i, sz - i, mem_info);
- return i;
- }
|