text: //
  // Created by SNAKE on 9/21/19.
  //
  
  #ifndef SYSBENCH_SB_TIMER_H
  #define SYSBENCH_SB_TIMER_H
  
  # include <sys/time.h>
  # include <time.h>
  
  #include <stdint.h>
  #include <stdbool.h>
  
  #include <barrelfish_kpi/spinlocks_arch.h>
  
  #include "sb_util.h"
  #include "sysbench.h"
  #include <stdio.h>
  
  #define NS_PER_SEC 1000000000
  #define MS_PER_SEC 1000
  #define NS_PER_MS (NS_PER_SEC / MS_PER_SEC)
  
  /* Convert nanoseconds to seconds and vice versa */
  #define NS2SEC(nsec) ((nsec) / (double) NS_PER_SEC)
  #define SEC2NS(sec)  ((uint64_t) (sec) * NS_PER_SEC)
  
  /* Convert nanoseconds to milliseconds and vice versa */
  #define NS2MS(nsec) ((nsec) / (double) NS_PER_MS)
  #define MS2NS(sec)  ((sec) * (uint64_t) NS_PER_MS)
  
  /* Convert milliseconds to seconds and vice versa */
  #define MS2SEC(msec) ((msec) / (double) MS_PER_SEC)
  #define SEC2MS(sec) ((sec) * MS_PER_SEC)
  
  
  /* Difference between two 'timespec' values in nanoseconds */
  #define TIMESPEC_DIFF(a, b) (SEC2NS(a.tv_sec - b.tv_sec) + \
            (a.tv_nsec - b.tv_nsec))
  
  /* Wrapper over various *gettime* functions */
  # define SB_GETTIME(tsp)                        \
    do {                                          \
      struct timeval tv;                          \
      gettimeofday(&tv, NULL);                    \
      (tsp)->tv_sec = tv.tv_sec;                  \
      (tsp)->tv_nsec = tv.tv_usec * 1000;         \
    } while (0)
  
  typedef enum {
    TIMER_UNINITIALIZED, TIMER_INITIALIZED, TIMER_STOPPED, \
                TIMER_RUNNING
  } timer_state_t;
  
  /* Timer structure definition */
  
  typedef struct {
    struct timespec time_start;
    struct timespec time_end;
    uint64_t events;
    uint64_t queue_time;
    uint64_t min_time;
    uint64_t max_time;
    uint64_t sum_time;
  
    spinlock_t lock;
  
    char pad[SB_CACHELINE_PAD(sizeof(struct timespec) * 2 + sizeof(uint64_t) * 5 +
                              sizeof(spinlock_t))];
  } sb_timer_t;
  sb_timer_t *timers;
  sb_timer_t *timers_copy;
  
  static inline int sb_nanosleep(uint64_t ns) {
    struct timespec ts = {ns / NS_PER_SEC, (long) ns % NS_PER_SEC};
    return nanosleep(&ts, NULL);
  }
  
  /* timer control functions */
  
  /* Initialize timer */
  void sb_timer_init(sb_timer_t *);
  
  /* Reset timer counters, but leave the current state intact */
  void sb_timer_reset(sb_timer_t *t);
  
  /* check whether the timer is running */
  bool sb_timer_running(sb_timer_t *t);
  
  /* start timer */
  static inline void sb_timer_start(sb_timer_t *t) {
    acquire_spinlock(&t->lock);
  
    SB_GETTIME(&t->time_start);
  
    release_spinlock(&t->lock);
  }
  
  /* stop timer */
  static inline uint64_t sb_timer_stop(sb_timer_t *t) {
    acquire_spinlock(&t->lock);
  
    SB_GETTIME(&t->time_end);
  
    uint64_t elapsed = TIMESPEC_DIFF(t->time_end, t->time_start) + t->queue_time;
  
    t->events++;
    t->sum_time += elapsed;
    printf("thread #%ld event %ld\n", t - timers, t->events);
    if (SB_UNLIKELY(elapsed < t->min_time))
      t->min_time = elapsed;
    if (SB_UNLIKELY(elapsed > t->max_time))
      t->max_time = elapsed;
  
    release_spinlock(&t->lock);
  
    return elapsed;
  }
  
  int init_timers(void);
  
  /*
    get the current timer value in nanoseconds without affecting its state, i.e.
    is safe to be used concurrently on a shared timer.
  */
  static inline uint64_t sb_timer_value(sb_timer_t *t) {
    struct timespec ts;
  
    SB_GETTIME(&ts);
    return TIMESPEC_DIFF(ts, t->time_start) + t->queue_time;
  }
  
  /* Clone a timer */
  void sb_timer_copy(sb_timer_t *to, sb_timer_t *from);
  
  /*
    get time elapsed since the previous call to sb_timer_checkpoint() for the
    specified timer without stopping it.  The first call returns time elapsed
    since the timer was started.
  */
  uint64_t sb_timer_current(sb_timer_t *t);
  
  /*
    Atomically reset a given timer after copying its state into the timer pointed
    to by 'old'.
  */
  void sb_timer_checkpoint(sb_timer_t *t, sb_timer_t *old);
  
  /* get average time per event */
  uint64_t sb_timer_avg(sb_timer_t *);
  
  /* get total time for all events */
  uint64_t sb_timer_sum(sb_timer_t *);
  
  /* get minimum time */
  uint64_t sb_timer_min(sb_timer_t *);
  
  /* get maximum time */
  uint64_t sb_timer_max(sb_timer_t *);
  
  /* sum data from two timers. used in summing data from multiple threads */
  sb_timer_t sb_timer_merge(sb_timer_t *, sb_timer_t *);
  
  int sb_timer_events_sum(sb_timer_t *, int size);
  /* timers for test */
  
  
  #endif //SYSBENCH_SB_TIMER_H
  