【问题标题】:Unexpected output in C with access to ARRAY in memory with RDTSCC 中的意外输出,可通过 RDTSC 访问内存中的 ARRAY
【发布时间】:2014-03-07 10:46:05
【问题描述】:

这是我的 C 程序。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>

static int DATA[1024]={1,2,3,4,.....1024};

inline void foo_0(void)
{
    int j;
    puts("Hello, I'm inside foo_0");
    int k=0;
    for(j=0;j<1024;j++)
    {
        //k=DATA[j];
        DATA[j]+=1;
    }
    k+=0;
}


inline void foo_1(void)
{
    int j;
    puts("Hello, I'm inside foo_1");
    int k=0;
    for(j=0;j<1024;j+=4)
    {
        //k=DATA[j];
        DATA[j]+=1;
    }
    k+=0;
}

inline void foo_2(void)
{
    int j;
    puts("Hello, I'm inside foo_2");
    int k=0;
    for(j=0;j<1024;j+=16)
    {
        //k=DATA[j];
        DATA[j]+=1;
    }
    k+=0;
}


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

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

int main(void)
{

    volatile uint64_t start, end,temp;
    unsigned long long total_time=0;


    foo_0();  // This will load DATA array into memory
    foo_1();  // DATA already loaded into memory
    foo_2(); // DATA already loaded into memory

    printf("**********************\n");  
    start=rdtsc();
    foo_2();
    end=rdtsc();
    temp=end-start;
    total_time=temp;

    printf("Time taken foo_2 = %llu\n",total_time);             

    start=rdtsc();
    foo_1();
    end=rdtsc();
    temp=end-start;
    total_time=temp;

    printf("Time taken foo_1 = %llu\n",total_time);

    start=rdtsc();
    foo_0();
    end=rdtsc();
    temp=end-start;
    total_time=temp;

    printf("Time taken foo_0 = %llu\n",total_time);


    return 0;
}

输出:

Hello, I'm inside foo_0
Hello, I'm inside foo_1
Hello, I'm inside foo_2
**********************
Hello, I'm inside foo_2
**Time taken foo_2 = 6350**
Hello, I'm inside foo_1
**Time taken foo_1 = 10056**
Hello, I'm inside foo_0
**Time taken foo_0 = 21726**

编辑 1:

当我从所有三个函数中删除 puts() 时,我得到了这个结果

Time taken foo_0 = 16448
Time taken foo_1 = 4438
**********************
Time taken foo_2 = 1548

期望所有三个 foo_0、foo_1 和 foo_2 的访问时间相同,因为当访问内存以访问整数时,会加载整个缓存块(64 字节是块大小,因此 16 个整数是在缓存块中加载),因此 1、4、16 整数的访问时间必须相同。我没有得到。我在哪里犯错? 我在linux下使用gcc。提前致谢 。

编辑 2

根据 BЈовић 的回答和 Leeor 在评论中的建议,执行时间必须不同,因为在三个不同的函数中执行的加法运算次数不同。尽管在所有三种情况下都没有相同的未命中率,但是执行加法操作的次数各不相同,并且对于所有操作数据都是从缓存中访问(*不是从主存*正如我怀疑的那样)总时间取决于对数组执行的加法操作,而不是缓存未命中/命中。所以我接受BЈовић的回答和Leeor的建议。谢谢大家。

【问题讨论】:

  • 杀死所有其他进程,看看你得到了什么
  • @BЈовић ,在关闭所有用户进程并使用 sync 清除 linux 缓存之后; echo 3 > /proc/sys/vm/drop_caches ,我得到了这个结果 耗时 foo_0 = 16532 耗时 foo_1 = 4386 ********************** 耗时foo_2 = 1556 耗时 foo_0 = 16532 耗时 foo_1 = 4412 ************************ 耗时 foo_2 = 1538 [root@localhost 10feb]# ./c foo_0 所用时间 = 16542 foo_1 所用时间 = 4436 ********************** foo_2 所用时间 = 1470
  • 为什么在foo_1() 的时间和foo_2() 的时间之间打印出一行星号?您的结果在运行之间是否一致?如果您将 all 控制台输出移动到三个调用的计时之后,您会得到类似的结果吗?另外,k+=0; 语句的意图是什么?
  • @MichaelBurr 我刚刚删除了其他带星号的打印语句,我得到了以下结果- 耗时 foo_0 = 16558 耗时 foo_1 = 4522 耗时 foo_2 = 1394。运行 1-2 次后保持一致。
  • 另外,如果我重新排列 foo 函数,我会得到与上面相同的结果。

标签: c linux performance cpu-architecture cpu-cache


【解决方案1】:

1)您的进程正在被其他进程推到后台,因此无法获得精确的时间。

2)由于循环不同,时间不可能相同:

foo_0() : for(j=0;j&lt;1024;j++)
foo_1() : for(j=0;j&lt;1024;j+=4)
foo_2() : for(j=0;j&lt;1024;j+=16)

【讨论】:

  • @BJob ,我关闭了所有其他用户进程。只有系统进程在那里。我的期望是当 foo_0()、foo_1()、foo_2() 被访问时,整个 DATA 数组被加载到缓存中。现在,当我为 DATA[0], DATA[16],DATA[32] 访问 for(j=0;j
  • @bholanath 不可能关闭所有进程。您的数据足够小,可以将其存储在缓存中 - 这不是问题。
  • 因为我的数组足够小,可以加载到缓存中,所以对于所有三种情况,它将从缓存中访问,这就是为什么它们必须提供相同的访问时间,但我的结果显示出巨大的差异。
  • @bholanath,缓存访问不是唯一的限制,您需要通过 CPU、内存管道、提交逻辑等运行所有这些指令。对于不同长度的循环,这将需要不同的时间。
  • @bholanath - 你自己说过 - 在你带来的链接中,循环从内存中获取数据(它是 256MB),因此内存访问时间支配一切,并掩盖了 CPU 中的任何差异。 mem访问的次数是一样的。但是,在您的示例中,数据适合 L1,因此获取时间非常短 - 暴露了执行时间。缓存访问还是一样,但是执行指令的数量是 4x 和 16x。
猜你喜欢
  • 1970-01-01
  • 2023-01-30
  • 2015-05-06
  • 1970-01-01
  • 2014-10-24
  • 1970-01-01
  • 2011-07-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多