【问题标题】:Modern approach to making std::vector allocate aligned memory使 std::vector 分配对齐内存的现代方法
【发布时间】:2020-05-26 22:01:25
【问题描述】:

following question 是相关的,但答案是旧的,用户 Marc Glisse 的评论表明,自 C++17 以来有新的方法可以解决这个问题,但可能没有得到充分讨论。

我正在尝试让对齐内存为 SIMD 正常工作,同时仍然可以访问所有数据。

在 Intel 上,如果我创建一个 __m256 类型的浮点向量,并将我的大小减少 8 倍,它会给我对齐内存。

例如std::vector<__m256> mvec_a((N*M)/8);

我可以用一种有点笨拙的方式将指向向量元素的指针转换为浮点数,这样我就可以访问单个浮点值。

相反,我希望有一个正确对齐的 std::vector<float>,因此可以加载到 __m256 和其他 SIMD 类型中而不会出现段错误。

我一直在调查aligned_alloc

这可以给我一个正确对齐的 C 样式数组:

auto align_sz = static_cast<std::size_t> (32);
float* marr_a = (float*)aligned_alloc(align_sz, N*M*sizeof(float));

但是我不确定如何为std::vector&lt;float&gt; 执行此操作。将 marr_a doesn't seem to be possible 的所有权授予 std::vector&lt;float&gt;

我看到了一些建议我应该写一个custom allocator,但这似乎需要做很多工作,也许现代 C++ 有更好的方法?

【问题讨论】:

  • 没有 segfaulting... 或者当您使用 _mm256_loadu_ps(&amp;vec[i]) 时不会因缓存行拆分而导致潜在的减速。 (尽管请注意,使用默认调整选项,GCC splits not-guaranteed-aligned 256-bit loads/stores 进入 vmovups xmm / vinsertf128。因此,如果您关心代码在 GCC 上的编译方式,使用 _mm256_load 优于 loadu如果有人忘记使用-mtune=...-march= 选项。)
  • @PrunusPersica 你最终让它工作了吗?我也有同样的问题。如果您愿意,我们可以合作吗?
  • @gansub 我最终使用了boost::alignment::aligned_allocator 的代码。然后我可以用std::vector&lt;T, aligned_allocator&lt;float&gt;&gt; 分配向量。它确实使普通的std::vectors 与这种类型的对齐向量不直接兼容,但你总是可以写出绕过它的方法。

标签: c++ c++17 stdvector simd memory-alignment


【解决方案1】:

标准 C++ 库中的所有容器,包括向量,都有一个可选的模板参数that specifies the container's allocator,实现自己的也不是很多工作:

class my_awesome_allocator {
};

std::vector<float, my_awesome_allocator> awesomely_allocated_vector;

您将不得不编写一些代码来实现您的分配器,但它不会比您已经编写的代码多多少。如果您不需要 C++17 之前的支持,您只需要实现 allocate()deallocate() 方法即可。

【讨论】:

  • 他们还需要专精allocator_traits
  • 这可能是一个规范答案的好地方,举个例子,人们可以复制/粘贴以跳过 C++ 烦人的箍。 (如果有办法让 std::vector 尝试就地重新分配而不是通常的脑死 C++ 总是分配 + 复制,则加分。)当然还要注意这个 vector&lt;float, MAA&gt;vector&lt;float&gt; 不类型兼容(不可能是因为在没有此分配器的情况下编译的普通std::vector&lt;float&gt; 上执行.push_back 的任何操作都可以执行新分配并复制到最小对齐内存中。并且new/delete 与aligned_alloc/free 不兼容)跨度>
  • 我认为不能保证分配器返回的指针直接用作std::vector的数组的基地址。例如,我可以想象一个std::vector 的实现,它只使用一个指向分配内存的指针,它将结束/容量/分配器存储在值范围之前的内存中。这很容易破坏分配器完成的对齐。
  • 除非std::vector 保证。这就是它的用途。也许您应该查看 C++ 标准在此处指定的内容。
  • > 他们还需要专门化allocator_traits——不,他们不需要。所需要的只是实现一个兼容的分配器。
猜你喜欢
  • 2012-10-08
  • 2019-08-08
  • 1970-01-01
  • 1970-01-01
  • 2010-12-30
  • 1970-01-01
  • 1970-01-01
  • 2015-09-24
相关资源
最近更新 更多