Łatwo mierz upływ czasu


297

Próbuję użyć time () do pomiaru różnych punktów mojego programu.

Nie rozumiem, dlaczego wartości przed i po są takie same? Rozumiem, że to nie jest najlepszy sposób na profilowanie mojego programu, chcę tylko zobaczyć, jak długo coś potrwa.

printf("**MyProgram::before time= %ld\n", time(NULL));

doSomthing();
doSomthingLong();

printf("**MyProgram::after time= %ld\n", time(NULL));

Próbowałem:

struct timeval diff, startTV, endTV;

gettimeofday(&startTV, NULL); 

doSomething();
doSomethingLong();

gettimeofday(&endTV, NULL); 

timersub(&endTV, &startTV, &diff);

printf("**time taken = %ld %ld\n", diff.tv_sec, diff.tv_usec);

Jak odczytać wynik **time taken = 0 26339? Czy to oznacza 26 339 nanosekund = 26,3 milisekundy?

A co **time taken = 4 45025to znaczy 4 sekundy i 25 ms?


10
Nie rozumiem pytania. Oczywiście wartości są różne. Czas mija między nimi, więc time()zwraca inną wartość.
Thomas

1
Co masz na myśli mówiąc „Nie rozumiem, dlaczego wartości przed i po są różne”? Bieżący czas otrzymujesz (w sekundach od 1 stycznia 1970 r.) Używając time(NULL)... drugiego wywołania będzie N sekund po pierwszym, a zatem ... innego (chyba że cokolwiek robisz, nie robi t zajmuje sekundę, aby ukończyć ... w takim przypadku będzie taki sam jak pierwszy).
Brian Roach

1
Czy możesz nam powiedzieć, co drukuje i jak długo to trwa, jeśli mierzysz czas stoperem lub zegarem ściennym (lub kalendarzem)?
Matt Curtis

4
Przepraszam, mam na myśli, że obie wartości są takie same. Błędnie wpisuję swoje pytanie.
hap497

Odpowiedzi:


335
//***C++11 Style:***
#include <chrono>

std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();

std::cout << "Time difference = " << std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count() << "[µs]" << std::endl;
std::cout << "Time difference = " << std::chrono::duration_cast<std::chrono::nanoseconds> (end - begin).count() << "[ns]" << std::endl;

10
tak, to powinna być odpowiedź
Ferenc Dajka

23
Aby to uruchomić, musisz dodać #include <chrono>dyrektywę, a ja zmieniłbym czas raportowania jako:std::cout << "Time difference (sec) = " << (std::chrono::duration_cast<std::chrono::microseconds>(end - begin).count()) /1000000.0 <<std::endl; (i nie zapomnieć o c ++ 11 flagę podczas kompilacji: -std=c++11)
Antonello

1
Nawiasem mówiąc, mierzy to czas procesora, a nie zegar ścienny. Dobrze?
Nikos

4
@ RestlessC0bra Według dokumentacji na temat preferencji: „Ten zegar nie jest związany z czasem naściennym (na przykład może to być czas od ostatniego uruchomienia) i jest najbardziej odpowiedni do mierzenia interwałów”.
cyl

1
Jaki to typ danych? Std :: chrono :: duration_cast <std :: chrono :: microseconds> (end - begin) .count ()
sqp_125

272
#include <ctime>

void f() {
  using namespace std;
  clock_t begin = clock();

  code_to_time();

  clock_t end = clock();
  double elapsed_secs = double(end - begin) / CLOCKS_PER_SEC;
}

time()Funkcja jest dokładna tylko w ciągu sekundy, ale istnieje CLOCKS_PER_SEC„zegary” w ciągu sekundy. Jest to łatwy, przenośny pomiar, nawet jeśli jest zbyt uproszczony.


129
Należy pamiętać, że clock()mierzy czas procesora, a nie upływ czasu rzeczywistego (który może być znacznie większy).
jlstrecker

12
Podczas programowania kodu równoległego dla klastrów ta metoda nie odzwierciedla czasu rzeczywistego ...
Nicholas Hamilton,

3
To wydaje się najłatwiejsze ze sposobów. Czy chciałbyś zaktualizować lub odnieść się do komentarza z @jlstrecker?
Lorah Attkins,

5
Rozwiązanie przedstawione powyżej nie jest dobrym rozwiązaniem z wielu powodów. To poprawna odpowiedź - stackoverflow.com/questions/2962785/…
Xofo

1
Wypróbowałem to rozwiązanie i, zgodnie z sugestiami, mój licznik czasu działał znacznie szybciej niż rzeczywisty czas na świecie.
RTbecard

267

Możesz wyodrębnić mechanizm pomiaru czasu i mierzyć czas działania każdej z wywołań przy minimalnym dodatkowym kodzie , po prostu przez wywołanie przez strukturę timera. Dodatkowo w czasie kompilacji można sparametryzować rodzaj taktowania (milisekundy, nanosekundy itp.).

Dzięki recenzji Lokiego Astari i sugestii zastosowania szablonów variadic. To dlatego przekazywane wywołanie funkcji.

#include <iostream>
#include <chrono>

template<typename TimeT = std::chrono::milliseconds>
struct measure
{
    template<typename F, typename ...Args>
    static typename TimeT::rep execution(F&& func, Args&&... args)
    {
        auto start = std::chrono::steady_clock::now();
        std::forward<decltype(func)>(func)(std::forward<Args>(args)...);
        auto duration = std::chrono::duration_cast< TimeT> 
                            (std::chrono::steady_clock::now() - start);
        return duration.count();
    }
};

int main() {
    std::cout << measure<>::execution(functor(dummy)) << std::endl;
}

Demo

Według komentarza Howarda Hinnanta najlepiej nie uciekać z systemu chronografu, dopóki nie będziemy musieli. Tak więc powyższa klasa może dać użytkownikowi wybór do countręcznego wywołania poprzez dostarczenie dodatkowej metody statycznej (pokazanej w C ++ 14)

template<typename F, typename ...Args>
static auto duration(F&& func, Args&&... args)
{
    auto start = std::chrono::steady_clock::now();
    std::forward<decltype(func)>(func)(std::forward<Args>(args)...);
    return std::chrono::duration_cast<TimeT>(std::chrono::steady_clock::now()-start);
} 

// call .count() manually later when needed (eg IO)
auto avg = (measure<>::duration(func) + measure<>::duration(func)) / 2.0;

i przydadzą się najbardziej tym klientom

„chcę przetworzyć kilka okresów przed wejściem / wyjściem (np. średnio)”


Pełny kod można znaleźć tutaj . Moja próba zbudowania narzędzia do analizy porównawczej opartej na chrono została tutaj odnotowana .


Jeśli C ++ 17 std::invoke jest dostępny, wywołanie wywoływanego w executionmożna wykonać w następujący sposób:

invoke(forward<decltype(func)>(func), forward<Args>(args)...);

aby zapewnić kallaby, które są wskaźnikami do funkcji składowych.


2
Miły; Mam w kodzie coś podobnego, ale używam innego interfejsu niż klasa: Mam klasę ( code_timer), która zajmuje czas rozpoczęcia ( std::chrono::system_clock::now();) w konstruktorze, metodę code_timer::ellapsedmierzącą różnicę między nowym now()wywołaniem a tym w konstruktorze oraz code_timer::resetmetodę, która resetuje czas rozpoczęcia do nowego now()wyniku. Aby zmierzyć wykonanie funktora w moim kodzie, używam darmowej funkcji poza klasą. Pozwala to na pomiar czasu od budowy obiektu do zakończenia wywołania asynchronicznego.
utnapistim

7
<nitpick>: Nie uciekaj z chronosystemu, dopóki nie będziesz musiał (unikaj używania .count()). Pozwól klientowi zadzwonić, .count()gdy zostaniesz do tego zmuszony (powiedz dla I / O, co w rzeczywistości jest niefortunne). Klient może chcieć przetworzyć kilka okresów czasu przed wejściem / wyjściem (np. Średnio) i najlepiej to zrobić w chronosystemie.
Howard Hinnant,

1
@ user3241228 1. VS2013 nie obsługuje typów automatycznego zwrotu (tylko końcowe typy zwrotów - jest to funkcja c ++ 14 jeszcze niedostępna). 2. Uważam, że to jest powód, ale poprosiłem aq, żeby się upewnić
Nikos Athanasiou

2
Dlaczego nie std::forward<F>(func)?
oliora

3
@oliora To to samo. wolęstd::forward<decltype(func)>(func) ponieważ może mieć zastosowanie do argumentów ogólnej lambdas ( auto&& func), w których Fnie ma tam składniowo, i łatwo jest ją wyodrębnić za pomocą makra narzędziowego, #define fw(arg) std::forward<decltype(arg)>(arg)które wykonuję w mojej bibliotece testów porównawczych (więc jest to pozostałość składniowa, na której nie rozwijam zbyt wiele odpowiedź)
Nikos Athanasiou

56

Jak widzę z twojego pytania, wygląda na to, że chcesz znać upływ czasu po wykonaniu jakiegoś fragmentu kodu. Myślę, że wygodnie byłoby zobaczyć wyniki w sekundach. Jeśli tak, spróbuj użyć difftime()funkcji pokazanej poniżej. Mam nadzieję, że to rozwiąże twój problem.

#include <time.h>
#include <stdio.h>

time_t start,end;
time (&start);
.
.
.
<your code>
.
.
.
time (&end);
double dif = difftime (end,start);
printf ("Elasped time is %.2lf seconds.", dif );

4
To zawsze daje mi całkowite sekundy. Czy to ma się zdarzyć?
azotan sodu

10
czas zawsze zwraca tylko sekundy, więc nie można go użyć do pomiarów poniżej sekundy.
DeepDeadpool,

31

Tylko Windows: (Tag Linux został dodany po opublikowaniu tej odpowiedzi)

Za pomocą GetTickCount () można uzyskać liczbę milisekund, które upłynęły od uruchomienia systemu.

long int before = GetTickCount();

// Perform time-consuming operation

long int after = GetTickCount();

7
Używam go na systemie Linux. Nie mogę więc użyć funkcji GetTickCount ().
hap497

1
już nieważne;) Dziękujemy za aktualizację tagu Twojego postu
RvdK

Działa i daje czas rzeczywisty, a nie czas procesora. Przetestowałem go poprzez umieszczenie SleepEx(5000,0)w miejsce // Wykonaj operację czasochłonne i różnicę afteri beforebył prawie 5 sek.
Ruchir

14

time(NULL)zwraca liczbę sekund, które upłynęły od 01.01.1970 o 00:00 ( Epoka ). Różnica między tymi dwiema wartościami to liczba sekund, które zajęło przetwarzanie.

int t0 = time(NULL);
doSomthing();
doSomthingLong();
int t1 = time(NULL);

printf ("time = %d secs\n", t1 - t0);

Możesz uzyskać lepsze wyniki getttimeofday(), które zwracają bieżący czas w sekundach, podobnie jak time()w mikrosekundach.


13

funkcja czasu (NULL) zwróci liczbę sekund, które upłynęły od 01.01.1970 o 00:00. A ponieważ ta funkcja jest wywoływana w innym czasie w twoim programie, zawsze będzie różna w C ++


Nie wiem, dlaczego ktoś przegłosował, ale twoja odpowiedź nie jest do końca poprawna. Na początek nie zwraca daty i nie zawsze będzie inaczej.
Matt Joiner

12
struct profiler
{
    std::string name;
    std::chrono::high_resolution_clock::time_point p;
    profiler(std::string const &n) :
        name(n), p(std::chrono::high_resolution_clock::now()) { }
    ~profiler()
    {
        using dura = std::chrono::duration<double>;
        auto d = std::chrono::high_resolution_clock::now() - p;
        std::cout << name << ": "
            << std::chrono::duration_cast<dura>(d).count()
            << std::endl;
    }
};

#define PROFILE_BLOCK(pbn) profiler _pfinstance(pbn)

Użycie jest poniżej:

{
    PROFILE_BLOCK("Some time");
    // your code or function
}

Jest to podobne do zakresu RAII

UWAGA, to nie jest moje, ale myślałem, że ma to znaczenie


1
obejmuje brak
Stepan Jakowenko

9
#include<time.h> // for clock
#include<math.h> // for fmod
#include<cstdlib> //for system
#include <stdio.h> //for delay

using namespace std;

int main()
{


   clock_t t1,t2;

   t1=clock(); // first time capture

   // Now your time spanning loop or code goes here
   // i am first trying to display time elapsed every time loop runs

   int ddays=0; // d prefix is just to say that this variable will be used for display
   int dhh=0;
   int dmm=0;
   int dss=0;

   int loopcount = 1000 ; // just for demo your loop will be different of course

   for(float count=1;count<loopcount;count++)
   {

     t2=clock(); // we get the time now

     float difference= (((float)t2)-((float)t1)); // gives the time elapsed since t1 in milliseconds

    // now get the time elapsed in seconds

    float seconds = difference/1000; // float value of seconds
    if (seconds<(60*60*24)) // a day is not over
    {
        dss = fmod(seconds,60); // the remainder is seconds to be displayed
        float minutes= seconds/60;  // the total minutes in float
        dmm= fmod(minutes,60);  // the remainder are minutes to be displayed
        float hours= minutes/60; // the total hours in float
        dhh= hours;  // the hours to be displayed
        ddays=0;
    }
    else // we have reached the counting of days
    {
        float days = seconds/(24*60*60);
        ddays = (int)(days);
        float minutes= seconds/60;  // the total minutes in float
        dmm= fmod(minutes,60);  // the rmainder are minutes to be displayed
        float hours= minutes/60; // the total hours in float
        dhh= fmod (hours,24);  // the hours to be displayed

    }

    cout<<"Count Is : "<<count<<"Time Elapsed : "<<ddays<<" Days "<<dhh<<" hrs "<<dmm<<" mins "<<dss<<" secs";


    // the actual working code here,I have just put a delay function
    delay(1000);
    system("cls");

 } // end for loop

}// end of main 

3
Doceniając twoją odpowiedź, wolimy preambułę zawierającą krótki opis kodu. Dzięki.
Kev

2
To nie jest czas, który upłynął, ale czas procesora.
JonnyJD

8

Wartości wydrukowane przez drugi program to sekundy i mikrosekundy.

0 26339 = 0.026'339 s =   26339 µs
4 45025 = 4.045'025 s = 4045025 µs

8
#include <ctime>
#include <cstdio>
#include <iostream>
#include <chrono>
#include <sys/time.h>
using namespace std;
using namespace std::chrono;

void f1()
{
  high_resolution_clock::time_point t1 = high_resolution_clock::now();
  high_resolution_clock::time_point t2 = high_resolution_clock::now();
  double dif = duration_cast<nanoseconds>( t2 - t1 ).count();
  printf ("Elasped time is %lf nanoseconds.\n", dif );
}

void f2()
{
  timespec ts1,ts2;
  clock_gettime(CLOCK_REALTIME, &ts1);
  clock_gettime(CLOCK_REALTIME, &ts2);
  double dif = double( ts2.tv_nsec - ts1.tv_nsec );
  printf ("Elasped time is %lf nanoseconds.\n", dif );
}

void f3()
{
  struct timeval t1,t0;
  gettimeofday(&t0, 0);
  gettimeofday(&t1, 0);
  double dif = double( (t1.tv_usec-t0.tv_usec)*1000);
  printf ("Elasped time is %lf nanoseconds.\n", dif );
}
void f4()
{
  high_resolution_clock::time_point t1 , t2;
  double diff = 0;
  t1 = high_resolution_clock::now() ;
  for(int i = 1; i <= 10 ; i++)
  {
    t2 = high_resolution_clock::now() ;
    diff+= duration_cast<nanoseconds>( t2 - t1 ).count();
    t1 = t2;
  }
  printf ("high_resolution_clock:: Elasped time is %lf nanoseconds.\n", diff/10 );
}

void f5()
{
  timespec ts1,ts2;
  double diff = 0;
  clock_gettime(CLOCK_REALTIME, &ts1);
  for(int i = 1; i <= 10 ; i++)
  {
    clock_gettime(CLOCK_REALTIME, &ts2);
    diff+= double( ts2.tv_nsec - ts1.tv_nsec );
    ts1 = ts2;
  }
  printf ("clock_gettime:: Elasped time is %lf nanoseconds.\n", diff/10 );
}

void f6()
{
  struct timeval t1,t2;
  double diff = 0;
  gettimeofday(&t1, 0);
  for(int i = 1; i <= 10 ; i++)
  {
    gettimeofday(&t2, 0);
    diff+= double( (t2.tv_usec-t1.tv_usec)*1000);
    t1 = t2;
  }
  printf ("gettimeofday:: Elasped time is %lf nanoseconds.\n", diff/10 );
}

int main()
{
  //  f1();
  //  f2();
  //  f3();
  f6();
  f4();
  f5();
  return 0;
}

4

C ++ std :: chrono ma wyraźną zaletę bycia wieloplatformowym. Jednak wprowadza również znaczny narzut w porównaniu do POSIX clock_gettime (). Na moim Linux-ie wszystkie std::chrono::xxx_clock::now()smaki działają mniej więcej tak samo:

std::chrono::system_clock::now()
std::chrono::steady_clock::now()
std::chrono::high_resolution_clock::now()

Chociaż POSIX clock_gettime(CLOCK_MONOTONIC, &time)powinien być taki sam jaksteady_clock::now() ale jest ponad x3 razy szybszy!

Oto mój test na kompletność.

#include <stdio.h>
#include <chrono>
#include <ctime>

void print_timediff(const char* prefix, const struct timespec& start, const 
struct timespec& end)
{
    double milliseconds = end.tv_nsec >= start.tv_nsec
                        ? (end.tv_nsec - start.tv_nsec) / 1e6 + (end.tv_sec - start.tv_sec) * 1e3
                        : (start.tv_nsec - end.tv_nsec) / 1e6 + (end.tv_sec - start.tv_sec - 1) * 1e3;
    printf("%s: %lf milliseconds\n", prefix, milliseconds);
}

int main()
{
    int i, n = 1000000;
    struct timespec start, end;

    // Test stopwatch
    clock_gettime(CLOCK_MONOTONIC, &start);
    for (i = 0; i < n; ++i) {
        struct timespec dummy;
        clock_gettime(CLOCK_MONOTONIC, &dummy);
    }
    clock_gettime(CLOCK_MONOTONIC, &end);
    print_timediff("clock_gettime", start, end);

    // Test chrono system_clock
    clock_gettime(CLOCK_MONOTONIC, &start);
    for (i = 0; i < n; ++i)
        auto dummy = std::chrono::system_clock::now();
    clock_gettime(CLOCK_MONOTONIC, &end);
    print_timediff("chrono::system_clock::now", start, end);

    // Test chrono steady_clock
    clock_gettime(CLOCK_MONOTONIC, &start);
    for (i = 0; i < n; ++i)
        auto dummy = std::chrono::steady_clock::now();
    clock_gettime(CLOCK_MONOTONIC, &end);
    print_timediff("chrono::steady_clock::now", start, end);

    // Test chrono high_resolution_clock
    clock_gettime(CLOCK_MONOTONIC, &start);
    for (i = 0; i < n; ++i)
        auto dummy = std::chrono::high_resolution_clock::now();
    clock_gettime(CLOCK_MONOTONIC, &end);
    print_timediff("chrono::high_resolution_clock::now", start, end);

    return 0;
}

Oto wynik, który otrzymuję po kompilacji z gcc7.2 -O3:

clock_gettime: 24.484926 milliseconds
chrono::system_clock::now: 85.142108 milliseconds
chrono::steady_clock::now: 87.295347 milliseconds
chrono::high_resolution_clock::now: 84.437838 milliseconds

3

time(NULL)Wywołanie funkcji zwróci liczbę sekund, które upłynęły od EPOC: 1 stycznia 1970. Może co masz na myśli zrobić, to wziąć różnicę między dwoma znacznikami:

size_t start = time(NULL);
doSomthing();
doSomthingLong();

printf ("**MyProgram::time elapsed= %lds\n", time(NULL) - start);

3

Jak już zauważyli inni, funkcja time () w standardowej bibliotece C nie ma rozdzielczości lepszej niż jedna sekunda. Jedyną w pełni przenośną funkcją C, która może zapewnić lepszą rozdzielczość, wydaje się być clock (), ale raczej mierzy czas procesora niż czas zegara ściennego. Jeśli ktoś chce ograniczyć się do platform POSIX (np. Linux), to funkcja clock_gettime () jest dobrym wyborem.

Od wersji C ++ 11 istnieją znacznie lepsze możliwości pomiaru czasu które oferują lepszą rozdzielczość w formie, która powinna być bardzo przenośna w różnych kompilatorach i systemach operacyjnych. Podobnie biblioteka boost :: datetime zapewnia dobre klasy czasowe wysokiej rozdzielczości, które powinny być wysoce przenośne.

Jednym z wyzwań przy korzystaniu z któregokolwiek z tych urządzeń jest opóźnienie czasowe wprowadzone przez zapytanie zegara systemowego. Od eksperymentowania z clock_gettime (), boost :: datetime i std :: chrono, to opóźnienie może być łatwo kwestią mikrosekund. Tak więc, mierząc czas trwania dowolnej części kodu, musisz pozwolić, aby wystąpił błąd pomiaru mniej więcej tego rozmiaru, lub spróbuj w jakiś sposób poprawić ten błąd zerowy. Najlepiej byłoby zebrać wiele pomiarów czasu zajętych przez funkcję i obliczyć średni lub maksymalny / minimalny czas potrzebny na wiele przebiegów.

Aby pomóc w rozwiązaniu wszystkich problemów związanych z przenośnością i gromadzeniem statystyk, opracowałem bibliotekę cxx-rtimers dostępną na Github, która stara się zapewnić prosty interfejs API dla bloków czasowych kodu C ++, obliczania zerowych błędów i raportowania statystyk z wielu osadzonych timerów w twoim kodzie. Jeśli masz kompilator C ++ 11, po prostu #include <rtimers/cxx11.hpp>i użyj czegoś takiego:

void expensiveFunction() {
    static rtimers::cxx11::DefaultTimer timer("expensiveFunc");
    auto scopedStartStop = timer.scopedStart();
    // Do something costly...
}

Po wyjściu z programu otrzymasz podsumowanie statystyk czasowych zapisanych do std :: cerr, takich jak:

Timer(expensiveFunc): <t> = 6.65289us, std = 3.91685us, 3.842us <= t <= 63.257us (n=731)

który pokazuje średni czas, jego odchylenie standardowe, górną i dolną granicę oraz liczbę wywołań tej funkcji.

Jeśli chcesz korzystać z funkcji czasowych specyficznych dla Linuksa, możesz #include <rtimers/posix.hpp>, lub jeśli masz biblioteki Boost, ale starszy kompilator C ++, możesz #include <rtimers/boost.hpp>. Istnieją również wersje tych klas timerów, które mogą gromadzić statystyczne informacje o taktowaniu z wielu wątków. Istnieją również metody, które pozwalają oszacować błąd zerowy związany z dwoma bezpośrednio kolejnymi zapytaniami zegara systemowego.


2

Funkcja ta wewnętrznie uzyskuje dostęp do zegara systemowego, dlatego zwraca inne wartości za każdym razem, gdy go wywołujesz. Ogólnie w przypadku języków niefunkcjonalnych w funkcjach może występować wiele efektów ubocznych i ukrytych funkcji, których nie można zobaczyć, patrząc tylko na nazwę funkcji i argumenty.


2

Z tego, co widać, tv_sec przechowuje sekundy, które upłynęły, a tv_usec przechowuje mikrosekundy, które upłynęły osobno. I nie są nawzajem konwersjami. Dlatego należy je zmienić na odpowiednią jednostkę i dodać, aby uzyskać całkowity czas, który upłynął.

struct timeval startTV, endTV;

gettimeofday(&startTV, NULL); 

doSomething();
doSomethingLong();

gettimeofday(&endTV, NULL); 

printf("**time taken in microseconds = %ld\n",
    (endTV.tv_sec * 1e6 + endTV.tv_usec - (startTV.tv_sec * 1e6 + startTV.tv_usec))
    );

2

W Linuksie clock_gettime () jest jednym z dobrych wyborów. Musisz połączyć bibliotekę czasu rzeczywistego (-lrt).

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>

#define BILLION  1000000000L;

int main( int argc, char **argv )
  {
    struct timespec start, stop;
    double accum;

    if( clock_gettime( CLOCK_REALTIME, &start) == -1 ) {
      perror( "clock gettime" );
      exit( EXIT_FAILURE );
    }

    system( argv[1] );

    if( clock_gettime( CLOCK_REALTIME, &stop) == -1 ) {
      perror( "clock gettime" );
      exit( EXIT_FAILURE );
    }

    accum = ( stop.tv_sec - start.tv_sec )
          + ( stop.tv_nsec - start.tv_nsec )
            / BILLION;
    printf( "%lf\n", accum );
    return( EXIT_SUCCESS );
  }

2

Musiałem zmierzyć czas wykonywania poszczególnych funkcji w bibliotece. Nie chciałem kończyć każdego wywołania każdej funkcji funkcją pomiaru czasu, ponieważ jest brzydka i pogłębia stos wywołań. Nie chciałem również umieszczać kodu czasowego na górze i na dole każdej funkcji, ponieważ robi to bałagan, gdy funkcja może wyjść wcześniej lub na przykład zgłasza wyjątki. Skończyło się na zrobieniu timera, który używa własnego czasu życia do mierzenia czasu.

W ten sposób mogę zmierzyć czas ściany bloku kodu, po prostu tworząc instancję jednego z tych obiektów na początku danego bloku kodu (naprawdę funkcja lub dowolny zakres), a następnie pozwalając destruktorowi instancji na pomiar czasu, który upłynął od konstrukcja, gdy instancja wykracza poza zakres. Możesz znaleźć pełny przykład tutaj, ale struktura jest niezwykle prosta:

template <typename clock_t = std::chrono::steady_clock>
struct scoped_timer {
  using duration_t = typename clock_t::duration;
  const std::function<void(const duration_t&)> callback;
  const std::chrono::time_point<clock_t> start;

  scoped_timer(const std::function<void(const duration_t&)>& finished_callback) :
      callback(finished_callback), start(clock_t::now()) { }
  scoped_timer(std::function<void(const duration_t&)>&& finished_callback) :
      callback(finished_callback), start(clock_t::now()) { }
  ~scoped_timer() { callback(clock_t::now() - start); }
};

Struktura oddzwoni na dostarczony funktor, gdy wyjdzie poza zakres, abyś mógł zrobić coś z informacjami o taktowaniu (wydrukować lub zapisać lub cokolwiek innego). Jeśli trzeba zrobić coś jeszcze bardziej skomplikowane można nawet korzystać std::bindz std::placeholdersdo callback funkcje z większą liczbą argumentów.

Oto szybki przykład użycia:

void test(bool should_throw) {
  scoped_timer<> t([](const scoped_timer<>::duration_t& elapsed) {
    auto e = std::chrono::duration_cast<std::chrono::duration<double, std::milli>>(elapsed).count();
    std::cout << "took " << e << "ms" << std::endl;
  });

  std::this_thread::sleep_for(std::chrono::seconds(1));

  if (should_throw)
    throw nullptr;

  std::this_thread::sleep_for(std::chrono::seconds(1));
}

Jeśli chcesz być bardziej rozmyślny, możesz również użyć newi deletejawnie uruchomić i zatrzymać stoper bez polegania na określaniu zakresu, aby zrobić to za Ciebie.


1

Są one takie same, ponieważ funkcja doSomething zachodzi szybciej niż ziarnistość timera. Próbować:

printf ("**MyProgram::before time= %ld\n", time(NULL));

for(i = 0; i < 1000; ++i) {
    doSomthing();
    doSomthingLong();
}

printf ("**MyProgram::after time= %ld\n", time(NULL));

1

Obie wartości są takie same, ponieważ twoja długa procedura nie trwa tak długo - krócej niż sekundę. Możesz spróbować po prostu dodać długą pętlę (dla (int i = 0; i <100000000; i ++);) na końcu funkcji, aby upewnić się, że to jest problem, a następnie możemy przejść od tego ...

Jeśli powyższe okaże się prawdą, musisz znaleźć inną funkcję systemową (rozumiem, że pracujesz na Linuksie, więc nie mogę ci pomóc z nazwą funkcji), aby dokładniej zmierzyć czas. Jestem pewien, że w Linuksie jest funkcja podobna do GetTickCount (), wystarczy ją znaleźć.


1

Zwykle używam następujących:

#include <chrono>
#include <type_traits>

using perf_clock = std::conditional<
    std::chrono::high_resolution_clock::is_steady,
    std::chrono::high_resolution_clock,
    std::chrono::steady_clock
>::type;

using floating_seconds = std::chrono::duration<double>;

template<class F, class... Args>
floating_seconds run_test(Func&& func, Args&&... args)
{
   const auto t0 = perf_clock::now();
   std::forward<Func>(func)(std::forward<Args>(args)...);
   return floating_seconds(perf_clock::now() - t0);
} 

Jest to to samo, co proponowane przez @ nikos-athanasiou, z tym wyjątkiem, że unikam używania niestałego zegara i używam zmiennej liczby sekund jako czasu trwania.


1
Na tym przełączniku typów : zazwyczaj high_resolution_clockjest typedef dla jednego system_clocklub dwóch steady_clock. Aby prześledzić, że std::conditionaljeśli is_steadyczęść jest prawdziwa, to wybierz to, high_resolution_clockco jest (typedef do) steady_clock. Jeśli to fałsz, wybierz steady_clockponownie. Po prostu użyj steady_clockod początku ...
Nikos Athanasiou

@ nikos-athanasiou Całkowicie zgadzam się z komentarzem 5gon12eder, że „typowy” przypadek nie jest wymagany przez standard, więc niektóre STL mogą być implementowane w inny sposób. Wolę, aby mój kod był bardziej ogólny i nie był związany ze szczegółami implementacji.
oliora

To nie jest wymagane, ale wyraźnie zaznaczono w 20.12.7.3 : high_resolution_clock may be a synonym for system_clock or steady_clock. Powód jest następujący: high_resolution_clockreprezentuje zegary z najkrótszym okresem tykania, więc niezależnie od implementacji, ma dwie możliwości, jest stabilny lub nie. Jakikolwiek wybór dokonamy, powiedzenie, że implementacja będzie się różnić od pozostałych dwóch zegarów, jest jak powiedzenie, że mamy lepszą implementację dla stałego (lub nie) zegara, którego zdecydujemy się nie używać (dla stałych lub nie). Wiedząc, jak dobrze, wiedząc, dlaczego lepiej
Nikos Athanasiou

@ nikos-athanasiou Wolałbym być w 100% bezpieczny, szczególnie gdy nie kosztowałoby mnie to narzutu czasu wykonywania i niewykrywalnego narzutu czasu kompilacji. Jeśli chcesz, możesz polegać na „may” i assamptions.
oliora

au contraire mój przyjacielu, to ty polegasz na „może”, ale pasuje do siebie. Jeśli chcesz być w 100% pewien i nadal to pisać, powinieneś również znaleźć sposób dla siebie i użytkowników swojego kodu, aby uniknąć nieprzenoszalnego mieszania punktów czasowych różnych zegarów (jeśli ten typ przełącznika nabiera znaczenia, będzie zachowywać się inaczej na różnych platformach). Baw się dobrze!
Nikos Athanasiou

0

W odpowiedzi na trzy szczegółowe pytania OP .

„Nie rozumiem, dlaczego wartości przed i po są takie same?

Pierwsze pytanie i próbki kodu pokazuje, że time()ma rozdzielczość 1 sekundę, więc odpowiedź musi być tak, że dwie funkcje wykonywane w mniej niż 1 sekundę. Ale od czasu do czasu poinformuje (najwyraźniej nielogicznie) o 1 sekundzie, jeśli dwa znaki timera przekraczają jedną sekundę.

W następnym przykładzie użyto gettimeofday()wypełnienia tej struktury

struct timeval {
    time_t      tv_sec;     /* seconds */
    suseconds_t tv_usec;    /* microseconds */
};

a drugie pytanie brzmi : „Jak odczytać wynik **time taken = 0 26339? Czy to oznacza 26 339 nanosekund = 26,3 ms?”

Moja druga odpowiedź to czas zajęty to 0 sekund i 26339 mikrosekund, czyli 0,026339 sekund, co dowodzi, że pierwszy przykład działa w czasie krótszym niż 1 sekunda.

Trzecie pytanie pyta: „A co **time taken = 4 45025, to znaczy, 4 sekundy i 25 ms?”

Moja trzecia odpowiedź to 4 sekundy i 45025 mikrosekund, czyli 4,045025 sekund, co pokazuje, że OP zmienił zadania wykonywane przez dwie funkcje, które wcześniej mierzył.


0
#include <ctime>
#include <functional>

using namespace std;

void f() {
  clock_t begin = clock();

  // ...code to measure time...

  clock_t end = clock();

  function<double(double, double)> convtime = [](clock_t begin, clock_t end)
  {
     return double(end - begin) / CLOCKS_PER_SEC;
  };

  printf("Elapsed time: %.2g sec\n", convtime(begin, end));

}

Podobny przykład do tego tutaj dostępnego, tylko z dodatkową funkcją konwersji + wydruku.


0

Utworzyłem klasę do automatycznego pomiaru upływu czasu. Sprawdź kod (c ++ 11) w tym linku: https://github.com/sonnt174/Common/blob/master/time_measure.h

Przykład użycia klasy TimeMeasure:

void test_time_measure(std::vector<int> arr) {
  TimeMeasure<chrono::microseconds> time_mea;  // create time measure obj
  std::sort(begin(arr), end(arr));
}

Podoba mi się twoje wyciągi z jednostkami. Co zajęłoby przeniesienie kodu do gcc i clang? ( wandbox.org )
Howard Hinnant

1
@HowardHinnant: dzięki za adres, zaktualizowałem również kod dla gcc i clang.
Sirn Nguyen Truong

0

Matlab przyprawiony!

ticuruchamia stoper w celu pomiaru wydajności. Funkcja rejestruje czas wewnętrzny przy wykonywaniu polecenia tic. Wyświetlaj upływający czas za pomocą tocfunkcji.

#include <iostream>
#include <ctime>
#include <thread>
using namespace std;

clock_t START_TIMER;

clock_t tic()
{
    return START_TIMER = clock();
}

void toc(clock_t start = START_TIMER)
{
    cout
        << "Elapsed time: "
        << (clock() - start) / (double)CLOCKS_PER_SEC << "s"
        << endl;
}

int main()
{
    tic();
    this_thread::sleep_for(2s);
    toc();

    return 0;
}

-4

Możesz użyć biblioteki SFML , która jest prostą i szybką biblioteką multimedialną. Zawiera wiele użytecznych i dobrze zdefiniowanych klas, takich jak Zegar, Gniazdo, Dźwięk, Grafika itp. Jest tak łatwy w użyciu i wysoce zalecany.

To jest przykład tego pytania.

sf::Clock clock;
...
Time time1 = clock.getElapsedTime();
...
Time time2 = clock.restart();
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.