【发布时间】:2017-11-26 21:49:30
【问题描述】:
我有一段代码在一个大矩阵上运行并计算按列分类的统计信息,其中的 bin 在向量 b 中给出。
代码是这样的:
for (item = 0; item < items; item++) {
uint8 bin = binvec[item];
for (col = 0; col < columns; col++) {
int idx = item * items_stride + col * cols_stride;
uint8 val = matrix[idx];
float x = matrix2[idx];
count[bin][val][col] += x;
}
}
假设在编译时列数是已知的。
matrix 的值没有特定的结构/顺序 - 假定为纯随机值。
数据量相当大:几百万个项目和数百列。
查看代码,我认为在以下情况下会实现最佳性能:
-
matrix是主要行,用于更好的缓存局部性。 -
count将作为count[bin][col][val]访问,因此可以优化count[bin][col]地址的计算,从而更容易预取等。
但是,在将matrix 创建为主要列并按照代码中出现的顺序访问count 时,我获得了最佳性能。
尝试使用选项 (1) 或 (2) 会导致约 50% 的运行时间损失。 这违背了我对缓存局部性和编译器优化、矢量化等的直觉。
知道为什么吗?这真的让我很困惑。
【问题讨论】:
-
是的,我预测您在此处编写代码的方式会更加优化,尤其是如果列数是编译时常数,因为编译器可以展开该循环(在某种程度上)。不幸的是,如果没有minimal reproducible example,我很难进一步调查这个问题。我无法验证您的计时结果;我无法分析常见编译器生成的代码;我无法尝试任何自己的优化来测试它们的效果。我所能做的就是说,“是的,这很奇怪。”对了,什么是“10x”?
-
10x 非常感谢 :) 无论矩阵内存布局和对
count的访问如何,都可以完成循环展开,所以我怀疑情况是否如此。不过我会尽快添加一个示例。
标签: c caching optimization nested-loops simd