SSE, ряд основных против основных проблем производительности столбца

Для личного и забавного я пишу geom lib, используя SSE (4.1).

Последние 12 часов я провожу, пытаясь понять проблему с производительностью при работе с основной строкой и основной хранимой матрицей столбцов.

Я знаю, что матрицы Dirext / OpenGL хранятся в основных строках, поэтому для меня было бы лучше, чтобы мои матрицы сохранялись в основном порядке строк, поэтому у меня не будет преобразования при сохранении / загрузке матриц в / из GPU / шейдеров.

Но я сделал некоторое профилирование, и я получил более быстрый результат с Colomun Major.

Чтобы преобразовать точку с матрицей преобразования в мажорной строке, это P '= P * M., а в мажорной колонке - P' = M * P. Таким образом, в мажорной колонке это просто 4-х точечное произведение, так что всего 4 инструкции SSE4.1 (_mm_dp_ps), когда в ряду мажор я должен сделать эти 4-точечные произведения на транспонированной матрице.

Результат производительности на 10М векторах

(30/05/2014 @ 08: 48: 10) Журнал: [5] (Vec.Mul.Matrix) = 76,216653 мс (старшее преобразование строки)

(30/05/2014 @ 08: 48: 10) Журнал: [6] (Matrix.Mul.Vec) = 61,554892 мс (столбец главного преобразования)

Я попробовал несколько способов выполнить операцию Vec * Matrix, используя _MM_TRANSPOSE или нет, и самый быстрый способ, который я нашел, это:

mssFloat    Vec4::operator|(const Vec4& v) const //-- Dot Product
{
    return _mm_dp_ps(m_val, v.m_val, 0xFF ).m128_f32[0];
}
inline Vec4 operator*(const Vec4& vec,const Mat4& m)
{
    return Vec4(    Vec4( m[0][0],m[1][0],m[2][0],m[3][0]) | vec
        ,   Vec4( m[0][1],m[1][1],m[2][1],m[3][1]) | vec
        ,   Vec4( m[0][2],m[1][2],m[2][2],m[3][2]) | vec
        ,   Vec4( m[0][3],m[1][3],m[2][3],m[3][3]) | vec
                );
}

Мой класс Vec4 - это просто __m128 m_val, в оптимизированном C ++ векторное построение эффективно выполняется в регистре SSE.

Мое первое предположение, что это умножение не оптимально. Я новичок в SSE, поэтому я немного озадачен тем, как это оптимизировать, моя интуиция подсказывает мне использовать инструкцию случайного воспроизведения, но я бы хотел понять, почему это будет быстрее. Будет ли он загружать 4 shuffle __m128 быстрее, чем назначать (__m128 m_val = _mm_set_ps (w, z, y, x);)

Отhttps://software.intel.com/sites/landingpage/IntrinsicsGuide/ Я не смог найти информацию о производительности на mm_set_ps

РЕДАКТИРОВАТЬ: я дважды проверяю метод профилирования, каждый тест выполняется одинаково, поэтому нет различий в кэш-памяти. Чтобы избежать локального кэша, я делаю операцию для массива векторов рандомизированных ошибок, начальное число одинаково для каждого теста. Только 1 тест при каждом выполнении, чтобы избежать увеличения производительности из кеша памяти.

Ответы на вопрос(2)

Ваш ответ на вопрос