Ich mag boost::cpu_timer::auto_cpu_timer
wirklich, und wenn ich nicht boost kann ich einfach meine eigene Hack:
#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);
}
}
Dieser Timer arbeitet dank RAII. Wenn Sie das Objekt innerhalb eines Bereichs erstellen, speichern Sie den Zeitpunkt zu diesem Zeitpunkt. Wenn Sie den Bereich verlassen (also den entsprechenden Wert }
), speichert der Timer zuerst den Zeitpunkt, berechnet dann die Anzahl der Ticks (die Sie in eine für Menschen lesbare Dauer konvertieren können) und druckt sie schließlich auf dem Bildschirm aus.
Natürlich ist boost::timer::auto_cpu_timer
viel aufwendiger als meine einfache Implementierung, aber ich finde oft meine Implementierung mehr als ausreichend für meine Zwecke.
Beispiel in meinem Computer laufen:
$ g++ -o example example.com -std=c++14 -Wall -Wextra
$ ./example
N = 10 : 0 musec
N = 1,000,000 : 10103 musec
EDIT
Ich mochte die von @ Jarod42 vorgeschlagen Umsetzung. Ich habe es ein wenig modifiziert, um eine gewisse Flexibilität bei den gewünschten "Einheiten" der Ausgabe zu bieten.
Standardmäßig wird die Anzahl der verstrichenen Mikrosekunden (eine Ganzzahl, normalerweise std::size_t
) zurückgegeben. Sie können jedoch die Ausgabe in einer beliebigen Dauer anfordern.
Ich denke, es ist ein flexibler Ansatz als der, den ich früher vorgeschlagen habe, weil ich jetzt andere Sachen machen kann, wie die Messungen zu machen und sie in einem Container zu lagern (wie im Beispiel).
Dank @ Jarod42 für die Inspiration.
#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;
}
Output (kompiliert mit 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
Ich verstehe nicht wirklich, wonach Sie fragen. Ist es besser, einen asynchronen Timer zu verwenden? –
Ich werde meine Frage bearbeiten. –
Edit gerade getan. –