2011-08-03 6 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 *는 질문과 관련이없는 일반적인 의미를 가지고 있습니다. 여기서 문제는 질문이 명확하지 않다는 것, 그가 피하고 싶은 것은 무엇인가? 첫 번째 호출에서 포인터가 null이됩니까? 그것이 파괴 된 후에 그것은 null입니까? 그리고 캐시 미스로 용어를 섞어도 도움이되지 않습니다. –

답변

1

이 사람들이 성능 최적화 도로 아래로 길에 도착 매우 구체적인 질문입니다. 그곳에있는 것이 확실합니까? 이유는 당신이 싱글 톤에 자주 접근하면 객체에 대한 포인터가 캐시에 남을 것입니다. 캐시에 없으면 개체를 자주 자주 액세스하지 않습니다. 즉, 실제로 필요하지 않다는 것을 의미하므로 포인터 (또는 개체)를 캐시에 프리 페칭하면 소중한 캐시 공간을 훔칠 수 있습니다. 실제로는 더 자주 사용합니다. 이로 인해 장기적으로 성능이 저하 될 수도 있습니다. 현재에있어 질문에 도착하는 나의 이해에 다음 단계를 진행해야 할 것 :

  1. static SingletonObject* SingletonObject(); 기능은 정말 핫 스폿은 (는 것을 알아 보려면 응용 프로그램을 프로파일 링> 전체의 10 % 시간은이 하나의 함수를 실행하는 데 소요됩니다)
  2. 응용 프로그램에서 이벤트 기반 샘플링 수집기 (예 : Intel VTune)를 프로파일 링하여 캐시 누락이이 함수의 실행 시간을 담당하는지 확인합니다. 그럴 필요는 없습니다. 함수 호출에 대한 호출 수 (호출 횟수) 일 수 있습니다.
  3. 포인터가 캐시에 없다는 것을 알아 낸 후에 (L1, L2 또는 LLC? L1과 L2는 매우 작고 L2에 액세스하는 데 대기 시간은 ~ 10 사이클이므로 L1 누락은 큰 것이 아닙니다. 문제) 왜 코드가 아닌지 알아 내기 위해 코드를 살펴 보겠습니다. 의미는 당신이 static SingletonObject* SingletonObject();에 대한 호출 사이에 액세스되는 데이터의 양을보고 모든 액세스가 필요한지 검사합니다. 그렇다면 정당화 된 캐시 미스이므로 아무 것도 할 수 없습니다.그렇지 않다면 가능한 한 작업 세트를 줄이고 프로파일 러를 다시 실행하십시오 (2 단계).
  4. 싱글 톤 개체에 액세스 할 때 캐시 미스가 여전히 나타나며 성능이 좋지 않을 경우에만 _mm_prefetch() 호출을 Singleton 개체에 액세스하기 전에 코드에 넣어야합니다 .
  5. 그런 다음 1-3 단계를 반복하여 4 단계가 성능 저하를 방지하고 캐시의 선택한 수준을 오염시킬 수 있는지 확인하십시오 (적어도 1 단계 이상).
1

아니, 그 다음 소수에 사용할 수있는 싱글의 포인터에 곧 참조가 있음을 프로그램 전반에 걸쳐 큰 지식이없는 L1/L2 캐시는 포인터와 참조하려는 오브젝트를 모두 캐시합니다.

이 기술을 프리 페칭이라고합니다.


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