2013-11-09 26 views
2

這是在Linux/GUN C程序:C程序中的CPU高速緩存無效?

#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); 
} 
} 

輸出:

它nealy相同

與CPU高速緩存。爲什麼他們有這麼多的差異?在C編程中,Cpu Cache無效?

+0

要查找執行時間,請使用System.nanoTime()而不是System.currentTimeMillis() – SpringLearner

+3

在「C」代碼中,語句「a [Max] * = 3」將修改內存超過數組末尾。你是不是指'一個[我]'? – Blastfurnace

+0

是的,這是一個錯誤,一個[我]是正確的。 –

回答

4

我希望你認識到在這些測試中,時間單位的差異是10^3。 C代碼比Java代碼快幾個數量級。

在C代碼中應該有a[i]而不是a[Max]。至於緩存:由於您只能訪問C代碼中的一個內存位置(觸發未定義的行爲),因此您的C測試是完全無效的。

即使它是正確的,你的方法也是有缺陷的。乘法運算甚至整個循環都可能被C編譯器徹底跳過,因爲沒有任何事情取決於它們的結果。

預計第一次運行花費很長時間,第二次花費更少時間的結果。無論如何,數據必須被加載到緩存中,這需要時間。一旦加載完成,對這些數據的操作需要更少的時間。

即使在執行循環之前,Java可能根本不使用緩存(不太可能)或預加載整個數組以緩存。這將解釋平等的執行時間。

+0

感謝您的回答 –

2

你有三個高速緩存大小,這些都是典型的

  • L1:32 KB(數據),4個時鐘週期
  • L2:256KB,10-11個時鐘週期
  • L3:3-24 MB。 40 - 75個時鐘週期。

任何比這大的東西都不適合緩存,就好像你只是在內存中滾動一樣,就好像它們不在那裏一樣。

我建議你編寫一個測試,根據經驗確定CPU緩存大小作爲一個很好的練習來幫助你理解這一點。順便說一句,你不需要使用*=來鍛鍊緩存,因爲這會練習ALU。也許有一個更簡單的操作,你可以使用;)

在你的Java代碼的情況下,很可能它還沒有編譯,所以你看到interperator的速度,而不是內存訪問。

我建議你在較小的內存大小上反覆運行測試至少2秒並取平均值。

+0

+1,指出Java結果很可能是假的。 –

+0

@StephenC在實際使用情況下,您只需調用一次該方法來處理這個數據集大小就是正確的。在這種情況下,如果您使用選擇排序,您很可能不關心性能。 –

+0

@PeterLawrey謝謝,我會嘗試一下你的答案 –