Beste Timing-Methode in C?

80

Was ist der beste Weg, um einen Codeabschnitt mit hoher Auflösung und Portabilität zeitlich festzulegen?

/* Time from here */
ProcessIntenseFunction();
/* to here. */

printf("Time taken %d seconds %d milliseconds", sec, msec);

Gibt es eine Standardbibliothek mit einer plattformübergreifenden Lösung?

lillq
quelle

Antworten:

137

Ich denke das sollte funktionieren:

#include <time.h>

clock_t start = clock(), diff;
ProcessIntenseFunction();
diff = clock() - start;

int msec = diff * 1000 / CLOCKS_PER_SEC;
printf("Time taken %d seconds %d milliseconds", msec/1000, msec%1000);
Sophie Alpert
quelle
10
Dies ist eigentlich gut, da Sie eher CPU-Zeit als verstrichene Zeit erhalten (verstrichene Zeit kann durch andere Prozesse beeinflusst werden). Denken Sie daran, dass eine Zahl von 10 Sekunden nicht unbedingt bedeutet, dass sie in 10 Sekunden ausgeführt wird, da möglicherweise E / A-Überlegungen vorliegen. Dies misst NUR die CPU .
Paxdiablo
1
Ich habe dies hunderte Male benutzt und ist die beste / einfachste Lösung für diese Frage
Gerhard
4
Sie können dies alles sogar in ein Makro einfügen, wenn Sie häufig mehrere Dinge planen: #define timing (a) start = clock (); ein; diff = clock () - start; ms = diff * 1000 / CLOCKS_PER_SEC; printf ("ms:% d \ n", ms); und dann aufrufen: Timing (IntenseFunc1 ())
eqzx
3
clock_t ist normalerweise lang und CLOCKS_PER_SEC ist 1000000. In diesem Fall führt eine Differenz von mehr als 4 Sekunden zu einem Überlauf und seltsamen Ergebnissen
Begelfor
2
@paxdiablo Ich erhalte damit völlig gleichwertige Ergebnisse wie mit gettimeofday (), nicht sicher, was Sie hier sagen.
user3467349
21

gettimeofday () wird wahrscheinlich tun, was Sie wollen.

Wenn Sie mit Intel-Hardware arbeiten, lesen Sie hier den Echtzeit-Befehlszähler der CPU. Hier erfahren Sie, wie viele CPU-Zyklen seit dem Start des Prozessors ausgeführt wurden. Dies ist wahrscheinlich der feinkörnigste und niedrigste Overhead-Zähler, den Sie für die Leistungsmessung erhalten können.

Beachten Sie, dass dies die Anzahl der CPU-Zyklen ist. Unter Linux können Sie die CPU-Geschwindigkeit von / proc / cpuinfo abrufen und teilen, um die Anzahl der Sekunden zu ermitteln. Dies in ein Doppel umzuwandeln ist sehr praktisch.

Wenn ich das auf meiner Box laufen lasse, bekomme ich

11867927879484732
11867927879692217
Es dauerte so lange, bis printf: 207485 aufgerufen wurde

Hier ist das Intel-Entwicklerhandbuch, das jede Menge Details enthält.

#include <stdio.h>
#include <stdint.h>

inline uint64_t rdtsc() {
    uint32_t lo, hi;
    __asm__ __volatile__ (
      "xorl %%eax, %%eax\n"
      "cpuid\n"
      "rdtsc\n"
      : "=a" (lo), "=d" (hi)
      :
      : "%ebx", "%ecx");
    return (uint64_t)hi << 32 | lo;
}

main()
{
    unsigned long long x;
    unsigned long long y;
    x = rdtsc();
    printf("%lld\n",x);
    y = rdtsc();
    printf("%lld\n",y);
    printf("it took this long to call printf: %lld\n",y-x);
}
Mark Harrison
quelle
5

gettimeofday gibt die auf Mikrosekunden genaue Zeit innerhalb der Auflösung der Systemuhr zurück. Vielleicht möchten Sie auch das Projekt High Res Timers auf SourceForge ausprobieren.

Tvanfosson
quelle
1

Wenn Sie keine CPU-Zeit möchten, suchen Sie meiner Meinung nach nach der Zeitstruktur.

Ich benutze das Folgende zur Berechnung der Ausführungszeit:

int timeval_subtract(struct timeval *result,                                                                                                                                        
                     struct timeval end,                                                                                                                                                 
                     struct timeval start)                                                                                                                                               
{                                                                                                                                                                                   
        if (start.tv_usec < end.tv_usec) {                                                                                                                                          
                int nsec = (end.tv_usec - start.tv_usec) / 1000000 + 1;                                                                                                             
                end.tv_usec -= 1000000 * nsec;                                                                                                                                      
                end.tv_sec += nsec;                                                                                                                                                 
        }                                                                                                                                                                           
        if (start.tv_usec - end.tv_usec > 1000000) {                                                                                                                                
                int nsec = (end.tv_usec - start.tv_usec) / 1000000;                                                                                                                 
                end.tv_usec += 1000000 * nsec;                                                                                                                                      
                end.tv_sec -= nsec;                                                                                                                                                 
        }                                                                                                                                                                           

        result->tv_sec = end.tv_sec - start.tv_sec;                                                                                                                                 
        result->tv_usec = end.tv_usec - start.tv_usec;                                                                                                                              

        return end.tv_sec < start.tv_sec;                                                                                                                                           
}                                                                                                                                                                                   

void set_exec_time(int end)                                                                                                                                                         
{                                                                                                                                                                                   
        static struct timeval time_start;                                                                                                                                           
        struct timeval time_end;                                                                                                                                                    
        struct timeval time_diff;                                                                                                                                                   

        if (end) {                                                                                                                                                                  
                gettimeofday(&time_end, NULL);                                                                                                                                      
                if (timeval_subtract(&time_diff, time_end, time_start) == 0) {                                                                                                      
                        if (end == 1)                                                                                                                                               
                                printf("\nexec time: %1.2fs\n",                                                                                                                     
                                        time_diff.tv_sec + (time_diff.tv_usec / 1000000.0f));                                                                                       
                        else if (end == 2)                                                                                                                                          
                                printf("%1.2fs",                                                                                                                                    
                                        time_diff.tv_sec + (time_diff.tv_usec / 1000000.0f));                                                                                       
                }                                                                                                                                                                   
                return;                                                                                                                                                             
        }                                                                                                                                                                           
        gettimeofday(&time_start, NULL);                                                                                                                                            
}                                                                                                                                                                                   

void start_exec_timer()                                                                                                                                                             
{                                                                                                                                                                                   
        set_exec_time(0);                                                                                                                                                           
}                                                                                                                                                                                   

void print_exec_timer()                                                                                                                                                             
{                                                                                                                                                                                   
        set_exec_time(1);                                                                                                                                                           
}
HDevejian
quelle
0

Hohe Auflösung ist relativ ... Ich habe mir die Beispiele angesehen und sie sind meistens für Millisekunden geeignet. Für mich ist es jedoch wichtig, Mikrosekunden zu messen. Ich habe keine plattformunabhängige Lösung für Mikrosekunden gesehen und dachte, dass so etwas wie der folgende Code nützlich sein wird. Ich war vorerst nur für Windows geplant und werde höchstwahrscheinlich eine Implementierung von gettimeofday () hinzufügen, wenn ich dasselbe unter AIX / Linux mache.

    #ifdef WIN32
      #ifndef PERFTIME
        #include <windows.h>
        #include <winbase.h>
        #define PERFTIME_INIT unsigned __int64 freq;  QueryPerformanceFrequency((LARGE_INTEGER*)&freq); double timerFrequency = (1.0/freq);  unsigned __int64 startTime;  unsigned __int64 endTime;  double timeDifferenceInMilliseconds;
        #define PERFTIME_START QueryPerformanceCounter((LARGE_INTEGER *)&startTime);
        #define PERFTIME_END QueryPerformanceCounter((LARGE_INTEGER *)&endTime); timeDifferenceInMilliseconds = ((endTime-startTime) * timerFrequency);  printf("Timing %fms\n",timeDifferenceInMilliseconds);
    #define PERFTIME(funct) {unsigned __int64 freq;  QueryPerformanceFrequency((LARGE_INTEGER*)&freq);  double timerFrequency = (1.0/freq);  unsigned __int64 startTime;  QueryPerformanceCounter((LARGE_INTEGER *)&startTime);  unsigned __int64 endTime;  funct; QueryPerformanceCounter((LARGE_INTEGER *)&endTime);  double timeDifferenceInMilliseconds = ((endTime-startTime) * timerFrequency);  printf("Timing %fms\n",timeDifferenceInMilliseconds);}
      #endif
    #else
      //AIX/Linux gettimeofday() implementation here
    #endif

Verwendung:

PERFTIME(ProcessIntenseFunction());

or

PERFTIME_INIT
PERFTIME_START
ProcessIntenseFunction()
PERFTIME_END
Rohan
quelle