No livro de Scott Meyers, encontrei um exemplo de expressão lambda genérica universal que pode ser usada para medir o tempo de execução da função. (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;
};
O problema é que você mede apenas uma execução para que os resultados possam ser muito diferentes. Para obter um resultado confiável, você deve medir um grande número de execução. De acordo com a palestra de Andrei Alexandrescu na conferência code :: dive 2015 - Writing Fast Code I:
Tempo medido: tm = t + tq + tn + a
Onde:
tm - tempo medido (observado)
t - o tempo real de interesse
tq - tempo adicionado pelo ruído de quantização
tn - tempo adicionado por várias fontes de ruído
tempo de overhead (funções de medição, loop, chamada)
De acordo com o que ele disse mais adiante na palestra, você deve ter no mínimo esse grande número de execuções como resultado. Encorajo-vos a olhar para a palestra em que ele explica o porquê.
Também há uma biblioteca muito boa do google - https://github.com/google/benchmark . Esta biblioteca é muito simples de usar e poderosa. Você pode conferir algumas palestras de Chandler Carruth no youtube, onde ele está usando esta biblioteca na prática. Por exemplo, CppCon 2017: Chandler Carruth “Indo a lugar nenhum mais rápido”;
Exemplo de uso:
#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: Claro que você sempre precisa se lembrar de que seu compilador pode otimizar algo ou não. Ferramentas como perf podem ser úteis nesses casos.
clock_gettime
.. gcc define outros relógios como:typedef system_clock steady_clock; typedef system_clock high_resolution_clock;
no Windows, useQueryPerformanceCounter
.