Ns-точность монотонных часов в C на Linux и OS X

clock_gettime(CLOCK_MONOTONIC, ...) доступен в Linux, но не в OS X. Таймеры Mach доступны в OS X, но не в Linux.

Как я могу получить монотонные часы ns-точности в C, которые работают как на Linux, так и на OS X?

Ответ 1

/* 
This is based on the snippet current_utc_time.c from:
https://gist.github.com/jbenet/1087739

On OS X, compile with: gcc get_monotonic_time.c
   Linux, compile with: gcc get_monotonic_time.c -lrt
*/

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

#ifdef __MACH__
#include <mach/clock.h>
#include <mach/mach.h>
#endif

// Use clock_gettime in linux, clock_get_time in OS X.
void get_monotonic_time(struct timespec *ts){
#ifdef __MACH__
  clock_serv_t cclock;
  mach_timespec_t mts;
  host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock);
  clock_get_time(cclock, &mts);
  mach_port_deallocate(mach_task_self(), cclock);
  ts->tv_sec = mts.tv_sec;
  ts->tv_nsec = mts.tv_nsec;
#else
  clock_gettime(CLOCK_MONOTONIC, ts);
#endif
}

double get_elapsed_time(struct timespec *before, struct timespec *after){
  double deltat_s  = after->tv_sec - before->tv_sec;
  double deltat_ns = after->tv_nsec - before->tv_nsec;
  return deltat_s + deltat_ns*1e-9;
}

int main(){

  // Do something and time how long it takes.
  struct timespec before, after;
  get_monotonic_time(&before);
  double sum=0.;
  unsigned u;
  for(u=1; u<100000000; u++)
    sum += 1./u/u;
  get_monotonic_time(&after);
  printf("sum = %e\n", sum);
  printf("deltaT = %e s\n", get_elapsed_time(&before,&after));

}

Ответ 2

Я использовал ответ Дугласа (принятый ответ), его ссылки и другие примеры, плавающие по интернету (такие как этот вопрос).

Этот ответ должен включать мою версию кода, который эмулирует clock_gettime для CLOCK_REALTIME и CLOCK_MONOTONIC. Он также эмулирует функцию clock_nanosleep() для абсолютного монотонного времени. Код размещен на GitHub здесь.

Для его работы единственным дополнительным битом, необходимым в вашем коде, является

#ifdef __MACH__
timing_mach_init();
#endif

затем используйте clock_gettime() и clock_nanosleep_abstime(), как если бы вы использовали систему, которая на самом деле совместима с POSIX (с расширениями в реальном времени).