【问题标题】:The CPU Cache is invalid in C Programing?C编程中CPU缓存无效?
【发布时间】:2013-11-21 08:03:22
【问题描述】:

这是Linux/GUN下的C程序:

#include<stdio.h>
#include<sys/time.h>
#define Max 1024*1024

int main()
{
    struct timeval start,end;
    long int dis;
    int i;
    int m=0;
    int a[Max];
    gettimeofday(&start,NULL);
    for(i=0;i<Max;i += 1){
            a[Max] *= 3;    
    }   
    gettimeofday(&end,NULL);
    dis = end.tv_usec - start.tv_usec;
    printf("time1: %ld\n",dis);

    gettimeofday(&start,NULL);
    for(i=0;i<Max;i += 16){
            a[Max] *= 3;
    }
    gettimeofday(&end,NULL);
    dis = end.tv_usec - start.tv_usec;
    printf("time2: %ld\n",dis);

    return 0;
}

输出:

时间1:7074

时间2:234

距离很远

这个 Java 程序:

public class Cache1 {
public static void main(String[] args){
    int a[] = new int[1024*1024*64];

    long  time1 = System.currentTimeMillis();
    for(int i=0;i<a.length;i++){
        a[i] *= 3;
    } 
    long time2 = System.currentTimeMillis();
    System.out.println(time2 - time1);

    time1 = System.currentTimeMillis();
    for(int i=0;i<a.length;i += 16){
        a[i] *= 3;
    }
    time2 = System.currentTimeMillis();
    System.out.println(time2 - time1);
}
}

输出:

92

82

几乎一样

与 CPU 缓存。为什么他们有这么大的区别? Cpu Cache在C编程中无效?

【问题讨论】:

  • 要查找执行时间,请使用 System.nanoTime() 而不是 System.currentTimeMillis()
  • 在您的C 代码中,语句a[Max] *= 3 将修改数组末尾之后的内存。你的意思是a[i]?
  • 是的,这是一个错误,a[i] 是正确的。

标签: java c++ c cpu-cache


【解决方案1】:

我希望您意识到这些测试中时间单位的差异是 10^3。 C 代码比 Java 代码快一个数量级。

在 C 代码中应该有 a[i] 而不是 a[Max]。

至于缓存:由于您只访问 C 代码中的一个内存位置(这会触发未定义的行为),因此您的 C 测试完全无效。

即使它是正确的,你的方法也是有缺陷的。乘法运算甚至整个循环很可能被 C 编译器完全跳过,因为没有什么取决于它们的结果。

第一次运行时间长,第二次运行时间短的结果是预期的。无论如何都必须将数据加载到缓存中,这需要时间。加载后,对该数据的操作将花费更少的时间。

Java 可能根本不使用缓存(不太可能),或者甚至在循环执行之前预加载整个数组以进行缓存。这可以解释相同的执行时间。

【讨论】:

    【解决方案2】:

    你有三种缓存大小,通常是

    • L1:32 KB(数据),4 个时钟周期
    • L2:256KB,10-11 个时钟周期
    • L3:3-24 MB。 40 - 75 个时钟周期。

    任何比这更大的东西都不会放入缓存,就像你只是滚动浏览内存一样,它们就好像它们不存在一样。

    我建议您编写一个根据经验计算出 CPU 缓存大小的测试,作为一个很好的练习来帮助您理解这一点。顺便说一句,您不需要使用*= 来行使缓存,因为这会行使 ALU。也许您可以使用更简单的操作;)

    对于您的 Java 代码,很可能它尚未编译,因此您看到的是交互器的速度,而不是内存访问。

    我建议您在较小的内存大小上重复运行测试至少 2 秒,然后取平均值。

    【讨论】:

    • +1 指出 Java 结果很可能是伪造的。
    • @StephenC 如果在实际用例中您只针对这个数据集大小调用此方法一次,这是正确的。在这种情况下,您很可能不会关心性能,尤其是如果您使用的是选择排序。
    • @PeterLawrey 谢谢,我会试试你的答案
    猜你喜欢
    • 2011-12-18
    • 2011-01-13
    • 2013-06-12
    • 2012-09-14
    • 1970-01-01
    • 2017-07-09
    • 1970-01-01
    • 1970-01-01
    • 2010-12-27
    相关资源
    最近更新 更多