【问题标题】:Memory Access Violations When Using SSE Operations使用 SSE 操作时的内存访问冲突
【发布时间】:2012-09-05 19:41:08
【问题描述】:

我一直在尝试重新实现一些现有的向量和矩阵类以使用 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 类型的元素,其组件全部初始化为 -11 之间的随机数。

这是我遇到的问题。如果sseVectors 的大小为8,191 或更小(我通过大量试验和错误得出的数字),则运行良好。如果大小为8,192 或更大,我在尝试运行时会收到此错误:

信号:SIGSEGV,si_code:0(地址内存访问冲突:0x00000080)

但是,如果我在最后注释掉该打印语句,即使 sseVectors 的大小为 8,192 或更大,我也不会收到错误。

我编写这个向量类的方式有问题吗?我正在运行带有 GCC 4.6 版的 Ubuntu 12.04.1

【问题讨论】:

  • 见:How is a vector's data aligned?(另外,第一个问题写得很好,+1。)
  • 您遇到了段错误,因为 STL 容器未与 SSE 对齐。 8192 发生的奇怪现象只是内存分配器中的一个伪影,它会影响返回指针的对齐方式。
  • 我认为要考虑的一个重要问题是_mm_add_ps() 例程正在加载多少数据,也许更关键的是,有多少数据被写回。这与浮点数组的实际大小有何关系?我认为这个问题的答案至少会指出三个问题——错误的计算结果、对齐问题和数组溢出......
  • 谢谢,我没有意识到这一点。我想这会带来另外几个问题:
  • 1) 这是否意味着每个使用 SSEVector3D 对象的数据结构和类也需要正确对齐?以及 Vector3D 的每个 std::vector 吗? [编辑:好吧,我想这不是“几个”问题,它只是一个!]

标签: c++ ubuntu vector sse sse3


【解决方案1】:

首先,不要这样做

__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 时,我的解决方案是对 SSE 部分使用英特尔的 C++ 编译器而不是 MSVC...

【讨论】:

    【解决方案2】:

    诀窍是注意__m128 是16 字节对齐的。使用_malloc_aligned() 确保您的浮点数组正确对齐,然后您可以继续将浮点数转换为__m128 的数组。还要确保您分配的浮点数可以被 4 整除。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-07-03
      • 1970-01-01
      • 2015-07-31
      • 1970-01-01
      • 1970-01-01
      • 2012-05-22
      • 2017-12-09
      • 1970-01-01
      相关资源
      最近更新 更多