在 i386 linux 上。如果可能的话,最好在 c/(c/posix std libs)/proc 中。如果没有,是否有任何组件或第三方库可以做到这一点?
编辑:我正在尝试开发测试内核模块是否清除缓存行或整个处理器(使用 wbinvd())。程序以 root 身份运行,但如果可能,我更愿意留在用户空间。
在 i386 linux 上。如果可能的话,最好在 c/(c/posix std libs)/proc 中。如果没有,是否有任何组件或第三方库可以做到这一点?
编辑:我正在尝试开发测试内核模块是否清除缓存行或整个处理器(使用 wbinvd())。程序以 root 身份运行,但如果可能,我更愿意留在用户空间。
缓存连贯系统尽最大努力向您隐藏这些东西。我认为您将不得不间接地观察它,或者通过使用性能计数寄存器来检测缓存未命中,或者通过使用高分辨率计时器仔细测量读取内存位置的时间。
这个程序在我的 x86_64 盒子上运行,以演示clflush
. 它计算使用读取全局变量所需的时间rdtsc
。作为直接与 CPU 时钟相关联的单条指令,直接使用rdtsc
非常理想。
用了 81 个刻度 用了 81 个刻度 同花顺:花费了 387 个滴答声 用了 72 个滴答声
您会看到 3 次试验:第一次确保i
在缓存中(确实如此,因为它只是作为 BSS 的一部分被归零),第二次是读取i
应该在缓存中。然后clflush
踢出i
缓存(连同它的邻居)并显示重新读取它需要更长的时间。最终读取验证它已回到缓存中。结果非常可重复,并且差异足够大,可以很容易地看到缓存未命中。如果您愿意校准您的开销,则rdtsc()
可以使差异更加明显。
如果您无法读取要测试的内存地址(尽管甚至mmap
应该/dev/mem
可以用于这些目的),如果您知道缓存线的大小和缓存的关联性,则可以推断出您想要的内容。然后,您可以使用可访问的内存位置来探测您感兴趣的集合中的活动。
#include <stdio.h>
#include <stdint.h>
inline void
clflush(volatile void *p)
{
asm volatile ("clflush (%0)" :: "r"(p));
}
inline uint64_t
rdtsc()
{
unsigned long a, d;
asm volatile ("rdtsc" : "=a" (a), "=d" (d));
return a | ((uint64_t)d << 32);
}
volatile int i;
inline void
test()
{
uint64_t start, end;
volatile int j;
start = rdtsc();
j = i;
end = rdtsc();
printf("took %lu ticks\n", end - start);
}
int
main(int ac, char **av)
{
test();
test();
printf("flush: ");
clflush(&i);
test();
test();
return 0;
}
我不知道任何通用命令来获取缓存状态,但有一些方法:
您提到了 WBINVD - afaik 将始终刷新完整,即所有缓存行
它可能不是您特定问题的答案,但您是否尝试过使用缓存分析器,例如Cachegrind?它只能用于分析用户空间代码,但您仍然可以使用它,例如,如果函数的代码不依赖于任何内核特定的接口,则将其移动到用户空间。
它实际上可能比试图向处理器询问可能存在或可能不存在的信息更有效,并且可能会受到您仅仅询问它的影响 - 是的,海森堡早于他的时代:-)