Кеширование производительности векторов, матриц и кватернионов - PullRequest
5 голосов
/ 07 ноября 2011

В прошлом я неоднократно замечал код на C и C ++, который использует следующий формат для этих структур:

class Vector3
{
    float components[3];
    //etc.
}

class Matrix4x4
{
    float components[16];
    //etc.
}

class Quaternion
{
    float components[4];
    //etc.
}

Мой вопрос: приведет ли это к лучшей производительности кеша, чем, скажем, это:

class Quaternion
{
    float x;
    float y;
    float z;
    //etc.
}

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


После некоторых советов от респондентов, я проверил разницу, и она на самом деле медленнее с массивом - я получаю разницу примерно в 3% по частоте кадров. Я реализовал operator [], чтобы обернуть доступ к массиву внутри Vector3. Не уверен, имеет ли это какое-либо отношение к этому, но я сомневаюсь в этом, так как в любом случае это следует указать. Единственный фактор, который я мог видеть, это то, что я больше не мог использовать список инициализатора конструктора в Vector3(x, y, z). Однако, когда я взял исходную версию и изменил ее, чтобы больше не использовать списки инициализатора конструктора, он работал очень незначительно медленнее, чем раньше (менее 0,05%). Понятия не имею, но, по крайней мере, теперь я знаю, что оригинальный подход был быстрее.

Ответы [ 3 ]

3 голосов
/ 07 ноября 2011

Эти объявления не эквивалентны в отношении макета памяти.

class Quaternion
{
    float components[4];
    //etc.
}

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

Приводит ли это к лучшей или худшей производительности, зависит в основном от вашего компилятора, так что вам придетсяпрофиль.

1 голос
/ 07 ноября 2011

Я не уверен, что компилятору удастся оптимизировать код лучше при использовании массива в этом контексте (например, в союзах), но при использовании таких API, как OpenGL, это может быть оптимизацией при вызове таких функций, как

void glVertex3fv(const GLfloat* v);

вместо звонка

void glVertex3f(GLfloat x, GLfloat y, GLfloat z);

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

1 голос
/ 07 ноября 2011

Я думаю, что разница в производительности от такой оптимизации минимальна.Я бы сказал, что-то вроде этого впадает в преждевременную оптимизацию для большинства кода.Однако, если вы планируете выполнять векторную обработку своих структур, скажем, с помощью CUDA, состав структуры имеет важное значение.Посмотрите на страницу 23, если вы заинтересованы: http://www.eecis.udel.edu/~mpellegr/eleg662-09s/li.pdf

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