Systemzeit mit getrusage Funktion in C messen

Jinku Hu 12 Oktober 2023
  1. Verwenden Sie die Funktion getrusage, um die Systemzeit eines Single-Threaded-Programms zu messen
  2. Verwenden Sie die Funktion getrusage, um die Systemzeit eines Multithread-Programms zu messen
Systemzeit mit getrusage Funktion in C messen

Dieser Artikel zeigt verschiedene Methoden zur Messung der Systemzeit mit der Funktion getrusage in C.

Verwenden Sie die Funktion getrusage, um die Systemzeit eines Single-Threaded-Programms zu messen

Im Allgemeinen gibt es in jedem laufenden Programm zwei Zeitkomponenten. Die Systemzeit stellt den Zeitraum dar, den das Programm im Kernelmodus und in der Benutzerzeit ausführt, und gibt die im Benutzermodus verstrichene Ausführungszeit an. Die Summe beider Werte wird als Prozesszeit bezeichnet. Dies ist ein nützliches Maß für die Optimierung der Programmleistung.

Die Funktion getrusage ruft mehrere Datenpunkte über den Prozess ab, und einer davon ist die Systemzeit, die als Objekt struc timeval dargestellt wird. getrusage verwendet einen ganzzahligen Wert und eine Adresse des Objekts struct rusage als Argumente. Die Ganzzahl gibt an, welche Threads / Prozesse gemessen werden sollen, und kann die folgenden vordefinierten Makrowerte RUSAGE_SELF, RUSAGE_CHILDREN oder RUSAGE_THREAD haben.

Andererseits sollte die Struktur rusage im Voraus deklariert werden, und der erfolgreiche Funktionsaufruf speichert die entsprechenden Werte darin. Da die Struktur timeval zwei Datenelemente enthält - Sekunden und Mikrosekunden zur Darstellung der Zeit - haben wir die Funktionen diffUserTime und diffSystemTime implementiert, um die verstrichene Zeit in Sekunden zu berechnen.

#include <stdio.h>
#include <stdlib.h>
#include <sys/resource.h>
#include <unistd.h>

enum { NUM_ITERS = 1000000 };

void loopFunc1(size_t num) {
  int tmp = 0;
  for (int i = 0; i < num; ++i) {
    tmp += 1;
  }
}

void *loopFunc2(size_t num) {
  for (int i = 0; i < num; ++i) {
    getpid();
  }
  return NULL;
}

float diffUserTime(struct rusage *start, struct rusage *end) {
  return (end->ru_utime.tv_sec - start->ru_utime.tv_sec) +
         1e-6 * (end->ru_utime.tv_usec - start->ru_utime.tv_usec);
}

float diffSystemTime(struct rusage *start, struct rusage *end) {
  return (end->ru_stime.tv_sec - start->ru_stime.tv_sec) +
         1e-6 * (end->ru_stime.tv_usec - start->ru_stime.tv_usec);
}

int main() {
  struct rusage start, end;

  getrusage(RUSAGE_SELF, &start);
  loopFunc1(NUM_ITERS);
  getrusage(RUSAGE_SELF, &end);

  printf("loopFunc1 stats:\n");
  printf("  CPU time: %.06f sec user, %.06f sec system\n",
         diffUserTime(&start, &end), diffSystemTime(&start, &end));

  getrusage(RUSAGE_SELF, &start);
  loopFunc1(NUM_ITERS);
  getrusage(RUSAGE_SELF, &end);

  printf("loopFunc2 stats:\n");
  printf("  CPU time: %.06f sec user, %.06f sec system\n",
         diffUserTime(&start, &end), diffSystemTime(&start, &end));

  exit(EXIT_SUCCESS);
}

Ausgabe:

loopFunc1 stats:
  CPU time: 0.002193 sec user, 0.000000 sec system
loopFunc2 stats:
  CPU time: 0.002087 sec user, 0.000190 sec system

Verwenden Sie die Funktion getrusage, um die Systemzeit eines Multithread-Programms zu messen

Die Funktion getrusage kann auch die Systemzeit abrufen, die von allen Threads im aufrufenden Prozess verwendet wird. Das Argument RUSAGE_SELF gibt diese Funktion an und kann in einem Programm mit einem Thread gegenseitig verwendet werden, wie im vorherigen Beispiel gezeigt.

Im folgenden Beispielcode erstellen wir 16 Threads, die alle dieselbe Funktion loopFunc2 ausführen und beenden. Unabhängig davon entspricht die vom Aufruf getrusage abgerufene Zeit der verstrichenen Zeit, die in allen Threads summiert wurde, einschließlich derjenigen, die sie erstellt haben. Wenn der Benutzer nur die vom aufrufenden Thread verbrauchte Systemzeit messen möchte, kann als erstes Argument RUSAGE_THREAD übergeben werden. Beachten Sie jedoch, dass der Wert RUSAGE_THREAD Linux-spezifisch ist und _GNU_SOURCE vor den Header-Dateien definiert werden muss, um ihn einzuschließen.

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <sys/resource.h>
#include <threads.h>
#include <unistd.h>

enum { NUM_ITERS = 1000000, NUM_THREADS = 16 };

void *loopFunc2(size_t num) {
  for (int i = 0; i < num; ++i) {
    getpid();
  }
  return NULL;
}

float diffUserTime(struct rusage *start, struct rusage *end) {
  return (end->ru_utime.tv_sec - start->ru_utime.tv_sec) +
         1e-6 * (end->ru_utime.tv_usec - start->ru_utime.tv_usec);
}

float diffSystemTime(struct rusage *start, struct rusage *end) {
  return (end->ru_stime.tv_sec - start->ru_stime.tv_sec) +
         1e-6 * (end->ru_stime.tv_usec - start->ru_stime.tv_usec);
}

int main() {
  struct rusage start, end;
  thrd_t threads[NUM_THREADS];
  int rc;

  getrusage(RUSAGE_SELF, &start);
  for (int i = 0; i < NUM_THREADS; i++) {
    rc = thrd_create(&threads[i], (thrd_start_t)loopFunc2, (void *)NUM_ITERS);
    if (rc == thrd_error) {
      perror("[ERROR] thrd_create() call failed\n");
    }
  }
  loopFunc2(NUM_ITERS);

  getrusage(RUSAGE_SELF, &end);
  printf("loopFunc2 stats:\n");
  printf("  CPU time: %.06f sec user, %.06f sec system\n",
         diffUserTime(&start, &end), diffSystemTime(&start, &end));

  exit(EXIT_SUCCESS);
}

Ausgabe:

loopFunc2 stats:
  CPU time: 0.599556 sec user, 0.233000 sec system
Autor: Jinku Hu
Jinku Hu avatar Jinku Hu avatar

Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.

LinkedIn Facebook

Verwandter Artikel - C Time