Я пытался повторно реализовать некоторые существующие векторные и матричные классы для использования команд SSE3, и мне кажется, что я сталкиваюсь с этими ошибками «нарушения доступа к памяти» всякий раз, когда я выполняю серию операций над массивом векторов. Я относительно новичок в SSE, поэтому я начал с простого. Вот весь мой векторный класс:
class SSEVector3D
{
public:
SSEVector3D();
SSEVector3D(float x, float y, float z);
SSEVector3D& operator+=(const SSEVector3D& rhs); //< Elementwise Addition
float x() const;
float y() const;
float z() const;
private:
float m_coords[3] __attribute__ ((aligned (16))); //< The x, y and z coordinates
};
Итак, пока не так много всего, только несколько конструкторов, методов доступа и одна операция. Используя мои (по общему признанию ограниченные) знания о SSE, я реализовал операцию сложения следующим образом:
SSEVector3D& SSEVector3D::operator+=(const SSEVector3D& rhs)
{
__m128 * pLhs = (__m128 *) m_coords;
__m128 * pRhs = (__m128 *) rhs.m_coords;
*pLhs = _mm_add_ps(*pLhs, *pRhs);
return (*this);
}
Чтобы скоростно протестировать мой новый векторный класс по сравнению со старым (чтобы понять, стоит ли его заново реализовывать), я создал простую программу, которая генерирует случайный массив объектов SSEVector3D и складывает их вместе. Ничего сложного
SSEVector3D sseSum(0, 0, 0);
for(i=0; i<sseVectors.size(); i++)
{
sseSum += sseVectors[i];
}
printf("Total: %f %f %f\n", sseSum.x(), sseSum.y(), sseSum.z());
sseVectors
переменная представляет собой std :: vector, содержащий элементы типа SSEVector3D
все компоненты которого инициализируются случайными числами между -1
а также 1
,
Вот проблема, которая у меня возникла. Если размер sseVectors
является 8,191
или меньше (число, которое я получил через много проб и ошибок), это работает нормально. Если размер 8,192
или больше, я получаю эту ошибку при попытке запустить ее:
сигнал: SIGSEGV, si_code: 0 (нарушение доступа к памяти по адресу: 0x00000080)
Однако, если я закомментирую этот оператор print в конце, я не получу ошибку, даже если sseVectors
имеет размер 8192 или более.
Что-то не так с тем, как я написал этот векторный класс? Я использую Ubuntu 12.04.1 с GCC версии 4.6
Прежде всего, не делай этого
__m128 * pLhs = (__m128 *) m_coords;
__m128 * pRhs = (__m128 *) rhs.m_coords;
*pLhs = _mm_add_ps(*pLhs, *pRhs);
С SSE, всегда загружать и хранить явно через соответствующие встроенные функции, никогда просто разыменовывая. Вместо того, чтобы хранить массив из 3-х чисел в вашем классе, сохраните значение типа _m128
, Это должно заставить компилятор корректно выравнивать экземпляры вашего класса, без необходимости align
атрибутов.
Обратите внимание, однако, что это не очень хорошо работает с MSVC. MSVC, как правило, не в состоянии справиться с требованиями выравнивания, более строгими, чем 8-байтовые, выровненные для аргументов по значению :-(. В прошлый раз, когда мне нужно было переносить код SSE в Windows, я решил использовать компилятор Intel C ++ для частей SSE вместо MSVC …
Хитрость заключается в том, чтобы заметить, что __m128
выровнен на 16 байт. использование _malloc_aligned()
чтобы убедиться, что ваш массив с плавающей точкой правильно выровнен, тогда вы можете продолжить и привести ваш float к массиву __m128
, Также убедитесь, что количество размещаемых вами чисел делится на четыре.