【问题标题】:if T is aligned, std::vector<T> is aligned too?如果 T 对齐, std::vector<T> 也对齐?
【发布时间】:2014-05-17 16:29:52
【问题描述】:

我正在浏览一些新的 C++14 功能,aligned_storage 引起了我的注意,在讨论了并发性、局部性和数据结构对齐之后,我想到了一个事实,即分配给std::vector 保证在内存中是连续的,但这并不一定意味着向量本身被有效打包,或者更好的说法是,您关心的数据被有效对齐,可能有额外的东西有关该数据结构的信息,这些信息不一定对计算有用,并且可能会干扰您的数据。

所以我问,如果我有一个 class T 并且我知道 T 是按照我喜欢的方式对齐和打包的,那么 std::vector&lt;T&gt; 是否也可以缓存友好并在管道中对齐?

我的问题涉及 C++11 和 C++14,并且仅与数据结构布局有关,我不考虑与缓存行组织相关的其他问题,例如错误共享,或与事情如何获取相关的其他问题获取、加载和执行。

我知道这听起来很傻,但我只是怀疑。

【问题讨论】:

  • 你链接到的页面是 C++11。
  • @chris 有一部分说since C++14 有相关的差异。
  • 保证data()指向的内存由T类型的连续排列的元素组成。这还不够吗?
  • 我不太了解您的担忧。向量的元素由向量唯一拥有、适当对齐且连续。也许发布一些您担心的代表性代码?
  • 也许this demo 有帮助?

标签: c++ caching c++11 vector memory-alignment


【解决方案1】:

C++ 默认分配器需要为任何所谓的标准类型正确对齐结构,并且在结构末尾自动添加的填充(通过sizeof() 可见)通常有助于在连续分配中实现这一点。强>

struct C {
  uint8_t  a; // followed by 7B of invisible padding to naturally align b
  uint64_t b;
  uint32_t c;
  uint8_t  d; // followed by 3B padding for C (natural alignment of 8B due to b)
};
// sizeof(C) = 24B, alignof(C) = 8B

struct D {
  uint8_t  a; // followed by 3B padding for b
  uint32_t b;
  uint8_t  c; // followed by 3B padding for D (natural alignment of 4B due to b)
};
// sizeof(D) = 12B, alignof(D) = 4B

struct E {
  __m256 v; // SSE/AVX intrinsics handle natural alignment properly too
  char v2;
};
// sizeof(E) = 64B, alignof(E) = 32B

在大多数情况下,这已经足够了,但是如果你正在做花哨的转换技巧或需要 64B 缓存行对齐等,你可以使用alignas(),前提是你使用的是 C++11 或更新版本。这也部分地通过填充结构的末尾来工作:

struct alignas(64) F {
  double stuff[3];
};
// sizeof(F) = 64B, alignof(F) = 64B

void foo() {
  F f[4];
  // these addresses separated by (and even multiples of) 0x40 bytes:
  cout << &f[0] << " " << &f[1] << " " << &f[2] << endl;
}

如果您需要一个大块对齐,例如 4 kiB 页面边界,请使用 std::aligned_storage&lt;T&gt;。但是一般情况下,您只能靠自己安置new,而失去std::vector&lt;&gt; 为您做所有事情的便利。

【讨论】:

  • 您使用 64 字节对齐是因为您假设使用 AVX 寄存器或其他原因?另外你能举个自定义分配器的例子吗?
  • @user2485710 自定义分配器是一个相当复杂的主题,超出了您的问题范围。我稍微更改了答案,以便通过alignas() 为您提供更简单的解决方案。你可能不应该担心std::aligned_storage&lt;&gt;,除非你也需要页面边界对齐。
  • 谢谢,AVX/64 字节对齐呢?你为什么选择那个号码?
  • SSE 寄存器为 16B,AVX 为 32B,AVX-512 为 64B,与所有相关 x86_64 处理器中的 64B 高速缓存行大小相匹配。 64 是您多年来对单个结构的最大需求。
  • 是的,我知道,但我很好奇你为什么使用 64B,因为我打算用我的代码来定位 SSE2/3 CPU,我确保我们在同一页面上.也许我对AVX 的看法是错误的,我应该说AVX2,但无论如何我就是这么想的。谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-01
  • 2023-02-16
  • 2018-05-02
  • 2016-03-31
  • 2018-02-02
  • 2019-10-20
相关资源
最近更新 更多