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 番目の方法は 2.5-3 のゲインを示し、最初の方法はパフォーマンスの低下を示します。

4

4 に答える 4

1

時間の違いの最も可能性の高い理由は、 への割り当てに費やされた時間endです。これにより、カウンターに余分な時間が追加されます。i2 番目の方法では、ループ内のインクリメントにかかる時間を大幅に短縮するという代償を払って、これを回避します。

于 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(これはの1つです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 に答える