【发布时间】:2018-11-13 06:03:17
【问题描述】:
我目前正在研究 C 优化,并且过去有一个任务是优化一段代码。在其他优化(展开循环和强度降低)中,我根据缓存大小使用了阻塞(按照英特尔关于此事的教程):
现在我想我明白为什么这种技术在这种情况下有效,当步幅为 1 时,它将块加载到缓存中,并在访问内存中的下一个位置时减少了未命中的数量。但在我的代码中,dst[dim * jj + ii] 似乎到处乱跳,因为它在最里面的循环中乘以 jj。缓存是如何解决这个问题的? dim 乘以 0 然后 1 然后 2 等等,在某些时候它将超过块可以容纳的值,优化将毫无意义。我理解这个正确吗?
然而,在实践中,当我仅对 jj 变量使用阻塞时,我并没有通过在 ii 和 jj 上使用阻塞来提高性能。所以我让它更快,但不知道为什么。现在作业已经过去了,但我还是不明白,很沮丧。
预先感谢您接受这个可能非常愚蠢的问题。
void transpose(int *dst, int *src, int dim)
{
int i, j, dimi, jj,ii;
dimi = 0;
for(i=0; i < dim; i+=block_size)
{
for(j=0; j<dim; j+=block_size)
{
for(ii = i; ii < i+block_size; ii++)
{
dimi = dim * ii;
for(jj = j; jj < j+block_size; jj++)
{
dst[dim*jj + ii] = src[dimi + jj];
}
}
}
}
}
【问题讨论】:
-
什么编译器具有什么优化级别,在什么硬件上?
gcc -O3将自动矢量化,但 IDK 如果它会在这里做得很好。连续存储可能比连续加载更好;然后您可以使用矢量加载+随机播放和矢量存储进行矢量化。但是,编译器可以在ii循环(从内部的第二个)而不是内部对循环进行矢量化,并并行生成 4 个dst[]结果。 (除了 x86 的 gcc 会进行向量加载并将其解压缩到 4 个存储中。它可以检查 src 和 dst 之间的重叠,但不会。godbolt.org/g/g24ehr IDK clang 对 256 字节的副本做了什么)
标签: c performance cpu-cache micro-optimization