En el libro de Scott Meyers encontré un ejemplo de expresión lambda genérica universal que se puede usar para medir el tiempo de ejecución de funciones. (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;
};
El problema es que solo mide una ejecución, por lo que los resultados pueden ser muy diferentes. Para obtener un resultado confiable, debe medir un gran número de ejecuciones. Según la conferencia de Andrei Alexandrescu en la conferencia code :: dive 2015 - Writing Fast Code I:
Tiempo medido: tm = t + tq + tn + to
dónde:
tm - tiempo medido (observado)
t - el tiempo real de interés
tq: tiempo agregado por el ruido de cuantización
tn - tiempo agregado por varias fuentes de ruido
a - tiempo de sobrecarga (medición, bucle, funciones de llamada)
De acuerdo con lo que dijo más adelante en la conferencia, debe tomar un mínimo de esta gran cantidad de ejecución como resultado. Os animo a mirar la conferencia en la que explica por qué.
También hay una muy buena biblioteca de google: https://github.com/google/benchmark . Esta biblioteca es muy simple de usar y poderosa. Puede consultar algunas conferencias de Chandler Carruth en YouTube donde está usando esta biblioteca en la práctica. Por ejemplo, CppCon 2017: Chandler Carruth "Going Nowhere Faster";
Ejemplo 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;
}
EDITAR: Por supuesto, siempre debe recordar que su compilador puede optimizar algo o no. Herramientas como perf pueden ser útiles en tales casos.
clock_gettime
.. gcc define otros relojes como:typedef system_clock steady_clock; typedef system_clock high_resolution_clock;
en Windows, useQueryPerformanceCounter
.