// @(#)root/base:$Id$
// Author: Fons Rademakers   11/10/95

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TStopwatch                                                           //
//                                                                      //
// Stopwatch class. This class returns the real and cpu time between    //
// the start and stop events.                                           //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TStopwatch.h"
#include "TTimeStamp.h"
#include "TString.h"

#if defined(R__UNIX)
#  include <sys/times.h>
#  include <unistd.h>
static Double_t gTicks = 0;
#elif defined(WIN32)
#  include "TError.h"
const Double_t gTicks = 1.0e-7;
#  include "Windows4Root.h"
#endif


ClassImp(TStopwatch)

//______________________________________________________________________________
TStopwatch::TStopwatch()
{
   // Create a stopwatch and start it.

#ifdef R__UNIX
   if (gTicks <= 0.0)
      gTicks = (Double_t)sysconf(_SC_CLK_TCK);
#endif

   fStopRealTime = 0;
   fStopCpuTime  = 0;

   Start();
}

//______________________________________________________________________________
void TStopwatch::Start(Bool_t reset)
{
   // Start the stopwatch. If reset is kTRUE reset the stopwatch before
   // starting it (including the stopwatch counter).
   // Use kFALSE to continue timing after a Stop() without
   // resetting the stopwatch.

   if (reset) {
      fState         = kUndefined;
      fTotalCpuTime  = 0;
      fTotalRealTime = 0;
      fCounter       = 0;
   }
   if (fState != kRunning) {
      fStartRealTime = GetRealTime();
      fStartCpuTime  = GetCPUTime();
   }
   fState = kRunning;
   fCounter++;
}

//______________________________________________________________________________
void TStopwatch::Stop()
{
   // Stop the stopwatch.

   fStopRealTime = GetRealTime();
   fStopCpuTime  = GetCPUTime();

   if (fState == kRunning) {
      fTotalCpuTime  += fStopCpuTime  - fStartCpuTime;
      fTotalRealTime += fStopRealTime - fStartRealTime;
   }
   fState = kStopped;
}

//______________________________________________________________________________
void TStopwatch::Continue()
{
   // Resume a stopped stopwatch. The stopwatch continues counting from the last
   // Start() onwards (this is like the laptimer function).

   if (fState == kUndefined)
      Error("Continue", "stopwatch not started");

   if (fState == kStopped) {
      fTotalCpuTime  -= fStopCpuTime  - fStartCpuTime;
      fTotalRealTime -= fStopRealTime - fStartRealTime;
   }

   fState = kRunning;
}

//______________________________________________________________________________
Double_t TStopwatch::RealTime()
{
   // Stop the stopwatch (if it is running) and return the realtime (in
   // seconds) passed between the start and stop events.

   if (fState == kUndefined)
      Error("RealTime", "stopwatch not started");

   if (fState == kRunning)
      Stop();

   return fTotalRealTime;
}

//______________________________________________________________________________
Double_t TStopwatch::CpuTime()
{
   // Stop the stopwatch (if it is running) and return the cputime (in
   // seconds) passed between the start and stop events.

   if (fState == kUndefined)
      Error("CpuTime", "stopwatch not started");

   if (fState == kRunning)
      Stop();

   return fTotalCpuTime;
}

//______________________________________________________________________________
Double_t TStopwatch::GetRealTime()
{
   // Private static method returning system realtime.

#if defined(R__UNIX)
   return TTimeStamp();
#elif defined(WIN32)
   union {
      FILETIME ftFileTime;
      __int64  ftInt64;
   } ftRealTime; // time the process has spent in kernel mode
   SYSTEMTIME st;
   GetSystemTime(&st);
   SystemTimeToFileTime(&st,&ftRealTime.ftFileTime);
   return (Double_t)ftRealTime.ftInt64 * gTicks;
#endif
}

//______________________________________________________________________________
Double_t TStopwatch::GetCPUTime()
{
   // Private static method returning system CPU time.

#if defined(R__UNIX)
   struct tms cpt;
   times(&cpt);
   return (Double_t)(cpt.tms_utime+cpt.tms_stime) / gTicks;
#elif defined(WIN32)

   OSVERSIONINFO OsVersionInfo;

   //         Value                      Platform
   //----------------------------------------------------
   //  VER_PLATFORM_WIN32s          Win32s on Windows 3.1
   //  VER_PLATFORM_WIN32_WINDOWS   Win32 on Windows 95
   //  VER_PLATFORM_WIN32_NT        Windows NT
   //
   OsVersionInfo.dwOSVersionInfoSize=sizeof(OSVERSIONINFO);
   GetVersionEx(&OsVersionInfo);
   if (OsVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) {
      DWORD       ret;
      FILETIME    ftCreate,       // when the process was created
                  ftExit;         // when the process exited

      union {
         FILETIME ftFileTime;
         __int64  ftInt64;
      } ftKernel; // time the process has spent in kernel mode

      union {
         FILETIME ftFileTime;
         __int64  ftInt64;
      } ftUser;   // time the process has spent in user mode

      HANDLE hThread = GetCurrentThread();
      ret = GetThreadTimes (hThread, &ftCreate, &ftExit,
                                     &ftKernel.ftFileTime,
                                     &ftUser.ftFileTime);
      if (ret != TRUE) {
         ret = GetLastError ();
         ::Error ("GetCPUTime", " Error on GetProcessTimes 0x%lx", (int)ret);
      }

      // Process times are returned in a 64-bit structure, as the number of
      // 100 nanosecond ticks since 1 January 1601.  User mode and kernel mode
      // times for this process are in separate 64-bit structures.
      // To convert to floating point seconds, we will:
      //
      // Convert sum of high 32-bit quantities to 64-bit int

      return (Double_t) (ftKernel.ftInt64 + ftUser.ftInt64) * gTicks;
   } else
      return GetRealTime();
#endif
}

//______________________________________________________________________________
void TStopwatch::Print(Option_t *opt) const
{
   // Print the real and cpu time passed between the start and stop events.
   // and the number of times (slices) this TStopwatch was called
   // (if this number > 1). If opt="m" print out realtime in milli second
   // precision. If opt="u" print out realtime in micro second precision.

   Double_t  realt = const_cast<TStopwatch*>(this)->RealTime();
   Double_t  cput  = const_cast<TStopwatch*>(this)->CpuTime();

   Int_t  hours = Int_t(realt / 3600);
   realt -= hours * 3600;
   Int_t  min   = Int_t(realt / 60);
   realt -= min * 60;
   Int_t  sec   = Int_t(realt);

   if (realt < 0) realt = 0;
   if (cput  < 0) cput  = 0;

   if (opt && *opt == 'm') {
      if (Counter() > 1) {
         Printf("Real time %d:%02d:%06.3f, CP time %.3f, %d slices", hours, min, realt, cput, Counter());
      } else {
         Printf("Real time %d:%02d:%06.3f, CP time %.3f", hours, min, realt, cput);
      }
   } else if (opt && *opt == 'u') {
      if (Counter() > 1) {
         Printf("Real time %d:%02d:%09.6f, CP time %.3f, %d slices", hours, min, realt, cput, Counter());
      } else {
         Printf("Real time %d:%02d:%09.6f, CP time %.3f", hours, min, realt, cput);
      }
   } else {
      if (Counter() > 1) {
         Printf("Real time %d:%02d:%02d, CP time %.3f, %d slices", hours, min, sec, cput, Counter());
      } else {
         Printf("Real time %d:%02d:%02d, CP time %.3f", hours, min, sec, cput);
      }
   }
}
 TStopwatch.cxx:1
 TStopwatch.cxx:2
 TStopwatch.cxx:3
 TStopwatch.cxx:4
 TStopwatch.cxx:5
 TStopwatch.cxx:6
 TStopwatch.cxx:7
 TStopwatch.cxx:8
 TStopwatch.cxx:9
 TStopwatch.cxx:10
 TStopwatch.cxx:11
 TStopwatch.cxx:12
 TStopwatch.cxx:13
 TStopwatch.cxx:14
 TStopwatch.cxx:15
 TStopwatch.cxx:16
 TStopwatch.cxx:17
 TStopwatch.cxx:18
 TStopwatch.cxx:19
 TStopwatch.cxx:20
 TStopwatch.cxx:21
 TStopwatch.cxx:22
 TStopwatch.cxx:23
 TStopwatch.cxx:24
 TStopwatch.cxx:25
 TStopwatch.cxx:26
 TStopwatch.cxx:27
 TStopwatch.cxx:28
 TStopwatch.cxx:29
 TStopwatch.cxx:30
 TStopwatch.cxx:31
 TStopwatch.cxx:32
 TStopwatch.cxx:33
 TStopwatch.cxx:34
 TStopwatch.cxx:35
 TStopwatch.cxx:36
 TStopwatch.cxx:37
 TStopwatch.cxx:38
 TStopwatch.cxx:39
 TStopwatch.cxx:40
 TStopwatch.cxx:41
 TStopwatch.cxx:42
 TStopwatch.cxx:43
 TStopwatch.cxx:44
 TStopwatch.cxx:45
 TStopwatch.cxx:46
 TStopwatch.cxx:47
 TStopwatch.cxx:48
 TStopwatch.cxx:49
 TStopwatch.cxx:50
 TStopwatch.cxx:51
 TStopwatch.cxx:52
 TStopwatch.cxx:53
 TStopwatch.cxx:54
 TStopwatch.cxx:55
 TStopwatch.cxx:56
 TStopwatch.cxx:57
 TStopwatch.cxx:58
 TStopwatch.cxx:59
 TStopwatch.cxx:60
 TStopwatch.cxx:61
 TStopwatch.cxx:62
 TStopwatch.cxx:63
 TStopwatch.cxx:64
 TStopwatch.cxx:65
 TStopwatch.cxx:66
 TStopwatch.cxx:67
 TStopwatch.cxx:68
 TStopwatch.cxx:69
 TStopwatch.cxx:70
 TStopwatch.cxx:71
 TStopwatch.cxx:72
 TStopwatch.cxx:73
 TStopwatch.cxx:74
 TStopwatch.cxx:75
 TStopwatch.cxx:76
 TStopwatch.cxx:77
 TStopwatch.cxx:78
 TStopwatch.cxx:79
 TStopwatch.cxx:80
 TStopwatch.cxx:81
 TStopwatch.cxx:82
 TStopwatch.cxx:83
 TStopwatch.cxx:84
 TStopwatch.cxx:85
 TStopwatch.cxx:86
 TStopwatch.cxx:87
 TStopwatch.cxx:88
 TStopwatch.cxx:89
 TStopwatch.cxx:90
 TStopwatch.cxx:91
 TStopwatch.cxx:92
 TStopwatch.cxx:93
 TStopwatch.cxx:94
 TStopwatch.cxx:95
 TStopwatch.cxx:96
 TStopwatch.cxx:97
 TStopwatch.cxx:98
 TStopwatch.cxx:99
 TStopwatch.cxx:100
 TStopwatch.cxx:101
 TStopwatch.cxx:102
 TStopwatch.cxx:103
 TStopwatch.cxx:104
 TStopwatch.cxx:105
 TStopwatch.cxx:106
 TStopwatch.cxx:107
 TStopwatch.cxx:108
 TStopwatch.cxx:109
 TStopwatch.cxx:110
 TStopwatch.cxx:111
 TStopwatch.cxx:112
 TStopwatch.cxx:113
 TStopwatch.cxx:114
 TStopwatch.cxx:115
 TStopwatch.cxx:116
 TStopwatch.cxx:117
 TStopwatch.cxx:118
 TStopwatch.cxx:119
 TStopwatch.cxx:120
 TStopwatch.cxx:121
 TStopwatch.cxx:122
 TStopwatch.cxx:123
 TStopwatch.cxx:124
 TStopwatch.cxx:125
 TStopwatch.cxx:126
 TStopwatch.cxx:127
 TStopwatch.cxx:128
 TStopwatch.cxx:129
 TStopwatch.cxx:130
 TStopwatch.cxx:131
 TStopwatch.cxx:132
 TStopwatch.cxx:133
 TStopwatch.cxx:134
 TStopwatch.cxx:135
 TStopwatch.cxx:136
 TStopwatch.cxx:137
 TStopwatch.cxx:138
 TStopwatch.cxx:139
 TStopwatch.cxx:140
 TStopwatch.cxx:141
 TStopwatch.cxx:142
 TStopwatch.cxx:143
 TStopwatch.cxx:144
 TStopwatch.cxx:145
 TStopwatch.cxx:146
 TStopwatch.cxx:147
 TStopwatch.cxx:148
 TStopwatch.cxx:149
 TStopwatch.cxx:150
 TStopwatch.cxx:151
 TStopwatch.cxx:152
 TStopwatch.cxx:153
 TStopwatch.cxx:154
 TStopwatch.cxx:155
 TStopwatch.cxx:156
 TStopwatch.cxx:157
 TStopwatch.cxx:158
 TStopwatch.cxx:159
 TStopwatch.cxx:160
 TStopwatch.cxx:161
 TStopwatch.cxx:162
 TStopwatch.cxx:163
 TStopwatch.cxx:164
 TStopwatch.cxx:165
 TStopwatch.cxx:166
 TStopwatch.cxx:167
 TStopwatch.cxx:168
 TStopwatch.cxx:169
 TStopwatch.cxx:170
 TStopwatch.cxx:171
 TStopwatch.cxx:172
 TStopwatch.cxx:173
 TStopwatch.cxx:174
 TStopwatch.cxx:175
 TStopwatch.cxx:176
 TStopwatch.cxx:177
 TStopwatch.cxx:178
 TStopwatch.cxx:179
 TStopwatch.cxx:180
 TStopwatch.cxx:181
 TStopwatch.cxx:182
 TStopwatch.cxx:183
 TStopwatch.cxx:184
 TStopwatch.cxx:185
 TStopwatch.cxx:186
 TStopwatch.cxx:187
 TStopwatch.cxx:188
 TStopwatch.cxx:189
 TStopwatch.cxx:190
 TStopwatch.cxx:191
 TStopwatch.cxx:192
 TStopwatch.cxx:193
 TStopwatch.cxx:194
 TStopwatch.cxx:195
 TStopwatch.cxx:196
 TStopwatch.cxx:197
 TStopwatch.cxx:198
 TStopwatch.cxx:199
 TStopwatch.cxx:200
 TStopwatch.cxx:201
 TStopwatch.cxx:202
 TStopwatch.cxx:203
 TStopwatch.cxx:204
 TStopwatch.cxx:205
 TStopwatch.cxx:206
 TStopwatch.cxx:207
 TStopwatch.cxx:208
 TStopwatch.cxx:209
 TStopwatch.cxx:210
 TStopwatch.cxx:211
 TStopwatch.cxx:212
 TStopwatch.cxx:213
 TStopwatch.cxx:214
 TStopwatch.cxx:215
 TStopwatch.cxx:216
 TStopwatch.cxx:217
 TStopwatch.cxx:218
 TStopwatch.cxx:219
 TStopwatch.cxx:220
 TStopwatch.cxx:221
 TStopwatch.cxx:222
 TStopwatch.cxx:223
 TStopwatch.cxx:224
 TStopwatch.cxx:225
 TStopwatch.cxx:226
 TStopwatch.cxx:227
 TStopwatch.cxx:228
 TStopwatch.cxx:229
 TStopwatch.cxx:230
 TStopwatch.cxx:231
 TStopwatch.cxx:232
 TStopwatch.cxx:233
 TStopwatch.cxx:234
 TStopwatch.cxx:235
 TStopwatch.cxx:236
 TStopwatch.cxx:237
 TStopwatch.cxx:238
 TStopwatch.cxx:239
 TStopwatch.cxx:240
 TStopwatch.cxx:241
 TStopwatch.cxx:242
 TStopwatch.cxx:243
 TStopwatch.cxx:244
 TStopwatch.cxx:245
 TStopwatch.cxx:246
 TStopwatch.cxx:247
 TStopwatch.cxx:248
 TStopwatch.cxx:249
 TStopwatch.cxx:250
 TStopwatch.cxx:251
 TStopwatch.cxx:252
 TStopwatch.cxx:253
 TStopwatch.cxx:254