2011-08-03 53 views
-1

有沒有辦法在使用單例對象時防止緩存未命中?這是我目前單身的實現:用C++防止單例緩存錯誤

SingletonObject.h

#pragma once 

class SingletonObject 
{ 
public: 
    static SingletonObject* SingletonObject(); 
    static void SingletonObject(); 
private: 
    static SingletonObject* sSingletonObject; 
    SingletonObject(); 
    ~SingletonObject(); 
}; 

SingletonObject.cpp

#include "SingletonObject.h" 

SingletonObject* SingletonObject::sSingletonObject = NULL; 

SingletonObject:: SingletonObject() 
{ 
} 

SingletonObject::~ SingletonObject() 
{ 
} 

SingletonObject* SingletonObject::GetSingleton() 
{ 
    if (sSingletonObject == NULL) // cache miss 
    { 
     sSingletonObject = new SingletonObject(); 
    } 
    return sSingletonObject; 
} 

void SingletonObject::DestroySingleton() 
{ 
    delete sSingletonObject; 
    sSingletonObject = NULL; 
} 

有沒有更好的方式來做到這一點,以防止高速緩存未命中?這是不使用單身人士的另一個原因嗎?


更新:原來這真的是無關的緩存爲堆棧展開,並在GetSingleton()調用的條件檢查生成的代碼一樣多。通過顯式創建和銷燬單例(而不是創建需求)以及爲靜態實例創建訪問器,我可以避免大部分開銷,並指出分析過程中的顯着加速。

SingletonObject.h

#pragma once 

class SingletonObject { 
public: 
    static void CreateSingleton(); 
    static void DestroySingleton(); 
    static inline SingletonObject* GetSingleton() { return sInstance; } 
private: 
    static SingletonObject* sInstance; 

    SingletonObject(); 
} 

SingletonObject.cpp

#include "SingletonObject.h" 

void SingletonObject::CreateSingleton() { 
    if (sInstance == NULL) 
     sInstance = new SingletonObject();` 
} 

void SingletonObject::DestroySingleton() { 
    delete(sInstance); 
    sInstance = NULL; 
} 
+3

你在哪裏看到緩存未命中? –

+0

@Alenxandre C.你不在'GetSingleton()'方法中看到那個註釋嗎? – Tom

+0

@Tom:* cache miss *具有與問題無關的常見含義。這裏的問題是這個問題不清楚,他想避免什麼?在第一次調用時指針爲空?它在被銷燬之後爲空?混合條款作爲緩存未命中沒有幫助。 –

回答

1

這是人到達後話了性能優化路一個非常具體的問題。你確定你一直在那裏?我問的原因是,如果你足夠頻繁地訪問你的Singleton,那麼指向這個對象的指針將停留在緩存中。如果它不在緩存中,那麼你沒有足夠頻繁地訪問這個對象,這意味着你並不需要它,所以預取緩存的指針(或對象)只會從你所擁有的東西中竊取寶貴的緩存空間在現實中更頻繁地使用 - 這可能甚至會長期影響性能。 在我的理解到達你在目前這個問題你必須要經過以下步驟:

  1. 配置您的應用程序,找出static SingletonObject* SingletonObject();功能確實是一個熱點(>整體的10%時間是花在執行這一功能上)
  2. 使用基於事件的採樣採集器(如英特爾VTune)來分析您的應用程序,以發現緩存未命中對此函數的執行時間負責。它不一定是。它可能只是您對該功能進行的呼叫次數(進行呼叫計數)。
  3. 在確定指針不在高速緩存中後(L1或L2或LLC的哪個高速緩存?L1和L2非常小,並且訪問L2的等待時間是〜10個週期,因此L1 miss不是一個巨大的問題)你會通過你的代碼來弄清楚爲什麼它不是。這意味着您可以查看在static SingletonObject* SingletonObject();調用之間訪問的數據量,並檢查是否有必要訪問所有這些訪問。如果他們是,那麼這是一個合理的緩存未命中,你不能做任何事情。如果不是,則儘可能減少工作集並重新運行探查器(步驟2)。
  4. 只有當您完成1-3並且您仍然在訪問Singleton對象時看到緩存未命中,並且您看到這會損害性能,那麼只有在訪問Singleton對象之前將_mm_prefetch()調用放入代碼中。
  5. 然後再次通過1-3(至少步驟1),以確保第4步改善了性能而不是傷害它,這可能會污染您選擇的緩存級別。
1

不,不是沒有,有一個即將到來的參考單的指針,它可能然後使用黃金在整個程序中的更多知識L1/L2與指針以及它將要引用的對象一起緩存。

這種技術被稱爲預取。


CF:http://portal.acm.org/citation.cfm?id=279529