开发者

Preventing Singleton Cache Miss in C++

Is there a way to prevent a cache miss when using singleton objects? Here's my current singleton implementation:

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

Is there a better way to do this that prevents a cache miss? Is this just another reason to not use singletons?


Update: Turns out it really was nothing to do with cache as much as the code generated for stack unwinding and the conditional check in the GetSingleton() call. By explicitly creating and destroying the singleton (instead of demand-creating it开发者_StackOverflow中文版), and creating an accessor for the static instance, I was able to avoid much of the overhead and noted a significant speedup in profiling.

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


This is a very specific question people arrive to way down the performance optimization road. Are you sure you're all the way there? Reason I'm asking is if you access your Singleton frequently enough, the pointer to the object will stay in cache. If it's not in cache, then you're not accessing the object frequently enough, which means you don't really need it, so prefetching the pointer (or the object) to cache will just steal precious cache space from something that you're using more often in reality - this might even hurt the performance in a long run. In my understanding arriving the question you're at currently you'd have to go through the following steps:

  1. profile your application to find out that static SingletonObject* SingletonObject(); function really is a hot spot (>10% of the overall time is spend executing this one function)
  2. profile your application with event-based sampling collector (like Intel VTune) to find out that cache misses are responsible for this function's execution time. Which it does not have to be. It could just be the number of calls you make to the function (do a call count).
  3. And after figuring out that the pointer is not in cache (which cache by the way? L1 or L2 or LLC? L1 and L2 are quite small and latency to access L2 is ~10 cycles, so L1 miss is not a huge problem) you'd go through your code to figure out why it is not. Meaning you'd look at the amount of data being accessed in between calls to static SingletonObject* SingletonObject(); and inspect if all those accesses are necessary. If they are, then it's a justified cache miss and you can't do anything about it. If they're not, then reduce your working set by as much as you can and re-run the profiler (step 2).
  4. Only when you're done with 1-3 and you're still seeing cache misses on access to Singleton object and you see that this hurts the performance, only then you put _mm_prefetch() calls in your code prior to accessing the Singleton object.
  5. And then go through 1-3 once again (well, at least step 1) to make sure that step 4 improved the performance as opposed to hurting it, which it could by polluting your chosen level of cache.


No, not without greater knowledge throughout your program that there is an upcoming reference to the singleton's pointer which it could then use to prime the L1/L2 caches with both the pointer, and the object that it is going to refer to.

This technique is called prefetching.


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

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜