我想测量缓存未命中率和dtlb未命中率。我已经完成了第一部分。但是我找不到如何设置配置来获取dtlb miss和dtlb hits。当我测量缓存未命中时,我会这样:
pe.type = PERF_TYPE_HARDWARE;
pe.size = sizeof(struct perf_event_attr);
pe.config = PERF_COUNT_HW_CACHE_MISSES;
perf
中没有'直接'PMU事件,这将有助于您测量dTLB hits
。有单独的dTLB miss
事件用于内存加载和存储,运行以下命令时可以看到这些事件,
sudo perf list | grep 'Hardware cache'
dTLB-load-misses [Hardware cache event]
dTLB-loads [Hardware cache event]
dTLB-store-misses [Hardware cache event]
dTLB-stores [Hardware cache event]
每个事件的含义已经提到here。它们取决于您使用的微体系结构,这对dTLB-hits
的计算很重要。
例如,您要对事件dTLB-load-misses
的发生进行采样,
pe.type = PERF_TYPE_HW_CACHE;
pe.size = sizeof(struct perf_event_attr);
pe.config = PERF_COUNT_HW_CACHE_DTLB << 0 | PERF_COUNT_HW_CACHE_OP_READ << 8 | PERF_COUNT_HW_CACHE_RESULT_MISS << 16;
并且如果您要测量事件dTLB-loads
的发生,
pe.type = PERF_TYPE_HW_CACHE;
pe.size = sizeof(struct perf_event_attr);
pe.config = PERF_COUNT_HW_CACHE_DTLB << 0 | PERF_COUNT_HW_CACHE_OP_READ << 8 | PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16;
为了测量dTLB-store-misses
和dTLB-stores
,您需要在上述配置中将PERF_COUNT_HW_CACHE_OP_READ
替换为PERF_COUNT_HW_CACHE_OP_WRITE
。
[测量任何硬件缓存事件时,配置应始终采用-]的形式>
pe.config = (perf_hw_cache_id << 0) | (perf_hw_cache_op_id << 8) | (perf_hw_cache_op_result_id << 16)
perf_hw_cache_id
,perf_hw_cache_op_id
和perf_hw_cache_op_result_id
的含义和不同的“枚举”值在here中提及。
理想情况下,根据您的要求,您希望针对单个工作负载一起测量上述四个事件,因此,下面显示了如何一起测量dTLB-load-misses
和dTLB-loads
的示例-
#define _GNU_SOURCE #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <sys/syscall.h> #include <string.h> #include <sys/ioctl.h> #include <linux/perf_event.h> #include <linux/hw_breakpoint.h> #include <asm/unistd.h> #include <errno.h> #include <stdint.h> #include <inttypes.h> struct read_format { uint64_t nr; struct { uint64_t value; uint64_t id; } values[]; }; int main(int argc, char* argv[]) { struct perf_event_attr pea; int fd1, fd2; uint64_t id1, id2; uint64_t val1, val2; char buf[4096]; struct read_format* rf = (struct read_format*) buf; int i; memset(&pea, 0, sizeof(struct perf_event_attr)); pea.type = PERF_TYPE_HW_CACHE; pea.size = sizeof(struct perf_event_attr); pea.config = PERF_COUNT_HW_CACHE_DTLB << 0 | PERF_COUNT_HW_CACHE_OP_READ << 8 | PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16; pea.disabled = 1; pea.exclude_kernel = 1; pea.exclude_hv = 1; pea.read_format = PERF_FORMAT_GROUP | PERF_FORMAT_ID; fd1 = syscall(__NR_perf_event_open, &pea, 0, -1, -1, 0); ioctl(fd1, PERF_EVENT_IOC_ID, &id1); memset(&pea, 0, sizeof(struct perf_event_attr)); pea.type = PERF_TYPE_HW_CACHE; pea.size = sizeof(struct perf_event_attr); pea.config = PERF_COUNT_HW_CACHE_DTLB << 0 | PERF_COUNT_HW_CACHE_OP_READ << 8 | PERF_COUNT_HW_CACHE_RESULT_MISS << 16;; pea.disabled = 1; pea.exclude_kernel = 1; pea.exclude_hv = 1; pea.read_format = PERF_FORMAT_GROUP | PERF_FORMAT_ID; fd2 = syscall(__NR_perf_event_open, &pea, 0, -1, fd1 /*!!!*/, 0); ioctl(fd2, PERF_EVENT_IOC_ID, &id2); ioctl(fd1, PERF_EVENT_IOC_RESET, PERF_IOC_FLAG_GROUP); ioctl(fd1, PERF_EVENT_IOC_ENABLE, PERF_IOC_FLAG_GROUP); sleep(10); ioctl(fd1, PERF_EVENT_IOC_DISABLE, PERF_IOC_FLAG_GROUP); read(fd1, buf, sizeof(buf)); for (i = 0; i < rf->nr; i++) { if (rf->values[i].id == id1) { val1 = rf->values[i].value; } else if (rf->values[i].id == id2) { val2 = rf->values[i].value; } } printf("dTLB-loads: %"PRIu64"\n", val1); printf("dTLB-load-misses: %"PRIu64"\n", val2); return 0;
提到使用
perf_event_open
监视多个事件时涉及的一些想法,并复制了上述程序。here。>