У меня есть класс вроде этого:
//Array of Structures
class Unit
{
public:
float v;
float u;
//And similarly many other variables of float type, upto 10-12 of them.
void update()
{
v+=u;
v=v*i*t;
//And many other equations
}
};
Я создаю массив объектов типа Unit. И назовите обновление для них.
int NUM_UNITS = 10000;
void ProcessUpdate()
{
Unit *units = new Unit[NUM_UNITS];
for(int i = 0; i < NUM_UNITS; i++)
{
units[i].update();
}
}
Чтобы ускорить работу и, возможно, автоматизировать цикл, я преобразовал AoS в структуру массивов.
//Structure of Arrays:
class Unit
{
public:
Unit(int NUM_UNITS)
{
v = new float[NUM_UNITS];
}
float *v;
float *u;
//Mnay other variables
void update()
{
for(int i = 0; i < NUM_UNITS; i++)
{
v[i]+=u[i];
//Many other equations
}
}
};
Когда цикл не работает autovectorize, я получаю очень плохую производительность для структуры массивов. Для 50 единиц обновление SoA немного быстрее, чем AoS. Но затем от 100 единиц вперед, SoA медленнее, чем AoS. В 300 единиц, SoA почти в два раза хуже. При 100K единицах SoA в 4 раза медленнее, чем AoS. Хотя кеш может быть проблемой для SoA, я не ожидал, что разница в производительности будет такой высокой. Профилирование на cachegrind показывает аналогичное количество промахов для обоих подходов. Размер объекта Unit равен 48 байтам. Кэш L1 составляет 256 КБ, L2 - 1 МБ, а L3 - 8 МБ. Что мне здесь не хватает? Это действительно проблема с кешем?
Edit: Я использую gcc 4.5.2. Параметры компилятора: -o3 -msse4 -ftree-vectorize.
Я сделал еще один эксперимент в SoA. Вместо динамического выделения массивов я выделял "v" и "u" во время компиляции. Когда есть 100K единиц, это дает производительность, которая в 10 раз быстрее, чем SoA с динамически распределенными массивами. Что тут происходит? Почему существует такая разница в производительности между статической и динамически распределенной памятью?