#define _GNU_SOURCE
#include <sys/syscall.h>
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <time.h>

void ts_subtract(struct timespec *result,
                 const struct timespec *time1, const struct timespec *time2) {
  *result = *time1;
  result->tv_sec -= time2->tv_sec ;
  if (result->tv_nsec < time2->tv_nsec) {
    /* borrow a second */
    result->tv_nsec += 1000000000L;
    result->tv_sec--;
  }
  result->tv_nsec -= time2->tv_nsec;
}

void usage(const char *cmd) {
    fprintf(stderr, "usage: %s <iterations>\n", cmd);
}

int main (int argc, char *argv[]) {
  struct timespec start_time, end_time, elapsed_time;
  uid_t uid;
  long iterations, i;
  double per_call;

  if (argc != 2) {
    usage(argv[0]);
    return 1;
  }

  iterations = atol(argv[1]);
  if (iterations < 0) {
    usage(argv[0]);
    return 1;
  }

  if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start_time)) {
    perror("clock_gettime");
    return errno;
  }

  for (i = iterations; i; i--)
    uid = syscall(SYS_getuid);

  if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end_time)) {
    perror("clock_gettime");
    return errno;
  }

  ts_subtract(&elapsed_time, &end_time, &start_time);
  per_call = (elapsed_time.tv_sec * 1000000000.0L + elapsed_time.tv_nsec) /
      (double)iterations;
  printf("%ld calls in %ld.%09ld s (%lf ns/call)\n", iterations,
         elapsed_time.tv_sec, elapsed_time.tv_nsec, per_call);

  return 0;
}