Nel libro di Scott Meyers ho trovato un esempio di espressione lambda generica universale che può essere utilizzata per misurare il tempo di esecuzione della funzione. (C ++ 14)
auto timeFuncInvocation =
[](auto&& func, auto&&... params) {
// get time before function invocation
const auto& start = std::chrono::high_resolution_clock::now();
// function invocation using perfect forwarding
std::forward<decltype(func)>(func)(std::forward<decltype(params)>(params)...);
// get time after function invocation
const auto& stop = std::chrono::high_resolution_clock::now();
return stop - start;
};
Il problema è che si misura solo un'esecuzione, quindi i risultati possono essere molto diversi. Per ottenere un risultato affidabile è necessario misurare un numero elevato di esecuzioni. Secondo la conferenza di Andrei Alexandrescu alla conferenza code :: dive 2015 - Scrivere Fast Code I:
Tempo misurato: tm = t + tq + tn + a
dove:
tm - tempo misurato (osservato)
t - l'ora effettiva di interesse
tq - tempo aggiunto dal rumore di quantizzazione
tn - tempo aggiunto da varie fonti di rumore
a - tempo di overhead (misurazione, loop, funzioni di chiamata)
Secondo quanto ha detto più avanti nella lezione, dovresti prendere un minimo di questo gran numero di esecuzioni come risultato. Ti incoraggio a guardare la lezione in cui spiega perché.
Inoltre c'è un'ottima libreria di google - https://github.com/google/benchmark . Questa libreria è molto semplice da usare e potente. Puoi dare un'occhiata ad alcune lezioni di Chandler Carruth su YouTube dove sta usando questa libreria in pratica. Ad esempio CppCon 2017: Chandler Carruth “Going Nowhere Faster”;
Esempio di utilizzo:
#include <iostream>
#include <chrono>
#include <vector>
auto timeFuncInvocation =
[](auto&& func, auto&&... params) {
// get time before function invocation
const auto& start = high_resolution_clock::now();
// function invocation using perfect forwarding
for(auto i = 0; i < 100000/*largeNumber*/; ++i) {
std::forward<decltype(func)>(func)(std::forward<decltype(params)>(params)...);
}
// get time after function invocation
const auto& stop = high_resolution_clock::now();
return (stop - start)/100000/*largeNumber*/;
};
void f(std::vector<int>& vec) {
vec.push_back(1);
}
void f2(std::vector<int>& vec) {
vec.emplace_back(1);
}
int main()
{
std::vector<int> vec;
std::vector<int> vec2;
std::cout << timeFuncInvocation(f, vec).count() << std::endl;
std::cout << timeFuncInvocation(f2, vec2).count() << std::endl;
std::vector<int> vec3;
vec3.reserve(100000);
std::vector<int> vec4;
vec4.reserve(100000);
std::cout << timeFuncInvocation(f, vec3).count() << std::endl;
std::cout << timeFuncInvocation(f2, vec4).count() << std::endl;
return 0;
}
EDIT: ovviamente devi sempre ricordare che il tuo compilatore può ottimizzare qualcosa o no. Strumenti come perf possono essere utili in questi casi.
clock_gettime
.. gcc definisce altri orologi come:typedef system_clock steady_clock; typedef system_clock high_resolution_clock;
su Windows, usaQueryPerformanceCounter
.