2013-07-15 4 views
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(); 

Эти варианты показывают очень разные результаты: я пытался заменить виртуальные функции с станд :: функции:

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, тогда как первый метод показывает снижение производительности.

+2

Один вариант включает 'now()', называемый 200 раз. – chris

+0

Я бы пошел со вторым! – Nawaz

+0

Второй способ дает больше смысла. – Rapptz

ответ

1

Наиболее вероятной причиной вашей разницы во времени является время, потраченное на выполнение задания end, что добавит дополнительное время на ваши счетчики. Второй способ позволяет избежать этого за счет подсчета времени, необходимого для увеличения i в цикле, что, вероятно, значительно меньше.

+0

Кстати, отладка и релиз показывают противоположные результаты в varinat 2 – gorill

0

Это действительно зависит от того, почему вы измеряете. Первый вариант немного лучше, всего 100 итераций - это не так много, и, конечно же, это очень зависит от вашего «func». Но не думайте, что каждый звонок будет занимать столько же времени, сегодня процессоры, трубы и другие компоненты очень сложны (и умны), поэтому, если вам нужна действительно точная ценность, вероятно, лучше найти какую-то существующую структуру тестирования или вам понадобится для работы с кешированием, прогнозированием и т. д. самостоятельно.

1

в первом измерении:

N*(t_func+t_now) 

во втором измерении:

N*t_func+t_now+t_loop_overhead 

если t_func мала и t_now сравнима с ..

читать о микро бенчмаркинг

0

Код, который я недавно использовал для определения времени std::sort vs 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 раза быстрее, на моем компьютере.