我想知道是否有任何单个事件可以捕获 L1D 缓存未命中。我试图通过测量延迟以在开始时使用 rdtsc 访问特定内存来捕获 L1d 缓存未命中。在我的设置中,如果发生 L1d 缓存未命中,它应该会命中 L2 缓存。因此,我用 RDTSC 测量访问内存的延迟,并将其与 L1 缓存延迟和 L2 缓存延迟进行比较。但是,由于噪音,我无法辨别它是击中 L1 还是 L2。所以我决定使用 RDPMC。
我发现有几个 API 提供了一些功能来轻松监控 perf 事件,但我想直接在我的测试程序上使用 RDPMC 指令。我发现 MEM_INST_RETIRED.ALL_LOADS-MEM_LOAD_RETIRED.L1_HIT 可用于计算 L1D 中未命中的已退休加载指令的数量。(使用 PAPI_read_counters 计算 L1 缓存未命中会产生意外结果)。但是,这篇帖子似乎在谈论 papi Api。
在执行 rdpmc 指令以捕获特定事件之前,如何找到应该为 ecx 寄存器分配哪些值?另外,我想知道是否有任何单个事件可以告诉我在两条 rdpmc 指令之间的一条内存加载指令发生 L1 未命中,如下所示。
c = XXX; //I don't know what value should be assigned for what perf counter..
asm volatile(
"lfence"
"rdpmc"
"lfence"
"mov (0xdeadbeef), %%r10"//read memory
"mov %%eax, %%r10 //read lower 32 bits of counter
"lfence"
"rdpmc" //another rdpmc to capture difference
"sub %%r10, %%eax //sub two counter to get difference
:"=a"(a)
:"c"(c)
:"r10", "edx");
我目前正在使用 9900k 咖啡湖机,所以我在英特尔手册中搜索了咖啡湖机的 perf counter number。似乎只在加载指令之前和之后捕获两个 MEM_LOAD_RETIRED.L1_HIT 就足以捕获事件,但我不确定这样做是否可以。我也不知道如何将该 perf 事件编码为ecx 寄存器。
最后,我想知道 rdpmc 指令背靠背是否需要任何序列化指令。就我而言,因为我只放置了加载指令并测量 L1d 缓存未命中是否发生,所以我将第一条 rdpmc 指令与 lfence 指令括起来,并在最后一条 rdpmc 之前再放置一条 lfence 指令,以确保加载指令在第二条 rdpmc 之前完成。
添加代码
asm volatile (
"lfence\n\t"
"rdpmc\n\t"
"lfence\n\t"
"mov %%eax, %%esi\n\t"
//measure
"mov (%4), %%r10\n\t"
"lfence\n\t"
"rdpmc\n\t"
"lfence\n\t"
"sub %%esi, %%eax\n\t"
"mov %%eax, (%0)\n\t"
:
:"r"(&perf[1]), "r"(&perf[2]), "r"(&perf[3]),
"r"(myAddr), "c"(0x0)
:"eax","edx","esi","r10", "memory");
我还用 isolcpu 固定了我的 3 号核心,并禁用了超线程进行测试。MSR 寄存器已用以下命令计算
sudo wrmsr -p 3 0x186 0x4108D1 #L1 MISS