Продолжая в соответствии с ответом @ Mike_Dunlavey:
Сначала получите профиль на основе времени, используя ваш любимый инструмент: VTune или PTU или OProf.
Затем получите профиль пропуска кэша. Отсутствует кэш L1, отсутствует кэш L2, или ...
т.е. первый профиль связывает «затраченное время» с каждым счетчиком программы.
Вторая ассоциирует значение «число пропусков кэша» с каждым счетчиком программы.
Примечание: я часто «сокращаю» данные, суммируя их по функциям или (если у меня есть технология) по циклам. Или по бинам, скажем, 64 байта. Сравнение отдельных программных счетчиков часто бесполезно, потому что счетчики производительности нечеткие - место, где вы видите сообщение об ошибке кэша, часто несколько отличается от того, где это произошло на самом деле.
ОК, теперь нарисуйте эти два профиля, чтобы сравнить их. Вот некоторые графики, которые я считаю полезными:
Диаграммы "Айсберг": ось X - это ПК, положительная ось Y - время, отрицательный доступ Y - это пропуски кэша. Поиск мест, которые идут как вверх, так и вниз.
(Диаграммы с чередованием также полезны: та же идея, ось X - это ПК, график и время, и тайник пропуска по оси Y, но с узкими вертикальными линиями разных цветов, обычно красного и синего. Места, где много обоих потраченное время и потери в кеше будут иметь чередующиеся красные и синие линии, почти выглядящие фиолетовыми. Это распространяется на пропуски кеша L2 и L3, все на одном графике. Кстати, вы, вероятно, хотите «нормализовать» числа, либо на% возраст общего времени или пропусков кэша, или, что еще лучше,% возраста максимального момента времени или пропадания кэша. Если вы неправильно укажете масштаб, вы ничего не увидите.)
XY-диаграммы : для каждого контейнера выборки (ПК, или функции, или петли, или ...) построить точку, у которой X-координата - нормализованное время, а Y-координата - это нормализованный кеш пропускает . Если вы получаете много точек данных в верхнем правом углу - большой процент времени возрастает и большой процент кэшей возраста пропадает - это интересное доказательство. Или забудьте количество баллов - если сумма всех процентов в верхнем углу велика ...
Обратите внимание, к сожалению, что вам часто приходится проводить эти анализы самостоятельно. Последний раз я проверял, VTune не делает это для вас. Я использовал gnuplot и Excel. (Предупреждение: Excel умирает выше 64 тысяч точек данных.)
Еще совет:
Если ваш умный указатель встроен, вы можете получить счет повсюду. В идеальном мире вы сможете отследить ПК до исходной строки исходного кода. В этом случае вы можете немного отложить сокращение: посмотрите на все отдельные ПК; отобразить их обратно на строки исходного кода; и затем отобразите их в исходную функцию. Многие компиляторы, например GCC, есть опции таблицы символов, которые позволяют вам сделать это.
Кстати, я подозреваю, что ваша проблема не в том, что умный указатель вызывает перегрузку кэша. Если вы не делаете smart_ptr повсюду. Если вы делаете smart_ptr , а sizeof (Obj) + больше, чем, скажем, 4 * sizeof (Obj *) (и если сам smart_ptr не очень большой), то это не так уж много.
Скорее всего, интеллектуальный указатель вызывает дополнительный уровень косвенности, который вызывает вашу проблему.
По совпадению, я разговаривал с парнем за ланчем, у которого был умный указатель с подсчетом ссылок, который использовал дескриптор, то есть уровень косвенности, что-то вроде
template<typename T> class refcntptr {
refcnt_handle<T> handle;
public:
refcntptr(T*obj) {
this->handle = new refcnt_handle<T>();
this->handle->ptr = obj;
this->handle->count = 1;
}
};
template<typename T> class refcnt_handle {
T* ptr;
int count;
friend refcnt_ptr<T>;
};
(я бы так не кодировал, но он служит для изложения.)
Двойная косвенность this-> handle-> ptr может быть большой проблемой производительности. Или даже тройная косвенность, это-> handle-> ptr-> field. По крайней мере, на машине с 5 циклами попаданий в кэш L1 каждое поле this-> handle-> ptr-> будет занимать 10 циклов. И будет гораздо сложнее перекрывать, чем погоня за одним указателем. Но, что еще хуже, если каждый из них является пропуском кеша L1, даже если до L2 было всего 20 циклов ... ну, гораздо сложнее скрыть 2 * 20 = 40 циклов задержки кеша, чем одиночное промах L1.
В общем, это хороший совет, чтобы избегать уровней косвенности в умных указателях. Вместо того, чтобы указывать на дескриптор, на который указывают все умные указатели, который сам указывает на объект, вы могли бы увеличить умный указатель, указав на него объект и дескриптор. (Что больше не то, что обычно называют дескриптором, а больше похоже на информационный объект.)
1049 * Е.Г. *
template<typename T> class refcntptr {
refcnt_info<T> info;
T* ptr;
public:
refcntptr(T*obj) {
this->ptr = obj;
this->info = new refcnt_handle<T>();
this->info->count = 1;
}
};
template<typename T> class refcnt_info {
T* ptr; // perhaps not necessary, but useful.
int count;
friend refcnt_ptr<T>;
};
В любом случае, профиль времени - ваш лучший друг.
О да, аппаратное обеспечение Intel EMON также может подсказать, сколько циклов вы ожидали на ПК. Это может отличить большое количество пропусков L1 от небольшого количества пропусков L2.