Допустим, у меня есть класс, который содержит члены данных с выделенной кучей памяти:
class X{
std::map<int, double> a;
std::set<int> b;
std::vector<int>;
std::string c;
}
и у меня есть std::vector<shared_ptr<X>>
содержащий многие из них X
объекты, через которые я буду проходить и получить доступ к map.begin ():
for(int i =0; i<vec.size(); i++){
running_total += *(vec[i]->a.begin());
}
Теоретически, сколько объектов я должен быть в состоянии удерживать / перебирать в векторе, прежде чем я столкнусь с отсутствием кэша L3?
Я думал, что ответом будет то, сколько строк кэша на объект может вместить кэш L3, но L3 size / sizeof (x_element.get ()), похоже, не дает мне ответ, который я вижу из профилирования ….
Мой кэш L3 составляет 8 МБ, каждая строка кэша — 64 байта, и поэтому я мог бы хранить около 125 000 объектов до того, как кэш L3 пропадет. Однако я вижу, что кэш L3 пропускает при гораздо меньшем количестве векторных элементов.
На процессорах Intel вы можете использовать Анализатор кода архитектуры Intel (IACA) для анализа вашей петли. Если я правильно помню, он также может анализировать ошибки кэша, если вы правильно настроили его и т. Д.
Другим инструментом является Valgrind, который является симулятором, который также можно использовать для имитации поведения кэша, если вы настроите его правильно.
Но в целом, чтобы максимизировать использование кэша, вы должны выделить данные, по которым вы выполняете итерацию, в один линейный массив (и как можно меньшего размера). Например. один массив с ключами (или данными, которые вы перебираете) и один массив с остальными, если это возможно. Таким образом, короче говоря, кеш действительно включается, только если адреса данных, по которым вы перебираете, упорядочены линейно, а НЕ произвольный доступ, как вы получите, если вы перебираете множество объектов, расположенных в разных местах в куче.