从性能的角度来看,哪个更快

What is faster from an performance standpoint of view?

本文关键字:性能      更新时间:2023-10-16

从性能的角度来看,哪个顺序实现会更快(我确实意识到第二种实现需要更多的内存和时间来将值写入RAM):

for(int j=3; j<=ceil(sqrt(i));j++){
...
}

int max=ceil(sqrt(i));
for(int j=3; j<=max;j++){
...
}

这与编译器如何处理这些代码有关。任何关于在哪里寻找答案的提示都是欢迎的。

注::请不要建议直接通过运行来检查性能。我必须提醒大家,底层系统的架构可能会有很大的不同。因此,第一种情况可能在一种架构上获胜,而第二种情况可能在另一种架构上占主导地位。所以我需要一个明确的治疗方法。这可能是编译器规范,让我们将情况限制为gcc。从这一点来看,问题将是:我应该在编译器规范的哪个部分找到它?

我想这要看情况。如果编译器能够证明i在循环执行期间没有改变,则常量传播可以删除sqrt()和ceil()的重复求值。如果编译器在执行过程中不能确定i是常量,它别无选择,只能在第一个例子中一次又一次地求值ceil(sqrt())。

我做了一些测量并使用了底部的代码(也可以随意使用)。

  • VC2013 (intel core i3 1.80GHz)测试结果:
  TIME FUN1 = 73.8 milli-seconds
  TIME FUN2 = 72.2 milli-seconds
  • GCC v4.7.2的结果(没有特征):
  TIME FUN1 = 23.7 milli-seconds
  TIME FUN2 = 23.5 milli-seconds

似乎第二种方法略优于第一种方法(我认为这是预期的)。然而,并不是慢了一个数量级。在我看来,差异很小,无法得出一个安全的结论。显然,编译器优化和系统架构起着重要的作用。

#include <iostream>
#include <cmath>
#include <chrono>
// facility to measure time
template<typename TimeT = std::chrono::milliseconds>
struct ExecTime
{
    template<typename F>
    static typename TimeT::rep exec(F const &func)
    {
        auto start = std::chrono::system_clock::now();
        func();
        auto duration = std::chrono::duration_cast< TimeT>(
            std::chrono::system_clock::now() - start);
        return duration.count();
    }
};
// dummy function to call in loop
void dummy() { int a = 0; }
int main()
{
  int const iters = 30;
  double d = 999999999999.0;
  auto fun1 = [&]() {for (int j = 3; j <= ceil(sqrt(d)); j++) dummy();};
  auto fun2 = [&]() {int max = ceil(sqrt(d)); for (int j = 3; j <= max; j++) dummy(); };
  double time1 = 0.0;
  for(int i = 0; i < iters; ++i) {
    time1 += ExecTime<>::exec(fun1);
  }
  double time2 = 0.0;
  for (int i = 0; i < iters; ++i) {
    time2 += ExecTime<>::exec(fun1);
  }
  std::cout << "TIME FUN1 = " << time1 / static_cast<double>(iters) << " milli-seconds" << std::endl;
  std::cout << "TIME FUN2 = " << time2 / static_cast<double>(iters) << " milli-seconds" << std::endl;
  return(0);
}