一尘不染

有没有一种方法可以检查处理器缓存是否最近已刷新?

linux

在i386 linux上。如果可能,最好在c /(c / posix std libs)/ proc中。如果没有,那么任何程序集或第三方库都可以做到这一点?

编辑:我正在尝试开发测试内核模块是否清除缓存行或整个处理器(与wbinvd())。程序以root身份运行,但我希望尽可能保留在用户空间中。


阅读 305

收藏
2020-06-07

共1个答案

一尘不染

高速缓存一致性系统会尽最大努力向您隐藏此类信息。我认为您将不得不通过使用性能计数寄存器来检测高速缓存未命中,或者通过使用高分辨率计时器仔细测量读取存储位置的时间来间接观察它。

该程序在我的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;
}
2020-06-07