2

这是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编程中无效?

4

2 回答 2

4

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

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

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

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

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

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

于 2013-11-09T08:13:36.467 回答
2

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

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

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

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

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

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

于 2013-11-09T08:22:22.743 回答