【问题标题】:Measure computation time测量计算时间
【发布时间】:2013-07-12 23:27:36
【问题描述】:

如何正确测量计算时间?

变体 1:

std::chrono::time_point<std::chrono::system_clock> start, end;  
    float elapsed = 0; 
    int N = 100;

    for(int i=0; i<N; ++i)
    {
        start = std::chrono::system_clock::now();
        func();//target function
        end = std::chrono::system_clock::now();
        elapsed += std::chrono::duration_cast<std::chrono::microseconds>(end-start).count();
    }

变体 2:

start = std::chrono::system_clock::now();
for(int i=0; i<N; ++i)
    func();
end = std::chrono::system_clock::now();
elapsed = std::chrono::duration_cast<std::chrono::microseconds>(end-start).count();

这些变体显示出截然不同的结果:我试图用 std::function 替换虚函数:

struct Base
{
    virtual void f() = 0;
};

struct Der1 : public Base
{
    virtual void f() override 
    {
        int i=0; 
        for(int j=0; j<100; ++j)
            i += 2*j; 
    }
};

struct Der2 : public Base
{
    virtual void f() override 
    {
        int i=0; 
        for(int j=0; j<100; ++j)
            i += 3*j; 
    }
};

struct Base_
{
    Base_(std::function<void()> f_) : f(f_) {}
    std::function<void()> f;
};

struct Der1_ : public Base_
{
    Der1_() : Base_([]{
                       int i=0; 
                       for(int j=0; j<100; ++j)
                           i += 2*j;
                      }){}
};

struct Der2_ : public Base_
{
    Der2_() : Base_([]{
                       int i=0; 
                       for(int j=0; j<100; ++j)
                           i += 3*j;
                      }){}
};


void process1(std::vector<Base_*>& v)
{
    for(auto &elem : v)
        elem->f();
}

void process2(std::vector<Base*>& v)
{
    for(auto &elem : v)
        elem->f();
}

int main()
{

    std::vector<Base_*> vec1;
    vec1.push_back(new Der1_);
    vec1.push_back(new Der2_);
    vec1.push_back(new Der1_);
    vec1.push_back(new Der2_);

    std::vector<Base*> vec2;
    vec2.push_back(new Der1);
    vec2.push_back(new Der2);
    vec2.push_back(new Der1);
    vec2.push_back(new Der2);
    std::chrono::time_point<std::chrono::system_clock> start1, end1, start2, end2;   
    float elapsed1 = 0; 
    float elapsed2 = 0;

    int N = 6000;
    //Variant 2
    start1 = std::chrono::system_clock::now();
    for(int i=0; i<N; ++i)
        process1(vec1);
    end1 = std::chrono::system_clock::now();
    elapsed1 = std::chrono::duration_cast<std::chrono::microseconds>(end1-start1).count();

    start2 = std::chrono::system_clock::now();
    for(int i=0; i<N; ++i)
        process2(vec2);
    end2 = std::chrono::system_clock::now();
    elapsed2 = std::chrono::duration_cast<std::chrono::microseconds>(end2-start2).count();

    std::cout<<"virtual: "<<elapsed2<<"\npointer: "<<elapsed1;

    for(int i=0; i<vec1.size(); ++i)
        delete vec1[i];

    for(int i=0; i<vec2.size(); ++i)
        delete vec2[i];

    return 0;
}

我想了解在 std::function 上替换虚函数是否能提高性能。第二种变体表示 2.5-3 增益,而第一种方法显示性能下降。

【问题讨论】:

  • 一种变体涉及 now() 被调用 200 次。
  • 我会选择第二个!
  • 第二个更有意义。

标签: c++ performance time chrono


【解决方案1】:

时间差异的最可能原因是分配给end 所花费的时间,这将为您的计数器增加额外的时间。第二种方法避免了这种情况,代价是计算循环中增加 i 所需的时间,这可能要少得多。

【讨论】:

  • 顺便说一句,调试和发布在 varinat 2 中显示相反的结果
【解决方案2】:

在您测量的第一个中:

N*(t_func+t_now)

在您测量的那一秒内:

N*t_func+t_now+t_loop_overhead

如果 t_func 很小并且 t_now 与之相当..

了解微基准测试

【讨论】:

    【解决方案3】:

    这真的取决于您测量的原因。第一个变体要好一些,只是 100 次迭代并没有那么多,当然这很大程度上取决于你的“功能”。但是不要认为每次调用都会花费相同的时间,今天处理器、管道和其他组件非常困难(而且很智能),所以如果你需要真正准确的值,最好找到一些现有的测量测试框架,或者你需要自己处理缓存、预测等。

    【讨论】:

      【解决方案4】:

      我最近用于计时 std::sortqsort 的代码(这里是 std::sort 的一个)

      #include <algorithm>
      #include <array>
      #include <chrono>
      #include <climits>
      #include <iostream>
      #include <random>
      
      using std::chrono::duration_cast; 
      using std::chrono::milliseconds; 
      using std::chrono::high_resolution_clock;
      
      std::default_random_engine generator; 
      std::uniform_int_distribution<int> distribution{INT_MIN, INT_MAX};
      
      constexpr auto size = 100000000; 
      std::array<int, size> data;
      
      int main() {
          auto start = high_resolution_clock::now();
      
          std::generate(std::begin(data), std::end(data), std::bind(distribution, generator));
          auto gen = high_resolution_clock::now();
      
          std::sort(std::begin(data), std::end(data));
          auto finish = high_resolution_clock::now();
          std::cout << 
              static_cast<double>(duration_cast<milliseconds>(finish - gen).count())/1000 <<
              "s for std::sort" << std::endl;
      }
      

      顺便说一句,std:sort 在我的电脑上几乎快 2 倍。

      【讨论】:

        猜你喜欢
        • 2011-08-04
        • 2013-02-21
        • 1970-01-01
        • 2017-01-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-03-21
        相关资源
        最近更新 更多