/*
 * nasd_generic_timer.h
 *
 * definitions of the NASD timing macros that do not
 * use platform-specific mechanisms
 *
 * Author: Jim Zelenka
 */
/*
 * Copyright (c) of Carnegie Mellon University, 1997,1998,1999.
 *
 * Permission to reproduce, use, and prepare derivative works of
 * this software for internal use is granted provided the copyright
 * and "No Warranty" statements are included with all reproductions
 * and derivative works. This software may also be redistributed
 * without charge provided that the copyright and "No Warranty"
 * statements are included in all redistributions.
 *
 * NO WARRANTY. THIS SOFTWARE IS FURNISHED ON AN "AS IS" BASIS.
 * CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY KIND, EITHER
 * EXPRESSED OR IMPLIED AS TO THE MATTER INCLUDING, BUT NOT LIMITED
 * TO: WARRANTY OF FITNESS FOR PURPOSE OR MERCHANTABILITY, EXCLUSIVITY
 * OF RESULTS OR RESULTS OBTAINED FROM USE OF THIS SOFTWARE. CARNEGIE
 * MELLON UNIVERSITY DOES NOT MAKE ANY WARRANTY OF ANY KIND WITH RESPECT
 * TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT.
 */


#ifndef _NASD__NASD_GENERIC_TIMER_H_
#define _NASD__NASD_GENERIC_TIMER_H_

typedef struct nasd_delaycounter_s    nasd_delaycounter_t;
typedef struct nasd_multitimer_s      nasd_multitimer_t;
typedef struct nasd_timer_s           nasd_timer_t;
typedef struct nasd_timer_interval_s  nasd_timer_interval_t;

struct nasd_delaycounter_s {
  nasd_timespec_t  t0;
};

#define NASD_BEGIN_DELAYCNT(_d_) { \
  nasd_gettime(&(_d_)->t0); \
}

#define NASD_DELAY_FROM(_d_,_us_) { \
  nasd_timespec_t _ts, _cur, _delta; \
  _ts.ts_sec = ((_us_)/NASD_USEC_PER_SEC); \
  _ts.ts_nsec = ((_us_)%NASD_USEC_PER_SEC) * 1000; \
  NASD_TIMESPEC_ADD(_ts, (_d_)->t0); \
  nasd_gettime(&_cur); \
  if (NASD_TIMESPEC_LT(_cur, _ts)) { \
    NASD_TIMESPEC_SUB(_ts, _cur); \
    nasd_delay_ts(_ts); \
  } \
}

struct nasd_timer_interval_s {
  nasd_timespec_t   start;
  nasd_timespec_t   stop;
  char             *start_file;
  char             *stop_file;
  int               start_line;
  int               stop_line;
};

struct nasd_multitimer_s {
  nasd_timer_interval_t  intervals[NASD_TM_INTERVALS];
  int                    cur;
};

struct nasd_timer_s {
  nasd_timer_interval_t  intervals[1];
  int                    cur;
};

#define NASD_TM_START(_tm_) { \
  (_tm_)->cur = 0; \
  (_tm_)->intervals[(_tm_)->cur].start_file = __FILE__; \
  (_tm_)->intervals[(_tm_)->cur].start_line = __LINE__; \
  nasd_gettime(&(_tm_)->intervals[(_tm_)->cur].start); \
}

#define NASD_TM_STOP(_tm_) { \
  nasd_gettime(&(_tm_)->intervals[(_tm_)->cur].stop); \
  (_tm_)->intervals[(_tm_)->cur].stop_file = __FILE__; \
  (_tm_)->intervals[(_tm_)->cur].stop_line = __LINE__; \
}

#define NASD_TM_CKPT(_tm_) { \
  nasd_timespec_t _ts; \
  if (sizeof((_tm_)->intervals) == sizeof(nasd_timer_interval_t)) { \
    /* this is not a multitimer */ \
    NASD_PANIC(); \
  } \
  nasd_gettime(&_ts); \
  (_tm_)->intervals[(_tm_)->cur].stop = _ts; \
  (_tm_)->intervals[(_tm_)->cur].stop_file = __FILE__; \
  (_tm_)->intervals[(_tm_)->cur].stop_line = __LINE__; \
  (_tm_)->cur++; \
  NASD_ASSERT((_tm_)->cur < NASD_TM_INTERVALS); \
  (_tm_)->intervals[(_tm_)->cur].start = _ts; \
  (_tm_)->intervals[(_tm_)->cur].start_file = __FILE__; \
  (_tm_)->intervals[(_tm_)->cur].start_line = __LINE__; \
}

#define NASD_TM_REPORT(_tm_) { \
  nasd_timer_interval_t *_intv, *_intv2; \
  nasd_timespec_t _diff; \
  int _i; \
  nasd_printf("-----\n"); \
  if (sizeof((_tm_)->intervals) > sizeof(nasd_timer_interval_t)) { \
    for(_i=0;_i<=(_tm_)->cur;_i++) { \
      _intv = &(_tm_)->intervals[_i]; \
      _diff = _intv->stop; \
      NASD_TIMESPEC_SUB(_diff, _intv->start); \
      nasd_printf("%d:%09d", _diff.ts_sec, _diff.ts_nsec); \
      nasd_printf(" start %s:%d", _intv->start_file, _intv->start_line); \
      nasd_printf(" end %s:%d", _intv->stop_file, _intv->stop_line); \
      nasd_printf(" (%d:%09d..%d:%09d)\n", \
        _intv->start.ts_sec, _intv->start.ts_nsec, \
        _intv->stop.ts_sec, _intv->stop.ts_nsec); \
    } \
  } \
  _intv = &(_tm_)->intervals[0]; \
  _intv2 = &(_tm_)->intervals[(_tm_)->cur]; \
  _diff = _intv2->stop; \
  NASD_TIMESPEC_SUB(_diff, _intv->start); \
  nasd_printf("%d:%09d", _diff.ts_sec, _diff.ts_nsec); \
  nasd_printf(" start %s:%d", _intv->start_file, _intv->start_line); \
  nasd_printf(" end %s:%d", _intv2->stop_file, _intv2->stop_line); \
  nasd_printf(" (%d:%09d..%d:%09d)\n", \
    _intv->start.ts_sec, _intv->start.ts_nsec, \
    _intv2->stop.ts_sec, _intv2->stop.ts_nsec); \
  nasd_printf("-----\n"); \
}

#define NASD_TM_ELAPSED_NSEC(_tm_,_nsecp_) { \
  nasd_timer_interval_t *_intv, *_intv2; \
  nasd_timespec_t _diff; \
  nasd_uint64 _nsecs; \
  _intv = &(_tm_)->intervals[0]; \
  _intv2 = &(_tm_)->intervals[(_tm_)->cur]; \
  _diff = _intv2->stop; \
  NASD_TIMESPEC_SUB(_diff, _intv->start); \
  _nsecs = _diff.ts_sec * NASD_NSEC_PER_SEC; \
  _nsecs += _diff.ts_nsec; \
  *(_nsecp_) = _nsecs; \
}

#define NASD_TM_ELAPSED_TS(_tm_,_tsp_) { \
  nasd_timer_interval_t *_intv, *_intv2; \
  nasd_timespec_t _diff; \
  _intv = &(_tm_)->intervals[0]; \
  _intv2 = &(_tm_)->intervals[(_tm_)->cur]; \
  _diff = _intv2->stop; \
  NASD_TIMESPEC_SUB(_diff, _intv->start); \
  *(_tsp_) = _diff; \
}

#define NASD_TM_STOP_ACCUM_TS(_tm_,_tsp_) { \
  nasd_timespec_t _tmp; \
  NASD_TM_STOP(_tm_); \
  NASD_TM_ELAPSED_TS(_tm_,&_tmp); \
  NASD_TIMESPEC_ADD(*(_tsp_), _tmp); \
}

#define NASD_TM_STOP_ELAP_TS(_tm_,_tsp_) { \
  NASD_TM_STOP(_tm_); \
  NASD_TM_ELAPSED_TS(_tm_,_tsp_); \
}

#endif /* !_NASD__NASD_GENERIC_TIMER_H_ */

/* Local Variables:  */
/* indent-tabs-mode: nil */
/* tab-width: 2 */
/* End: */
