数组的迭代方向
iteration direction on an array
假设我们有两个基本类型的数组a
和b
(例如,float
),我们需要为每个有效索引i
计算a[i] + b[i]
,并存储结果。遍历数组以最大化缓存命中率的最佳方法是什么?是正面对反面,还是正面对反面?
对于这种操作,您应该使用编译器的自动向量化。迭代小i
到大i
。此外,答案取决于您所说的"存储结果"的含义以及您将要迭代的项目的数量n
。
如果你的意思是c[i] = a[i] + b[i]
和n
不是太小,那么你的编译器的自动矢量化器将在没有任何更改的情况下进行最佳优化。即使是MSVC也会得到正确的答案(至少对于SSE)。你的编译器将不得不对n做一些调整,而不是4的倍数(或AVX的8)和对齐,但这个成本将分摊到n上,除了很小的n
,这个开销的影响可以忽略不计。如果n
很小,那么你可能需要考虑对齐。到底有多小还有待确定,但我猜要比100小得多。
如果你指的是sum + = a[i] + b[i]
,减少,那么你确实需要考虑这个。这有一个依赖链,所以你需要展开你的循环3-10次。此外,您需要使用一个宽松的浮点模型,因为浮点算术不是关联的,没有它就无法进行自动向量化,因此将-ffast-math
添加到GCC(将/fp:fast
添加到MSVC)。如果展开循环并使用一个宽松的浮点模型,那么GCC、ICC、Clang和MSVC应该有效地自动向量化您的缩减。
为了利用缓存预取功能,您需要从前到后顺序读取数组。
此外,数组应该是SSE对齐的(16字节)。更重要的是,项(例如浮点数)将按其大小对齐(浮点数为4字节)。这一点很重要,这样数据就不会跨越缓存线(读取速度较慢)。
数组对齐后,您可以使用SSE/AVX在单个指令中执行4或8次操作来读取,添加和存储结果。
编辑:你可以在这里阅读更多关于缓存预取的内容,也可以在Intel SW开发者手册中阅读更深入的描述。
- 使用std::multimap迭代器创建std::list
- 来自 std::list 的迭代器 .end() 按预期返回"0xcdcdcdcdcdcdcdcd"但 .begin()
- C++中带有List类的迭代器Segfault
- 迭代时从向量和内存中删除对象
- 如何在c++迭代器类型中包装std::chrono
- 带过滤器的现代迭代c++集合
- 在c++中检查长方体是否尽可能快地重叠(无迭代)
- C++矢量迭代
- 集合上的输出迭代器:assign和increment迭代器
- Boost Spirit,获取迭代器内部语义动作
- 擦除while循环中迭代的元素
- 实现一个在集合上迭代的模板函数
- 对于set上的循环-获取next元素迭代器
- 在向量内的向量上迭代
- 为什么output_editor Concept不需要output_e迭代器标记
- TSP递归解的迭代形式
- c++17文件系统::recursive_directory迭代器()在mac上没有给出这样的目录,但在windows上
- 如何最好地控制迭代方向
- 数组的迭代方向
- 迭代方向枚举