【问题标题】:clflush not flushing the instruction cacheclflush 不刷新指令缓存
【发布时间】:2013-12-15 22:41:14
【问题描述】:

考虑以下代码段:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#define ARRAYSIZE(arr) (sizeof(arr)/sizeof(arr[0]))


inline void
clflush(volatile void *p)
{
    asm volatile ("clflush (%0)" :: "r"(p));
}

inline uint64_t
rdtsc()
{
    unsigned long a, d;
    asm volatile ("cpuid; rdtsc" : "=a" (a), "=d" (d) : : "ebx", "ecx");
    return a | ((uint64_t)d << 32);
}

inline int func() { return 5;}

inline void test()
{
    uint64_t start, end;
    char c;
    start = rdtsc();
    func();
    end = rdtsc();
    printf("%ld ticks\n", end - start);
}

void flushFuncCache()
{
    // Assuming function to be not greater than 320 bytes.
    char* fPtr = (char*)func;
    clflush(fPtr);
    clflush(fPtr+64);
    clflush(fPtr+128);
    clflush(fPtr+192);
    clflush(fPtr+256);
}

int main(int ac, char **av)
{
    test();
    printf("Function must be cached by now!\n");
    test();
    flushFuncCache();
    printf("Function flushed from cache.\n");
    test();
    printf("Function must be cached again by now!\n");
    test();

    return 0;
}

在这里,我正在尝试刷新指令缓存以删除“func”的代码,然后预计下一次调用 func 时会产生性能开销,但我的结果与我的预期不符:

858 ticks
Function must be cached by now!
788 ticks
Function flushed from cache.
728 ticks
Function must be cached again by now!
710 ticks

我期待CLFLUSH 也刷新指令缓存,但显然它没有这样做。有人可以解释这种行为或建议如何实现所需的行为。

【问题讨论】:

    标签: c++ assembly x86 cpu-cache


    【解决方案1】:

    您的代码在 func 中几乎什么都不做,而您所做的那一点点会被内联到 test 中,并且由于您从不使用返回值,因此可能会被优化掉。

    gcc -O3 给我 -

    0000000000400620 <test>:
      400620:       53                      push   %rbx
      400621:       0f a2                   cpuid
      400623:       0f 31                   rdtsc
      400625:       48 89 d7                mov    %rdx,%rdi
      400628:       48 89 c6                mov    %rax,%rsi
      40062b:       0f a2                   cpuid
      40062d:       0f 31                   rdtsc
      40062f:       5b                      pop    %rbx
      ...
    

    因此,您正在测量硬件方面非常便宜的两个动作的时间 - 您的测量结果可能显示 cpuid 的延迟相对昂贵..

    更糟糕的是,您的 clflush 实际上也会刷新 test,这意味着您在下次访问它时会支付重新获取的罚款,这不在 rdtsc 对中,因此无法测量。另一方面,测量的代码依次跟随,因此获取test 可能还会获取您测量的刷新代码,因此它实际上可以在您测量它时被缓存。

    【讨论】:

    • 好的,您的解释是有道理的,我怎样才能产生所需的行为,即将函数移出指令缓存并测量惩罚?增加函数大小和使用 noinline 属性会有帮助吗?
    • @sud03r,可能不会,单个函数会丢失一次,然后继续运行以获取其余函数。尝试定义多个函数,如果可能,每个调用下一​​个。
    【解决方案2】:

    它在我的电脑上运行良好。

    264 ticks
    Function must be cached by now!
    258 ticks
    Function flushed from cache.
    519 ticks
    Function must be cached again by now!
    240 ticks
    

    【讨论】:

    • 我还是不明白第一个输出是 264 滴答声的原因。
    猜你喜欢
    • 2019-06-23
    • 2020-11-26
    • 1970-01-01
    • 2020-10-15
    • 2011-02-16
    • 1970-01-01
    • 2013-04-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多