mi piace molto boost::cpu_timer::auto_cpu_timer
, e quando non posso usare spinta ho semplicemente incidere il mio proprio:
#include <cmath>
#include <string>
#include <chrono>
#include <iostream>
class AutoProfiler {
public:
AutoProfiler(std::string name)
: m_name(std::move(name)),
m_beg(std::chrono::high_resolution_clock::now()) { }
~AutoProfiler() {
auto end = std::chrono::high_resolution_clock::now();
auto dur = std::chrono::duration_cast<std::chrono::microseconds>(end - m_beg);
std::cout << m_name << " : " << dur.count() << " musec\n";
}
private:
std::string m_name;
std::chrono::time_point<std::chrono::high_resolution_clock> m_beg;
};
void foo(std::size_t N) {
long double x {1.234e5};
for(std::size_t k = 0; k < N; k++) {
x += std::sqrt(x);
}
}
int main() {
{
AutoProfiler p("N = 10");
foo(10);
}
{
AutoProfiler p("N = 1,000,000");
foo(1000000);
}
}
Questo timer funziona grazie a Raii. Quando si crea l'oggetto in un ambito, si memorizza il punto di tempo in quel momento. Quando si lascia l'ambito (ovvero, al corrispondente }
), il timer memorizza prima il punto di tempo, quindi calcola il numero di zecche (che è possibile convertire in una durata leggibile dall'uomo) e infine lo stampa sullo schermo.
Ovviamente, boost::timer::auto_cpu_timer
è molto più elaborato della mia semplice implementazione, ma spesso trovo la mia implementazione più che sufficiente per i miei scopi.
Esempio correre nel mio computer:
$ g++ -o example example.com -std=c++14 -Wall -Wextra
$ ./example
N = 10 : 0 musec
N = 1,000,000 : 10103 musec
EDIT
Mi è piaciuto molto l'attuazione suggerito da @ Jarod42. L'ho modificato un po 'per offrire una certa flessibilità sulle "unità" desiderate dell'output.
Per impostazione predefinita, restituisce il numero di microsecondi trascorsi (un numero intero, normalmente std::size_t
), ma è possibile richiedere che l'output sia in qualsiasi durata di propria scelta.
Penso che sia un approccio più flessibile rispetto a quello che ho suggerito in precedenza perché ora posso fare altre cose come prendere le misure e memorizzarle in un contenitore (come faccio nell'esempio).
Grazie a @ Jarod42 per l'ispirazione.
#include <cmath>
#include <string>
#include <chrono>
#include <algorithm>
#include <iostream>
template<typename Duration = std::chrono::microseconds,
typename F,
typename ... Args>
typename Duration::rep profile(F&& fun, Args&&... args) {
const auto beg = std::chrono::high_resolution_clock::now();
std::forward<F>(fun)(std::forward<Args>(args)...);
const auto end = std::chrono::high_resolution_clock::now();
return std::chrono::duration_cast<Duration>(end - beg).count();
}
void foo(std::size_t N) {
long double x {1.234e5};
for(std::size_t k = 0; k < N; k++) {
x += std::sqrt(x);
}
}
int main() {
std::size_t N { 1000000 };
// profile in default mode (microseconds)
std::cout << "foo(1E6) takes " << profile(foo, N) << " microseconds" << std::endl;
// profile in custom mode (e.g, milliseconds)
std::cout << "foo(1E6) takes " << profile<std::chrono::milliseconds>(foo, N) << " milliseconds" << std::endl;
// To create an average of `M` runs we can create a vector to hold
// `M` values of the type used by the clock representation, fill
// them with the samples, and take the average
std::size_t M {100};
std::vector<typename std::chrono::milliseconds::rep> samples(M);
for(auto & sample : samples) {
sample = profile(foo, N);
}
auto avg = std::accumulate(samples.begin(), samples.end(), 0)/static_cast<long double>(M);
std::cout << "average of " << M << " runs: " << avg << " microseconds" << std::endl;
}
uscita (compilato con g++ example.cpp -std=c++14 -Wall -Wextra -O3
):
foo(1E6) takes 10073 microseconds
foo(1E6) takes 10 milliseconds
average of 100 runs: 10068.6 microseconds
Non capisco davvero cosa mi stai chiedendo. E 'se è meglio usare un timer asincrono? –
Modificherò la mia domanda. –
Modifica appena eseguita. –