c-如何在Linux系统中体验缓存丢失和命中



你好,我一直在尝试在Linux中体验缓存丢失和命中。为了做到这一点,我用C语言编写了一个程序,其中我测量了CPU周期中执行指令printf((的时间。第一部分测量未命中所需的时间,第二部分测量命中所需时间。这是给定的程序:

#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <sched.h>
#include <sys/types.h> 
#include <unistd.h> 
#include <signal.h>
uint64_t rdtsc() {
uint64_t a, d;
asm volatile ("mfence");
asm volatile ("rdtsc" : "=a" (a), "=d" (d));
a = (d<<32) | a;
asm volatile ("mfence");
return a;
}
int main(int argc, char** argv)
{
size_t time = rdtsc();
printf("Hey ");
size_t delta1 = rdtsc() - time;
printf("delta: %zun", delta1);
size_t time2 = rdtsc();
printf("Hey ");
size_t delta2 = rdtsc() - time2;
printf("delta: %zun", delta2);
sleep(100);
} 

现在我想展示两个进程(两个终端(在communi中有缓存。所以我认为在两个终端上运行这个程序会导致:

Terminal 1:
miss
hit
Terminal 2:
hit 
hit

但现在我有了类似的东西:

Terminal 1:
miss
hit
Terminal 2:
miss 
hit

我的理解有误吗?或者我的程序错了?

您的假设在某种程度上是正确的
printflibc库的一部分。如果您使用动态链接,操作系统可能会为所有使用该库的进程只加载一次库,从而优化内存使用情况。
然而,我不希望您测量任何相当大的差异有多个原因:

  1. 与缓存命中和缓存未命中之间的差异相比,printf需要大量的时间来完成,并且有很多事情会引入噪声。只需一次测量,就不太可能测量出微小的差异
  2. 第一次测量花费更长时间的实际原因可能是加载器正在解决库函数printf的延迟绑定(https://maskray.me/blog/2021-09-19-all-about-procedure-linkage-table)或者对于第一输出发生一些其他魔术(正在设置缓冲器等(
  3. 许多不同的进程使用许多CCD_ 5函数。如果库是共享的,那么即使您没有使用printf,它也可能被缓存

我建议发起Flush+Road攻击(https://eprint.iacr.org/2013/448.pdf)在其中一个终端的CCD_ 6上,并在另一个终端中使用它。然后,你可能会看到时间上的差异
注意:要找到攻击的printf的实际地址,您需要熟悉动态链接和plt。仅仅使用void* addr = printf这样的东西可能是行不通的!

最新更新