在C ++中防止Singleton Cache Miss

时间:2011-08-03 18:46:02

标签: c++ caching singleton

使用单例对象时,有没有办法防止缓存未命中?这是我目前的单例实现:

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

2 个答案:

答案 0 :(得分:1)

不,在整个程序中没有更多的知识,即将出现对单例指针的引用,然后它可以使用指针和它将引用的对象来启动L1 / L2高速缓存。

这种技术称为预取。


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

答案 1 :(得分:1)

这是人们在性能优化之路上走下去的一个非常具体的问题。你确定你一直都在那里吗?原因我问的是,如果你经常访问你的Singleton,指向对象的指针将保留在缓存中。如果它不在缓存中,那么你就不会经常访问该对象,这意味着你并不真正需要它,因此将指针(或对象)预取到缓存只会从你所拥有的东西中窃取宝贵的缓存空间在现实中经常使用 - 从长远来看,这甚至可能会损害性能。 根据我的理解,你现在遇到的问题是你必须完成以下步骤:

  1. 对您的应用进行分析,以确定static SingletonObject* SingletonObject();功能确实是一个热点(>总时间的10%用于执行此功能)
  2. 使用基于事件的采样采集器(如Intel VTune)对您的应用程序进行概要分析,以发现缓存未命中对此函数的执行时间负责。它不一定是。它可能只是你对函数进行的调用次数(进行调用计数)。
  3. 在确定指针不在缓存中之后(顺便说一下哪个缓存?L1或L2或LLC?L1和L2非常小,访问L2的延迟是~10个周期,所以L1 miss不是很大问题)你会仔细检查你的代码,找出原因。这意味着您将查看在调用static SingletonObject* SingletonObject();之间访问的数据量,并检查是否所有这些访问都是必需的。如果它们是,那么这是一个合理的缓存未命中,你无法做任何事情。如果不是,请尽可能减少工作量并重新运行探查器(步骤2)。
  4. 只有当你完成1-3并且你仍然看到访问Singleton对象时出现缓存未命中并且你发现这会损害性能,只有这样你才能在代码之前加入_mm_prefetch()次调用访问Singleton对象。
  5. 然后再次通过1-3(好吧,至少第1步),以确保第4步改善了性能,而不是伤害它,这可能会污染您选择的缓存级别。