2

如何正确测量计算时间?

变体 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 增益,而第一个方法显示性能下降。

4

4 回答 4

1

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

于 2013-07-15T07:11:25.590 回答
1

在您测量的第一个中:

N*(t_func+t_now)

在您测量的第二秒内:

N*t_func+t_now+t_loop_overhead

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

阅读有关微基准测试的信息

于 2013-07-15T07:18:24.130 回答
0

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

于 2013-07-15T07:17:51.793 回答
0

我最近用于计时std::sortvs的代码qsort(这里是一个用于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 倍。

于 2013-07-15T07:41:04.423 回答