解引用迭代器的性能



我有3个函数,可以归结为下面的代码,运行800x800次:

下面的每个while循环在iter1 == lim之前正好运行了800次,所以持续时间是按照运行800x800x800(512亿)次来测量的。

iter1iter2limdouble指针。它们指向一个足够大的double的向量。

sumdouble的局部变量。

s1s2为本地unsigned int,均等于800。

首次运行用时2.257秒:

while ( iter1 < lim )
{
    sum += *iter1 * *iter2;
    ++iter1;
    iter2 += s2;
}

Second runs in 7.364秒:

while ( iter1 < lim )
{
    sum += *iter1 * *iter2;
    iter1 += s1;
    iter2 += s2;
}

第三次跑1.355秒:

while ( iter1 < lim )
{
    sum += *iter1 * *iter2;
    ++iter1;
    ++iter2;
}

如果我将sum += *iter1 * *iter2;指令从它们中移除,它们都在1.07秒左右运行。

如果我删除第二个乘法并将指令更改为sum += *iter1;,则第一个和第三个运行时间为1.33秒,第二个运行时间为1.46秒。

如果我删除另一个迭代器,像这样:sum += *iter2;,那么第一个和第二个迭代器大约运行2.2秒,而第三个迭代器运行1.35秒。

显然,性能下降与添加到iter1iter2的数量有关。我不是处理器如何访问内存和解引用指针方面的专家,所以我希望社区中有人比我知道得更多,并愿意为我的问题提供一些启示。

如果您需要任何关于我运行这些测试的硬件的信息,或者任何其他可能证明有用的信息,请随时在评论中询问。

编辑:问题是第二个函数很慢,当与其他函数相比,我想知道是否有什么我可以做的,使它运行得更快,因为它似乎是做类似的事情像其他2。

编辑2:所有的测量都是在发布版本

这只是数据局部性的一种表现。看一本书下一页的东西比看下一页第800页的东西花的时间要少。

性能差异与迭代器无关。区别在于以大于单位步长推进大量数据所造成的额外缓存丢失。

我猜是生成的机器码,这取决于编译器/平台的复杂程度。

为了检索指针值,内部机器将使用类似LOAD指令的东西,我们将虚构的汇编代码称为LD addr0

addr0是指所使用的地址寄存器。

许多cpu提供了LD addr0+这样的语句,在加载存储值后增加地址。通常,这个额外的增量不会导致任何额外的循环。

我使用过一些编译器,它们只能在地址递增操作符直接在解引用语句之后或在解引用语句中完成时生成addr0+语句。

所以最后一个可能是最有效的机器代码的例子。

如果您可以为每个示例发布编译过程的结果汇编代码,那将会很有趣。

最新更新