Chcę się dowiedzieć, ile czasu zajmuje wykonanie określonej funkcji w moim programie w języku C ++ w systemie Linux . Następnie chcę dokonać porównania szybkości. Widziałem kilka funkcji czasu, ale skończyło się na tym z doładowania. Chrono:
process_user_cpu_clock, captures user-CPU time spent by the current process
Teraz nie jestem pewien, czy użyję powyższej funkcji, czy otrzymam jedyny czas, jaki procesor spędził na tej funkcji?
Po drugie, nie mogłem znaleźć żadnego przykładu użycia powyższej funkcji. Czy ktoś może mi pomóc, jak korzystać z powyższej funkcji?
PS: W tej chwili używam, std::chrono::system_clock::now()
aby uzyskać czas w sekundach, ale daje to inne wyniki ze względu na różne obciążenie procesora za każdym razem.
c++
optimization
profiling
Xara
źródło
źródło
clock_gettime
.. gcc definiuje inne zegary jako:typedef system_clock steady_clock; typedef system_clock high_resolution_clock;
w Windows użyjQueryPerformanceCounter
.Odpowiedzi:
Jest to bardzo łatwa w użyciu metoda w C ++ 11. Musisz użyć
std::chrono::high_resolution_clock
z<chrono>
nagłówka.Użyj go w ten sposób:
#include <iostream> #include <chrono> void function() { long long number = 0; for( long long i = 0; i != 2000000; ++i ) { number += 5; } } int main() { auto t1 = std::chrono::high_resolution_clock::now(); function(); auto t2 = std::chrono::high_resolution_clock::now(); auto duration = std::chrono::duration_cast<std::chrono::microseconds>( t2 - t1 ).count(); std::cout << duration; return 0; }
Będzie to mierzyć czas trwania funkcji.
UWAGA: Nie zawsze uzyskasz ten sam czas dla funkcji. Dzieje się tak, ponieważ procesor twojego komputera może być mniej lub bardziej używany przez inne procesy uruchomione na twoim komputerze, tak jak twój umysł może być bardziej lub mniej skoncentrowany podczas rozwiązywania zadań matematycznych. W ludzkim umyśle możemy zapamiętać rozwiązanie problemu matematycznego, ale dla komputera ten sam proces zawsze będzie czymś nowym; zatem, jak powiedziałem, nie zawsze uzyskasz ten sam wynik!
źródło
high_resolution_clock
Daje czas fizyczną i prawdziwe, że funkcja zaczyna biec. Tak więc w pierwszym uruchomieniu Twój procesor był używany mniej niż w następnym. Przez „używany” mam na myśli to, jakie inne aplikacje wykorzystują procesor.steady_clock
? Czy nie jest możliwe,high_resolution_clock
aby zegar był niemonotoniczny?Oto funkcja, która będzie mierzyć czas wykonania dowolnej funkcji przekazanej jako argument:
#include <chrono> #include <utility> typedef std::chrono::high_resolution_clock::time_point TimeVar; #define duration(a) std::chrono::duration_cast<std::chrono::nanoseconds>(a).count() #define timeNow() std::chrono::high_resolution_clock::now() template<typename F, typename... Args> double funcTime(F func, Args&&... args){ TimeVar t1=timeNow(); func(std::forward<Args>(args)...); return duration(timeNow()-t1); }
Przykładowe użycie:
#include <iostream> #include <algorithm> typedef std::string String; //first test function doing something int countCharInString(String s, char delim){ int count=0; String::size_type pos = s.find_first_of(delim); while ((pos = s.find_first_of(delim, pos)) != String::npos){ count++;pos++; } return count; } //second test function doing the same thing in different way int countWithAlgorithm(String s, char delim){ return std::count(s.begin(),s.end(),delim); } int main(){ std::cout<<"norm: "<<funcTime(countCharInString,"precision=10",'=')<<"\n"; std::cout<<"algo: "<<funcTime(countWithAlgorithm,"precision=10",'='); return 0; }
Wynik:
norm: 15555 algo: 2976
źródło
high_resolution_clock
może być aliasemsystem_clock
(zegar ścienny)steady_clock
lub trzecim niezależnym zegarem. Zobacz szczegóły tutaj . Dla zegara procesorastd::clock
może być używanyprosty program do znalezienia czasu wykonania funkcji.
#include <iostream> #include <ctime> // time_t #include <cstdio> void function() { for(long int i=0;i<1000000000;i++) { // do nothing } } int main() { time_t begin,end; // time_t is a datatype to store time values. time (&begin); // note time before execution function(); time (&end); // note time after execution double difference = difftime (end,begin); printf ("time taken for function() %.2lf seconds.\n", difference ); return 0; }
źródło
W książce Scotta Meyersa znalazłem przykład uniwersalnego generycznego wyrażenia lambda, którego można użyć do pomiaru czasu wykonywania funkcji. (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; };
Problem polega na tym, że mierzysz tylko jedno wykonanie, więc wyniki mogą być bardzo różne. Aby uzyskać wiarygodny wynik, należy zmierzyć dużą liczbę wykonań. Według wykładu Andrei Alexandrescu na konferencji code :: dive 2015 - Writing Fast Code I:
Zmierzony czas: tm = t + tq + tn + to
gdzie:
tm - zmierzony (obserwowany) czas
t - rzeczywisty czas zainteresowania
tq - czas dodany przez szum kwantyzacji
tn - czas dodawany przez różne źródła hałasu
to - czas narzutu (pomiar, pętla, wywołanie funkcji)
Zgodnie z tym, co powiedział w dalszej części wykładu, jako wynik należy przyjąć minimum tej dużej liczby egzekucji. Zachęcam do obejrzenia wykładu, w którym wyjaśnia dlaczego.
Jest też bardzo dobra biblioteka Google - https://github.com/google/benchmark . Ta biblioteka jest bardzo prosta w użyciu i potężna. Możesz sprawdzić niektóre wykłady Chandlera Carrutha na youtube, gdzie korzysta z tej biblioteki w praktyce. Na przykład CppCon 2017: Chandler Carruth „Going Nowhere Faster”;
Przykładowe użycie:
#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; }
EDYCJA: Oczywiście zawsze musisz pamiętać, że Twój kompilator może coś zoptymalizować lub nie. W takich przypadkach przydatne mogą być narzędzia takie jak perf.
źródło
Łatwy sposób na starsze C ++ lub C:
#include <time.h> // includes clock_t and CLOCKS_PER_SEC int main() { clock_t start, end; start = clock(); // ...code to measure... end = clock(); double duration_sec = double(end-start)/CLOCKS_PER_SEC; return 0; }
Dokładność pomiaru czasu w sekundach wynosi
1.0/CLOCKS_PER_SEC
źródło
Na przykład, aby znaleźć wszystkie liczby pierwsze od 1 do 100 milionów, zajmuje to około 1 minuty i 40 sekund. Więc czas wykonania jest drukowany jako:
Execution Time: 1 Minutes, 40 Seconds, 715 MicroSeconds, 715000 NanoSeconds
Kod jest tutaj:
#include <iostream> #include <chrono> using namespace std; using namespace std::chrono; typedef high_resolution_clock Clock; typedef Clock::time_point ClockTime; void findPrime(long n, string file); void printExecutionTime(ClockTime start_time, ClockTime end_time); int main() { long n = long(1E+8); // N = 100 million ClockTime start_time = Clock::now(); // Write all the prime numbers from 1 to N to the file "prime.txt" findPrime(n, "C:\\prime.txt"); ClockTime end_time = Clock::now(); printExecutionTime(start_time, end_time); } void printExecutionTime(ClockTime start_time, ClockTime end_time) { auto execution_time_ns = duration_cast<nanoseconds>(end_time - start_time).count(); auto execution_time_ms = duration_cast<microseconds>(end_time - start_time).count(); auto execution_time_sec = duration_cast<seconds>(end_time - start_time).count(); auto execution_time_min = duration_cast<minutes>(end_time - start_time).count(); auto execution_time_hour = duration_cast<hours>(end_time - start_time).count(); cout << "\nExecution Time: "; if(execution_time_hour > 0) cout << "" << execution_time_hour << " Hours, "; if(execution_time_min > 0) cout << "" << execution_time_min % 60 << " Minutes, "; if(execution_time_sec > 0) cout << "" << execution_time_sec % 60 << " Seconds, "; if(execution_time_ms > 0) cout << "" << execution_time_ms % long(1E+3) << " MicroSeconds, "; if(execution_time_ns > 0) cout << "" << execution_time_ns % long(1E+6) << " NanoSeconds, "; }
źródło
Jeśli chcesz zaoszczędzić czas i linie kodu, możesz zmierzyć czas wykonywania funkcji makrem jednowierszowym:
a) Zaimplementuj klasę pomiaru czasu, jak już zasugerowano powyżej (oto moja implementacja dla Androida):
class MeasureExecutionTime{ private: const std::chrono::steady_clock::time_point begin; const std::string caller; public: MeasureExecutionTime(const std::string& caller):caller(caller),begin(std::chrono::steady_clock::now()){} ~MeasureExecutionTime(){ const auto duration=std::chrono::steady_clock::now()-begin; LOGD("ExecutionTime")<<"For "<<caller<<" is "<<std::chrono::duration_cast<std::chrono::milliseconds>(duration).count()<<"ms"; } };
b) Dodaj dogodnym makro, które wykorzystuje aktualną nazwę funkcjonować jako TAG (za pomocą makra tutaj jest ważne, bo inaczej
__FUNCTION__
oceni abyMeasureExecutionTime
zamiast funkcji, którą wanto do środka#ifndef MEASURE_FUNCTION_EXECUTION_TIME #define MEASURE_FUNCTION_EXECUTION_TIME const MeasureExecutionTime measureExecutionTime(__FUNCTION__); #endif
c) Napisz makro na początku funkcji, którą chcesz zmierzyć. Przykład:
void DecodeMJPEGtoANativeWindowBuffer(uvc_frame_t* frame_mjpeg,const ANativeWindow_Buffer& nativeWindowBuffer){ MEASURE_FUNCTION_EXECUTION_TIME // Do some time-critical stuff }
Co da w wyniku następujący wynik:
ExecutionTime: For DecodeMJPEGtoANativeWindowBuffer is 54ms
Zauważ, że to (podobnie jak wszystkie inne sugerowane rozwiązania) będzie mierzyć czas między wywołaniem funkcji a zwróceniem, niekoniecznie czas wykonywania funkcji przez procesor. Jeśli jednak nie dasz programowi planującemu żadnej zmiany, aby zawiesić działający kod przez wywołanie funkcji sleep () lub podobnej, nie ma różnicy między.
źródło
Oto doskonały szablon klasy z samym nagłówkiem do pomiaru czasu, który upłynął od funkcji lub dowolnego bloku kodu:
#ifndef EXECUTION_TIMER_H #define EXECUTION_TIMER_H template<class Resolution = std::chrono::milliseconds> class ExecutionTimer { public: using Clock = std::conditional_t<std::chrono::high_resolution_clock::is_steady, std::chrono::high_resolution_clock, std::chrono::steady_clock>; private: const Clock::time_point mStart = Clock::now(); public: ExecutionTimer() = default; ~ExecutionTimer() { const auto end = Clock::now(); std::ostringstream strStream; strStream << "Destructor Elapsed: " << std::chrono::duration_cast<Resolution>( end - mStart ).count() << std::endl; std::cout << strStream.str() << std::endl; } inline void stop() { const auto end = Clock::now(); std::ostringstream strStream; strStream << "Stop Elapsed: " << std::chrono::duration_cast<Resolution>(end - mStart).count() << std::endl; std::cout << strStream.str() << std::endl; } }; // ExecutionTimer #endif // EXECUTION_TIMER_H
Oto kilka zastosowań:
int main() { { // empty scope to display ExecutionTimer's destructor's message // displayed in milliseconds ExecutionTimer<std::chrono::milliseconds> timer; // function or code block here timer.stop(); } { // same as above ExecutionTimer<std::chrono::microseconds> timer; // code block here... timer.stop(); } { // same as above ExecutionTimer<std::chrono::nanoseconds> timer; // code block here... timer.stop(); } { // same as above ExecutionTimer<std::chrono::seconds> timer; // code block here... timer.stop(); } return 0; }
Ponieważ klasa jest szablonem, możemy naprawdę łatwo określić sposób, w jaki chcemy mierzyć i wyświetlać nasz czas. Jest to bardzo poręczny szablon klasy użytkowej do wykonywania oznaczeń laboratoryjnych i jest bardzo łatwy w użyciu.
źródło
stop()
funkcja członkowska nie jest potrzebna, ponieważ destruktor zatrzymuje licznik czasu za Ciebie.test code
uruchomieniem licznika czasu. Następnie potest code
jawnym użyciu obiektu timera i wywołaniu jego metody stop. Musisz wywołać go ręcznie, kiedy chcesz, abystop
timer. Klasa nie przyjmuje żadnych parametrów. Ponadto, jeśli użyłeś tej klasy, tak jak pokazałem, zobaczysz, że jest minimalny upływ czasu między wywołaniemobj.stop
a jegodestructor
.<chrono>
?W
steady_clock
przeciwieństwie do tego, zalecam używanie tego, co jest gwarantowane, aby było monotonicznehigh_resolution_clock
.#include <iostream> #include <chrono> using namespace std; unsigned int stopwatch() { static auto start_time = chrono::steady_clock::now(); auto end_time = chrono::steady_clock::now(); auto delta = chrono::duration_cast<chrono::microseconds>(end_time - start_time); start_time = end_time; return delta.count(); } int main() { stopwatch(); //Start stopwatch std::cout << "Hello World!\n"; cout << stopwatch() << endl; //Time to execute last line for (int i=0; i<1000000; i++) string s = "ASDFAD"; cout << stopwatch() << endl; //Time to execute for loop }
Wynik:
Hello World! 62 163514
źródło
Możesz mieć prostą klasę, której można użyć do tego rodzaju pomiarów.
class duration_printer { public: duration_printer() : __start(std::chrono::high_resolution_clock::now()) {} ~duration_printer() { using namespace std::chrono; high_resolution_clock::time_point end = high_resolution_clock::now(); duration<double> dur = duration_cast<duration<double>>(end - __start); std::cout << dur.count() << " seconds" << std::endl; } private: std::chrono::high_resolution_clock::time_point __start; };
Jedyne, co musisz zrobić, to utworzyć obiekt w swojej funkcji na początku tej funkcji
void veryLongExecutingFunction() { duration_calculator dc; for(int i = 0; i < 100000; ++i) std::cout << "Hello world" << std::endl; } int main() { veryLongExecutingFunction(); return 0; }
i to wszystko. Klasę można modyfikować, aby odpowiadała Twoim wymaganiom.
źródło
Ponieważ żadna z udzielonych odpowiedzi nie jest bardzo dokładna ani nie daje powtarzalnych wyników, zdecydowałem się dodać link do mojego kodu, który ma precyzję poniżej nanosekund i statystyki naukowe.
Zauważ, że zadziała to tylko do pomiaru kodu, którego wykonanie zajmuje (bardzo) krótki czas (czyli kilka cykli zegara do kilku tysięcy): jeśli działają tak długo, że prawdopodobnie zostaną przerwane przez jakieś -heh- przerwanie , wtedy oczywiście nie jest możliwe podanie powtarzalnego i dokładnego wyniku; Konsekwencją tego jest to, że pomiar nigdy się nie kończy: a mianowicie kontynuuje pomiar, dopóki nie uzyska statystycznej 99,9% pewności, że ma prawidłową odpowiedź, co nigdy się nie zdarza na maszynie, na której działają inne procesy, gdy kod trwa zbyt długo.
https://github.com/CarloWood/cwds/blob/master/benchmark.h#L40
źródło