2017-02-23 61 views
0

我有一個內存訪問模式在我的程序像...如果地址B訪問往往後跟地址C訪問,緩存可以識別它嗎?

b1->c1 (b and c are address.) 
//.... do something else .... 
b2->c2 
//.... do something else .... 
b3->c3 
.... 

是編譯器/緩存/ CPU足夠聰明地認識到:
當我加載b,應該(準備)相應的負載c

更具體地說:它能以某種方式預測我的訪問模式並在某些方面對其進行優化嗎?
大致的好處是多少?

我創建了a test case。結果表明在運行時不能學習
(在現實情況下,B有很多領域,但往往->c

class C{ 
    public: int data=0; 
}; 
class B{ 
    public: C* c; int accu=0; 
    public: B(){ 
     c=new C(); 
    } 
    public: void doSomething(){ 
     accu+=c->data; //do something about c 
    } 
}; 
int main() { 
    using namespace std; 
    const int NUM=1000000; 
    B* bs[NUM]; 
    for(int n=0;n<NUM;n++){ 
     bs[n]=new B(); 
    } 
    for(int loop=0;loop<20;loop++){ 
     double accumulator=0; 
     for(int n=0;n<NUM;n++){ 
      int iSecret = rand() % NUM; 
      clock_t begin = clock(); 
      bs[iSecret]->doSomething(); 
      clock_t end = clock(); 
      accumulator+=double(end - begin); 
     } 
     double elapsed_secs = accumulator; 
     std::cout<<elapsed_secs<<std::endl; 
    } 
} 

打印(每循環一次)

如果能學習,後來的循環應使用比以前少的時間。

298749 
306951 
332946 
... 
337232 

我不認爲它可以利用Spatial locality,因爲c的地址很遠。

+0

不,我不這麼認爲。 – immibis

+0

@immibis謝謝,這是一個有價值的評論。 – javaLover

+0

你期望*它可以學習*?在最近的CPU管道AFAICT中總是用b加載c並不會更高效。 –

回答

1

在你的情況bs[iSecret]是它試圖通過doSomething()

這是用戶只可以通過適當地放置由你的b和c指示的數據優化用戶級別的邏輯,以便採取訪問某些其他地址c一個地址空間局部性的優勢。

作爲一個簡單的例子,你會期望編譯器優化這段代碼嗎?

int a[100][100]; 
for(int i = 0; i < 100; ++i) 
for(int j = 0; j < 100; ++j) 
    cout << a[j][i] << endl; 

然而,將它已經條件構造的情況下,像

address X: if(condition) 
      { 
address Y:  //dosomething_A 
      } 
      else 
      { 
address Z: //dosomething_B 
      } 

這裏,if條件爲address X等..

在這樣的條件結構編譯器可以生成代碼可以最小化流水線處理器上停頓週期(由於分支)的損失。

此外,流水線處理器可以在運行時使用Branch_predictor瞭解您的分支。

+0

我不太擅長英語,請問您可以回答一個非問題的陳述嗎?謝謝! – javaLover

+0

我只是說編譯器/處理器無法優化/預測用戶級邏輯。但是,編譯器可以優化編程語言結構,因爲它知道這些結構。同樣,CPU可以優化/預測指令流程,因爲它處理這些事情。 – sameerkn

+0

我想了解它。你的回答是否意味着:「答案是否定的,我應該讓b和c有類似的地址,爲了達到這個目的,我必須手動控制,例如你的第一個例子。」 ? – javaLover