//
// LiDIA - a library for computational number theory
//   Copyright (c) 1995 by the LiDIA Group
//
// File        : timer.c 
// Author      : Thomas Papanikolaou (TP)
// Last change : TP, Feb 7 1995, initial version
//

#include <LiDIA/timer.h>

void timer::print_hms(ostream & out, long rt) const
{
  long d, h, m, s, hs;

  d = rt / 86400000;
  if (d)
  {
    out << d << " day ";
    rt -= d * 86400000;
  }

  h = rt / 3600000;
  if (h)
  {
    out << h << " hour ";
    rt -= h * 3600000;
  }

  m = rt / 60000;
  if (m)
  {
    out << m << " min ";
    rt -= m * 60000;
  }

  s = rt / 1000;
  if (s)
  {
    out << s << " sec ";
    rt -= s * 1000;
  }

  hs = rt / 10;
  if (hs)
  {
    out << hs << " hsec ";
    rt -= hs * 10;
  }

  if (rt)
    out << rt << " msec";
}

#ifdef HAVE_GETRUSAGE
struct rusage timer::buffer;
#else
struct tms timer::buffer;
#endif

timer::timer()
{
  user_t = 0;
  sys_t = 0;
  t_user_t = 0;
  t_sys_t = 0;
  print_mode = TIME_MODE;
}

timer::timer(const timer & t)
{
  user_t = t.user_t;
  sys_t = t.sys_t;
  t_user_t = t.t_user_t;
  t_sys_t = t.t_sys_t;
  print_mode = t.print_mode;
}

timer::~timer()
{
}

int timer::set_print_mode(int m)
{
  int old_print_mode = print_mode;
  switch (m)
  {
    case 0 :
    case 1 :
      print_mode = m;
      break;
    default:
      warning_handler("timer", "unknown print mode. Set to HMS_MODE");
      print_mode = 1;
      break;
  }
  return old_print_mode;
}

int timer::get_print_mode() const
{ return print_mode; }

void timer::start_timer()
{
#ifdef HAVE_GETRUSAGE
  getrusage(0, &timer::buffer);
  user_t = timer::buffer.ru_utime.tv_sec * 100 
           + timer::buffer.ru_utime.tv_usec / 10000;
  sys_t  = timer::buffer.ru_stime.tv_sec * 100 
           + timer::buffer.ru_stime.tv_usec / 10000;
#else
  times(&buffer);
  user_t = (timer::buffer.tms_utime * 100) / HZ; 
  sys_t  = (timer::buffer.tms_stime * 100) / HZ; 
#endif
  t_user_t = 0;
  t_sys_t  = 0;
}

void timer::stop_timer()
{
#ifdef HAVE_GETRUSAGE
  getrusage(0, &timer::buffer);
  t_user_t += timer::buffer.ru_utime.tv_sec * 100 
              + timer::buffer.ru_utime.tv_usec / 10000
              - user_t;
  t_sys_t  += timer::buffer.ru_stime.tv_sec * 100 
              + timer::buffer.ru_stime.tv_usec / 10000
              - sys_t;
#else
  times(&buffer);
  t_user_t += (timer::buffer.tms_utime * 100) / HZ - user_t;
  t_sys_t  += (timer::buffer.tms_stime * 100) / HZ - sys_t;
#endif
}

void timer::cont_timer()
{
#ifdef HAVE_GETRUSAGE
  getrusage(0, &timer::buffer);
  user_t = timer::buffer.ru_utime.tv_sec * 100 
           + timer::buffer.ru_utime.tv_usec / 10000;
  sys_t  = timer::buffer.ru_stime.tv_sec * 100 
           + timer::buffer.ru_stime.tv_usec / 10000;
#else
  times(&buffer);
  user_t = (timer::buffer.tms_utime * 100) / HZ; 
  sys_t  = (timer::buffer.tms_stime * 100) / HZ; 
#endif
}

long timer::user_time() const
{ return t_user_t; }

long timer::sys_time() const
{ return t_sys_t; }

long timer::real_time() const
{ return t_user_t + t_sys_t; }

void timer::print(ostream & out) const
{
  switch (print_mode)
  {
    case 0:
        out << real_time() << " real\t";
        out << user_time() << " user\t";
        out <<  sys_time() << " sys";
	break;
    case 1:
	  print_hms(out, real_time() * 10);
	break;
    default:
        warning_handler("timer", "unknown print mode. Use HMS_MODE");
	print_hms(out, real_time() * 10);
	break;
  }
}

timer & timer::operator = (const timer & t)
{
  user_t = t.user_t;
  sys_t = t.sys_t;
  t_user_t = t.t_user_t;
  t_sys_t = t.t_sys_t;
  print_mode = t.print_mode;
  return *this;
}

ostream & operator << (ostream & out, const timer & t)
{ t.print(out); return out; }
