Предотвращение пропадания одиночного кэша в C ++ - PullRequest
0 голосов
/ 03 августа 2011

Есть ли способ предотвратить потерю кэша при использовании одноэлементных объектов?Вот моя текущая реализация синглтона:

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.ч

#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 ]

1 голос
/ 04 мая 2012

Это очень специфический вопрос, с которым люди приходят на путь оптимизации производительности.Ты уверен, что ты весь путь туда?Причина, по которой я спрашиваю, заключается в том, что если вы обращаетесь к своему синглтону достаточно часто, указатель на объект будет оставаться в кэше.Если он не находится в кеше, значит, вы недостаточно часто обращаетесь к объекту, а это значит, что он вам на самом деле не нужен, поэтому предварительная выборка указателя (или объекта) для кеширования просто украдет драгоценное место в кешеиспользование чаще в реальности - это может даже повредить производительность в долгосрочной перспективе.В моем понимании, чтобы получить вопрос, по которому вы находитесь в данный момент, вам нужно будет выполнить следующие шаги:

  1. профилировать ваше приложение, чтобы узнать, что функция static SingletonObject* SingletonObject(); действительно является горячей точкой (> 10% от общего времени, потраченного на выполнение этой одной функции)
  2. профилирует ваше приложение с помощью сборщика выборок на основе событий (например, Intel VTune), чтобы выяснить, что пропуски кэша ответственны за время выполнения этой функции.Что это не должно быть.Это может быть просто количество обращений к функции (количество вызовов).
  3. И после выяснения, что указатель не находится в кеше (какой кеш между прочим? L1 или L2 или LLC?L1 и L2 довольно малы, и задержка для доступа к L2 составляет ~ 10 циклов, поэтому пропуск L1 не является большой проблемой). Вы должны были бы просмотреть свой код, чтобы выяснить, почему это не так.Это означает, что вы посмотрите на объем данных, к которым осуществляется доступ между вызовами static SingletonObject* SingletonObject();, и проверьте, все ли эти обращения необходимы.Если они есть, то это оправданная ошибка кэша, и вы ничего не можете с этим поделать.Если это не так, уменьшите свой рабочий набор настолько, насколько это возможно, и повторно запустите профилировщик (шаг 2).
  4. Только когда вы закончили с 1-3 и все еще видитеотсутствует доступ к кэшу при доступе к объекту Singleton, и вы видите, что это снижает производительность, только тогда вы добавляете в свой код вызовы _mm_prefetch() до доступа к объекту Singleton.
  5. И затем снова проходите через 1-3 (ну, по крайней мере, шаг 1) чтобы убедиться, что шаг 4 улучшил производительность, а не повредил ее, что могло бы привести к загрязнению выбранного вами уровня кэша.
1 голос
/ 03 августа 2011

Нет, не без больших знаний в вашей программе, что есть предстоящая ссылка на указатель синглтона, который он мог бы затем использовать для заполнения кэшей L1 / L2 как указателем, так и объектом, на который он будет ссылаться.

Этот метод называется предварительной выборкой.


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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...