2014-10-04 2 views
2

Я использую Eigen для обработки неструктурированного точечного набора (облака точек), представленного как массив объектов Eigen::Vector3f. Для того, чтобы включить векторную идентификацию SIMD, я подклассифицировал Vector3f в класс с alignas (16). Объекты в массиве начинаются с границы 16 байтов, имеют пробелы в 4 байта между собой и содержат неинициализированные данные.Eigen :: Vector3f alignment

Подкласс выглядит в настоящее время следующим образом: (Stil нужно добавить конструктор шаблонов копирования и оператор =, как указано в Эйгене документации)

struct alignas(16) point_xyz : public Eigen::Vector3f { 
    using Eigen::Vector3f::Vector3f; 
}; 

point_xyz cloud[n]; 

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

Безопасно ли использовать Eigen таким образом, или результаты зависят от содержимого неиспользуемых 4-байтовых зазоров и т. Д.?

Кроме того, было бы безопасно помещать данные цвета RGB или другое в неиспользуемые 4 байта (требуется переопределение выравнивания памяти)?

Редактировать: Кажется, что и clang ++, и g ++ выполняют некоторую векторизации, когда оптимизация включена. Без оптимизации (и ниже -O2 для лязга ++), как генерировать вызов библиотечной функции Эйгена для следующего умножения матриц (преобразование):

using transform_t = Eigen::Transform<float, 3, Eigen::Affine>; 
transform_t t = Eigen::AngleAxisf(0.01*M_PI, Eigen::Vector3f::UnitX()) * Eigen::Translation3f(0.1, 0.1, 0.1); 
Eigen::Vector3f p(123, 234, 345); 
std::cout << p << std::endl; 

for(;;) { 
    asm("# BEGIN TRANS"); 
    p = t * p; 
    asm("# END TRANS"); 
} 
std::cout << p << std::endl; 

(для цикла и соиЬ необходимы, так что оптимизация Безразлично 't удалить умножение или поставить постоянное значение).

В GCC (-O1) это приводит к

# 50 "src/main.cc" 1 
    # BEGIN TRANS 
# 0 "" 2 
    movss (%rsp), %xmm4 
    movaps %xmm4, %xmm2 
    mulss 64(%rsp), %xmm2 
    movss 4(%rsp), %xmm0 
    movaps %xmm0, %xmm1 
    mulss 80(%rsp), %xmm1 
    addss %xmm1, %xmm2 
    movss 8(%rsp), %xmm3 
    movaps %xmm4, %xmm5 
    mulss 68(%rsp), %xmm5 
    movaps %xmm0, %xmm1 
    mulss 84(%rsp), %xmm1 
    addss %xmm5, %xmm1 
    movaps %xmm3, %xmm5 
    mulss 100(%rsp), %xmm5 
    addss %xmm5, %xmm1 
    addss 116(%rsp), %xmm1 
    mulss 72(%rsp), %xmm4 
    mulss 88(%rsp), %xmm0 
    addss %xmm4, %xmm0 
    movaps %xmm3, %xmm4 
    mulss 104(%rsp), %xmm4 
    addss %xmm4, %xmm0 
    addss 120(%rsp), %xmm0 
    mulss 96(%rsp), %xmm3 
    addss %xmm3, %xmm2 
    addss 112(%rsp), %xmm2 
    movss %xmm2, (%rsp) 
    movss %xmm1, 4(%rsp) 
    movss %xmm0, 8(%rsp) 
# 52 "src/main.cc" 1 
    # END TRANS 
# 0 "" 2 

Это приводит к тому же выходу и без #define EIGEN_DONT_VECTORIZE 1. С Vector4f генерируется несколько более короткий выход, когда векторизация Эйгена не отключена, но оба работают с регистрами xmm.

AlignedVector3<float>, похоже, не поддерживает умножение с помощью Eigen::Transform. Я делаю аффинные преобразования на множествах точек, представленных с использованием 3 (неоднородных) координат. Я не уверен, как Eigen реализует трансформацию с Eigen::Transform<float, 3, Eigen::Affine> из Eigen::Vector4f. То есть изменяет ли он только первые 3 компонента вектора, а четвертый компонент должен быть равен нулю или может содержать произвольное значение или он интерпретирует 4-вектор как однородные координаты? И зависит ли оно от внутреннего представления преобразования (Affine, AffineCompact, Projective).

+0

Я удивлен, что SIMD используется. Разумеется, Eigen не генерирует явно SIMD в таком случае. Проверьте неподдерживаемый/Eigen/AlignedVector3 модуль для явно векторизованного vector3f. – ggael

+0

код кажется неэффективен. Конечно, «SIMD» будет использоваться, поскольку SSE используется по умолчанию для операций fp с большинством компиляторов (т. Е. Код 80x87 больше не генерируется). – user1095108

+0

'mulss' = mul Scalar Single-precision. Он использует векторные регистры, но это ** не SIMD **. Это как amd64 делает математику; x87 устарел для всего, кроме 80-битного 'long double' (который намного быстрее, чем любой другой способ получения более 64-битных поплавков). –

ответ

2

Не делайте этого! Вместо этого используйте Aligned Vector3 unsupported module. Например:

#include <unsupported/Eigen/AlignedVector3> 
// ... 
// and use it somewhere in the code: 
Eigen::AlignedVector3<double> a, b; 
// ... 
a += b;// will use simd instruction, even known they aren't real 3d vectors. 

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

Этот класс сделал его прозрачным для пользователя. Используйте его так же, как вы использовали обычный 3d-вектор, просто так!


АОМ в вопросе не используется SIMD, только скалярные операции FP в векторных регистров как нормальный для x86-64. (И для x86-32, когда имеется SSE). addss - это FP add Scalar Single-precision. (addps - дополнительно упакованный).

Авто-векторизация включена только в gcc по адресу -O3, а не -O2, и используется только -O1.

Неинициализированный элемент в каждом блоке 16B в основном предотвращает плавающие точки SIMD, поскольку они могут содержать денормалы или NaN, которые замедляют математические инструкции более чем на порядок (если вы не разрешите Denormals Are Zero и Flush To Zero, а компилятор знает это и может воспользоваться этим). Целочисленные инструкции не имеют этой слабости проблем с производительностью с мусором в некоторых элементах, но не ожидайте, что компиляторы будут автоматически векторизовать даже с этим.

+0

Хотя это может ответить на вопрос, [было бы предпочтительно] (http://meta.stackoverflow.com/q/8259) включить сюда основные части ответа и предоставить ссылку для справки. – IKavanagh