1/*---------------------------------------------------------------------------*
2 *  pcputimer.c  *
3 *                                                                           *
4 *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
5 *                                                                           *
6 *  Licensed under the Apache License, Version 2.0 (the 'License');          *
7 *  you may not use this file except in compliance with the License.         *
8 *                                                                           *
9 *  You may obtain a copy of the License at                                  *
10 *      http://www.apache.org/licenses/LICENSE-2.0                           *
11 *                                                                           *
12 *  Unless required by applicable law or agreed to in writing, software      *
13 *  distributed under the License is distributed on an 'AS IS' BASIS,        *
14 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
15 *  See the License for the specific language governing permissions and      *
16 *  limitations under the License.                                           *
17 *                                                                           *
18 *---------------------------------------------------------------------------*/
19
20
21
22#include "pcputimer.h"
23#include "pmemory.h"
24
25#if defined(_WIN32)
26
27/*
28  Note that this implementation assumes that GetThreadTimes is
29  available (requires NT 3.5 and above) and that 64 bit arithmetic is
30  available (requires VC)
31*/
32
33struct PCPUTimer_t
34{
35  HANDLE hThread;
36  LARGE_INTEGER RefTime;
37  asr_uint32_t elapsed;
38};
39
40
41/**
42 * Creates a new timer object.
43 **/
44ESR_ReturnCode PCPUTimerCreate(PCPUTimer **timer)
45{
46  PCPUTimer *tmp = NULL;
47
48  if (timer == NULL)
49    return ESR_INVALID_ARGUMENT;
50  tmp = NEW(PCPUTimer, "PCPUTimer");
51  if (tmp == NULL) return ESR_OUT_OF_MEMORY;
52
53  tmp->hThread = GetCurrentThread();
54  tmp->RefTime.QuadPart = -1;
55  tmp->elapsed = 0;
56  *timer = tmp;
57
58  return ESR_SUCCESS;
59}
60
61ESR_ReturnCode PCPUTimerDestroy(PCPUTimer *timer)
62{
63  if (timer == NULL) return ESR_INVALID_ARGUMENT;
64  FREE(timer);
65  return ESR_SUCCESS;
66}
67
68/**
69 * Starts the timer. This sets the reference time from which all new elapsed
70 * time are computed.  This does not reset the elapsed time to 0.  This is
71 * useful to pause the timer.
72 **/
73ESR_ReturnCode PCPUTimerStart(PCPUTimer *timer)
74{
75  FILETIME CreationTime;
76  FILETIME ExitTime;
77  FILETIME KernelTime;
78  FILETIME UserTime;
79
80  if (timer == NULL) return ESR_INVALID_ARGUMENT;
81  if (!GetThreadTimes(timer->hThread,
82                      &CreationTime, &ExitTime, &KernelTime, &UserTime))
83  {
84    return ESR_FATAL_ERROR;
85  }
86
87  timer->RefTime.QuadPart = (((LARGE_INTEGER*) & KernelTime)->QuadPart +
88                             ((LARGE_INTEGER*) & UserTime)->QuadPart);
89
90  return ESR_SUCCESS;
91}
92
93/**
94 * Stops the timer.
95 **/
96ESR_ReturnCode PCPUTimerStop(PCPUTimer *timer)
97{
98  if (timer == NULL) return ESR_INVALID_ARGUMENT;
99  if (timer->RefTime.QuadPart != -1)
100  {
101    FILETIME CreationTime;
102    FILETIME ExitTime;
103    FILETIME KernelTime;
104    FILETIME UserTime;
105
106    if (!GetThreadTimes(timer->hThread,
107                        &CreationTime, &ExitTime, &KernelTime, &UserTime))
108      return ESR_FATAL_ERROR;
109
110    timer->elapsed =
111      (asr_uint32_t) (((LARGE_INTEGER*) &KernelTime)->QuadPart +
112                  ((LARGE_INTEGER*) &UserTime)->QuadPart -
113                  timer->RefTime.QuadPart) / 10;
114  }
115  return ESR_SUCCESS;
116}
117
118/**
119 * Returns the timer elapsed time.  If the Timer is in the stopped state,
120 * successive calls to getElapsed() will always return the same value.  If
121 * the Timer is in the started state, successive calls will return the
122 * elapsed time since the last time PCPUTimerStart() was called.
123 */
124ESR_ReturnCode PCPUTimerGetElapsed(PCPUTimer *timer, asr_uint32_t *elapsed)
125{
126  if (timer == NULL || elapsed == NULL) return ESR_INVALID_ARGUMENT;
127  if (timer->RefTime.QuadPart != -1)
128  {
129    FILETIME CreationTime;
130    FILETIME ExitTime;
131    FILETIME KernelTime;
132    FILETIME UserTime;
133
134    if (!GetThreadTimes(timer->hThread,
135                        &CreationTime, &ExitTime, &KernelTime, &UserTime))
136      return ESR_FATAL_ERROR;
137
138    *elapsed = timer->elapsed +
139               (asr_uint32_t)(((LARGE_INTEGER*) & KernelTime)->QuadPart +
140                              ((LARGE_INTEGER*) & UserTime)->QuadPart -
141                              timer->RefTime.QuadPart) / 10;
142  }
143  else
144    *elapsed = timer->elapsed;
145  return ESR_SUCCESS;
146}
147
148
149/**
150 * Resets the elapsed time to 0 and resets the reference time of the Timer.
151 * This effectively reset the timer in the same state it was right after creation.
152 **/
153ESR_ReturnCode PCPUTimerReset(PCPUTimer *timer)
154{
155  if (timer == NULL) return ESR_INVALID_ARGUMENT;
156  timer->RefTime.QuadPart = -1;
157  timer->elapsed = 0;
158  return ESR_SUCCESS;
159}
160
161#elif defined(POSIX)
162/*
163*/
164
165struct PCPUTimer_t
166{
167  HANDLE   hThread;
168  asr_uint32_t RefTime;
169  asr_uint32_t elapsed;
170};
171
172/**
173* Creates a new timer object.
174**/
175ESR_ReturnCode PCPUTimerCreate(PCPUTimer **timer)
176{
177  PCPUTimer *tmp = NULL;
178
179  if (timer == NULL) return ESR_INVALID_ARGUMENT;
180  tmp = NEW(PCPUTimer, "PCPUTimer");
181  if (tmp == NULL) return ESR_OUT_OF_MEMORY;
182
183  tmp->hThread = (HANDLE)pthread_self();
184  tmp->elapsed = 0;
185  *timer = tmp;
186
187  return ESR_SUCCESS;
188}
189
190ESR_ReturnCode PCPUTimerDestroy(PCPUTimer *timer)
191{
192  if (timer == NULL) return ESR_INVALID_ARGUMENT;
193  FREE(timer);
194  return ESR_SUCCESS;
195}
196
197/**
198* Starts the timer. This sets the reference time from which all new elapsed
199* time are computed.  This does not reset the elapsed time to 0.  This is
200* useful to pause the timer.
201**/
202ESR_ReturnCode PCPUTimerStart(PCPUTimer *timer)
203{
204  return ESR_SUCCESS;
205}
206
207/**
208* Stops the timer.
209**/
210ESR_ReturnCode PCPUTimerStop(PCPUTimer *timer)
211{
212  return ESR_SUCCESS;
213}
214
215/**
216* Returns the timer elapsed time.  If the Timer is in the stopped state,
217* successive calls to getElapsed() will always return the same value.  If
218* the Timer is in the started state, successive calls will return the
219* elapsed time since the last time PCPUTimerStart() was called.
220*/
221ESR_ReturnCode PCPUTimerGetElapsed(PCPUTimer *timer, asr_uint32_t *elapsed)
222{
223  return ESR_SUCCESS;
224}
225
226
227/**
228* Resets the elapsed time to 0 and resets the reference time of the Timer.
229* This effectively reset the timer in the same state it was right after creation.
230**/
231ESR_ReturnCode PCPUTimerReset(PCPUTimer *timer)
232{
233  return ESR_SUCCESS;
234}
235
236#else
237/* #error "Ptimer not implemented for this platform." */
238#endif
239