拥有类变量或本地函数变量更好/更快?

时间:2009-11-30 00:18:51

标签: c++ optimization

好的,我知道标题并没有完全解释这个问题。所以我正在编写一个执行大量计算的程序,我正在尝试对其进行优化,以使其运行速度不会那么慢。我有一个函数,它是一个被调用大约500万次的类的成员。这是功能:

void PointCamera::GetRay(float x, float y, Ray& out)
{
    //Find difference between location on view plane and origin and normalize
    float vpPointx = pixelSizex * (x - 0.5f * (float)width);
    float vpPointy = pixelSizey * (((float)height - y) - 0.5f * height);

    //Transform ray to camera's direction
    out.d = u * vpPointx + v * vpPointy - w * lens_distance;
    out.d.Normalize();

    //Set origin to camera location
    out.o = loc;
}

我想知道在类中声明变量vpPointx和vpPointy是否比在每次调用函数时声明它们更好/更快。这是一个很好的优化还是效果不大?

总的来说,如果这里有任何可以优化的内容,请告诉我。

7 个答案:

答案 0 :(得分:10)

通过限制变量的范围,您可以为编译器优化器提供更多机会来重新排列代码并使其运行得更快。例如,它可能将这些变量的值完全保留在CPU寄存器中,这可能比内存访问快一个数量级。此外,如果这些变量是类实例变量,那么每次访问变量时,编译器都必须生成解除引用this的代码,这很可能比局部变量访问慢。

与往常一样,您应该自己测量性能并尝试两种方式(或者更好,尽可能多的方式)。所有优化建议都取决于您的编译器实际所做的任何事情,这需要进行实验。

答案 1 :(得分:3)

总是喜欢本地人

任何临时值都应该是本地的。这样的值可能完全存在于寄存器中而不会从缓存中踢出其他东西,或者需要一个无用的存储器存储,它将使用比CPU周期短得多的资源。

双3 GHz CPU每秒可执行60亿个CPU周期。为了接近这个60亿的数字,通常大多数操作都不应该涉及内存或高速缓存操作,并且下一条指令不需要大多数周期的结果,除非CPU可以找到可立即调度的后续指令。这一切都变得相当复杂,但是包括一些等待状态在内的60亿个事件肯定会每秒发生。

然而,同样的CPU系统每秒只能进行10到4千万次内存操作。差异部分由缓存系统补偿,尽管它们仍然比CPU慢,但它们的大小有限,并且它们不处理写入以及它们对读取的处理。

好消息是,在这种情况下,良好的软件抽象和软件速度优化都是一致的。除非您有理由在以后引用它,否则不要在对象中存储瞬态。

答案 2 :(得分:1)

如何预先计算一些永不改变的乘法。例如,w * lens_distance和0.5 * height。每当变量发生变化时计算一次,然后在此函数调用中使用存储的值。

答案 3 :(得分:1)

在课堂上声明它们会有性能损失。实际上,通过使用this->字段来访问它们。至少会有一个内存写入来存储结果。函数局部变量可以在整个生命周期中存在于寄存器中。

答案 4 :(得分:1)

我不确定,虽然我的猜测是在函数内部更好(因为它只是在堆栈上“声明”变量,而使它成为类的一部分意味着每次使用间接从内存访问它你访问它)。当然,实际上编译器可能无论如何都会将所有这些优化到寄存器中。

这让我想到了我的观点:

你的方式错误

我认为没有人能真正告诉你什么会更快。即使有人这样做也没关系。 唯一真正的优化方法是衡量

这通常意味着两件事之一:

  1. 一种选择是尝试每种方式,测量所需的时间,并进行比较。请注意,这并不总是微不足道的(因为每次运行有时会依赖于外部因素,困难的内存问题等)。但运行代码几百万次可能会为你解决这个问题。
  2. 理想情况下,您应该使用分析器。这是一款旨在为您量身定制的软件,并告诉您哪些部分需要花费最长的时间。由于大多数处理过优化问题的人会告诉您,您通常会对花费大量时间的事情感到惊讶。
  3. 这就是为什么你应该总是采用“科学”测量方法,而不是依赖任何人的猜测。

答案 5 :(得分:0)

似乎是一个光线追踪者。小事情确实加起来,但也考虑了大热门:你将获得一个巨大的加速与适当的空间划分。在复杂的场景中获得一些octtree或KD-Tree可以获得几个数量级的加速。

至于你的直接问题:简介。

答案 6 :(得分:0)

其他人已经介绍了使用locals对类变量的好处,所以我不会讨论这个...但是因为你一般要求优化提示:

  • 你的int-to-float演员跳了出来。需要付出代价especially if you are using the x387 FPU。使用SSE寄存器会使它变得更好,但对于你的函数来说它看起来完全没必要:你可以简单地将它们的副本存储为类中的浮点数。
  • 您在评论中提到您仍在使用kd-tree。在进行低级优化之前,最好先完成它;现在看来重要的事情可能不会占用一小部分时间。
  • 使用指令级分析器,如VTune。 gprof没有给你足够的信息。
  • 你听说过ompf.org吗?这是一个很棒的光线追踪论坛,你可以在那里学到很多相关的优化。
  • 有关更多提示,请参阅my answer to this post
  • 阅读Agner Fog

顺便说一句:我听说Bounding Interval Hierarchy更容易实现。我没有实现kd-tree,但我已经实现了BIH,我认为它相当简单。