Ориентированный на данные дизайн в ООП

На этих слайдах (после слайда 15) предлагается использовать

void updateAims(float* aimDir, const AimingData* aim, vec3 target, uint count)
{
     for(uint i = 0; i < count; i++)
     {
          aimDir[i] = dot3(aim->positions[i], target) * aim->mod[i];
     }
}

потому что это более эффективный кэш.

А если у меня есть класс

class Bot
{
    vec3 position;
    float mod;
    float aimDir;

    void UpdateAim(vec3 target)
    {
         aimDir = dot3(position, target) * mod;
    }
 };

 void updateBots(Bots* pBots, uint count, vec3 target)
 {
      for(uint i = 0; i < count; i++)
            pBots[i]->UpdateAim(target);
  }

И я храню все объекты этого класса в одном линейном массиве.

Так как они все в одном массиве, будут ли ошибки в кеше? Почему первый подход будет лучше?

2 ответа

Решение

Современные архитектуры кеша обычно структурированы как строки данных, каждая из которых достаточно велика, чтобы вместить несколько слов; 64 байта - это типичный размер строки. Когда вы пытаетесь прочитать данные, которых нет в кэше, извлекается целая строка, а не только нужное вам слово. При записи данные в кеше обновляются, если они там есть, но обычно их не нужно извлекать, если их там нет.

В первом случае для каждой выбранной строки кэша входных данных вы будете использовать каждое ее слово. Во втором случае вы будете использовать только некоторые поля структуры; получение других тратило определенную пропускную способность.

В частности, вы выбираете старое значение aimDir каждый раз, который не нужен для расчета. В целом, "объект", скорее всего, будет содержать больше полей, которые вам не нужны для этого конкретного расчета, тратя еще больше пропускной способности, когда они выбираются в кэш и затем игнорируются.

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

При первом подходе все aimDir данные хранятся в не фрагментированном блоке памяти. Таким образом, если вы обработали первый, вы можете сразу перейти к следующему элементу, поскольку он сохраняется в следующей единице памяти.

Если у вас есть массив Botс, тогда у вас есть Bot объекты хранятся в не фрагментированном блоке памяти. Но разные aimDir данные двух ботов теперь разделены другими данными ботом (positionа также mod).

Графически первый подход (если принять массивы для позиции и мода тоже) выглядит так

[R] означает случайные неизвестные данные, не связанные с ботами

[R][position_0][position_1]...[position_n][R][mod_0][mod_1]...[mod_n][R][aimDir_0][aimDir_1]...[aimDir_n][R]

Второй подход выглядит так:

[R][[position_0],[mod_0],[aimDir_0]][[position_1][mod_1][aimDir_1]]...[[position_n][mod_n][aimDir_n]][R]
Другие вопросы по тегам