1 //*@@@+++@@@@******************************************************************
2 //
3 // Copyright � Microsoft Corp.
4 // All rights reserved.
5 //
6 // Redistribution and use in source and binary forms, with or without
7 // modification, are permitted provided that the following conditions are met:
8 //
9 // � Redistributions of source code must retain the above copyright notice,
10 // this list of conditions and the following disclaimer.
11 // � Redistributions in binary form must reproduce the above copyright notice,
12 // this list of conditions and the following disclaimer in the documentation
13 // and/or other materials provided with the distribution.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
19 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 // POSSIBILITY OF SUCH DAMAGE.
26 //
27 //*@@@---@@@@******************************************************************
28
29 //***************************************************************************
30 // Includes
31 //***************************************************************************
32 #include <time.h>
33 #include "strcodec.h"
34 #include "perfTimer.h"
35
36
37 #ifndef DISABLE_PERF_MEASUREMENT
38
39
40 //***************************************************************************
41 // Private Functions
42 //***************************************************************************
43
AccumulateTime(PERFTIMERSTATE * pState,PERFTIMERTIME * ptAccumulator)44 Bool AccumulateTime(PERFTIMERSTATE *pState, PERFTIMERTIME *ptAccumulator)
45 {
46 Bool fResult = FALSE;
47 clock_t iStopTime;
48 clock_t iIntervalTime;
49 iStopTime = clock();
50
51 // Check clock result
52 if ((clock_t)-1 == iStopTime)
53 {
54 TraceResult(WM_E_CLOCKFAILURE);
55 goto exit;
56 }
57
58 iIntervalTime = (iStopTime - (clock_t) pState->iPrevStartTime);
59
60 // Check for zero-time interval
61 if (0 == iIntervalTime)
62 pState->iZeroTimeIntervals += 1;
63
64 // Accumulate current interval's time
65 *ptAccumulator += iIntervalTime;
66 fResult = TRUE;
67
68 exit:
69 return fResult;
70 }
71
72
73 //***************************************************************************
74 // Public Functions
75 //***************************************************************************
76
77
PerfTimerNew(PERFTIMERSTATE ** ppNewPerfTimer)78 Bool PerfTimerNew(PERFTIMERSTATE **ppNewPerfTimer)
79 {
80 Bool fResult = FALSE;
81 PERFTIMERSTATE *pState = NULL;
82 clock_t ctResult;
83
84 // Check if this clock works
85 ctResult = clock();
86 if ((clock_t)-1 == ctResult)
87 {
88 TraceResult(WM_E_CLOCKFAILURE);
89 goto exit;
90 }
91
92 pState = malloc(sizeof(*pState));
93 if (NULL == pState)
94 {
95 TraceResult(E_OUTOFMEMORY);
96 goto exit;
97 }
98 memset(pState, 0, sizeof(*pState));
99 pState->eState = CS_STOPPED;
100 pState->iElapsedTime = 0;
101 pState->iPrevStartTime = 0;
102 pState->iZeroTimeIntervals = 0;
103
104 *ppNewPerfTimer = pState;
105 fResult = TRUE;
106
107 exit:
108 assert(fResult || NULL == pState); // If error, we need to free pState
109 return fResult;
110 } // PerfTimerNew
111
112
113
PerfTimerDelete(PERFTIMERSTATE * pState)114 void PerfTimerDelete(PERFTIMERSTATE *pState)
115 {
116 free(pState);
117 } // PerfTimerDelete
118
119
120
PerfTimerStart(PERFTIMERSTATE * pState)121 Bool PerfTimerStart(PERFTIMERSTATE *pState)
122 {
123 Bool fResult = FALSE;
124
125 if (NULL == pState)
126 {
127 // Can happen because we typically ignore errors and use a single bool to
128 // control all perf timing (some of which can fail to init)
129 goto exit;
130 }
131
132 // Make sure we are in the right state
133 if (CS_STOPPED != pState->eState)
134 {
135 assert(FALSE);
136 goto exit;
137 }
138
139 pState->iPrevStartTime = clock();
140
141 // Check clock result
142 if ((clock_t)-1 == pState->iPrevStartTime)
143 {
144 TraceResult(WM_E_CLOCKFAILURE);
145 goto exit;
146 }
147
148 pState->eState = CS_RUNNING;
149 fResult = TRUE;
150
151 exit:
152 return fResult;
153 } // PerfTimerStart
154
155
156
PerfTimerStop(PERFTIMERSTATE * pState)157 Bool PerfTimerStop(PERFTIMERSTATE *pState)
158 {
159 Bool fResult = FALSE;
160
161 if (NULL == pState)
162 {
163 // Can happen because we typically ignore errors and use a single bool to
164 // control all perf timing (some of which can fail to init)
165 goto exit;
166 }
167
168 // Make sure we are in the right state
169 if (CS_RUNNING != pState->eState)
170 {
171 assert(FALSE);
172 goto exit;
173 }
174
175 fResult = AccumulateTime(pState, &pState->iElapsedTime);
176 pState->eState = CS_STOPPED;
177 fResult = TRUE;
178
179 exit:
180 return fResult;
181 } // PerfTimerStop
182
183
184
PerfTimerGetResults(PERFTIMERSTATE * pState,PERFTIMERRESULTS * pResults)185 Bool PerfTimerGetResults(PERFTIMERSTATE *pState, PERFTIMERRESULTS *pResults)
186 {
187 Bool fResult = FALSE;
188 PERFTIMERTIME iElapsedTime;
189
190 if (NULL == pState)
191 {
192 // Can happen because we typically ignore errors and use a single bool to
193 // control all perf timing (some of which can fail to init)
194 goto exit;
195 }
196
197 // Make sure we are in the right state
198 if (CS_STOPPED != pState->eState && CS_RUNNING != pState->eState)
199 {
200 assert(FALSE);
201 goto exit;
202 }
203
204 iElapsedTime = pState->iElapsedTime;
205 if (CS_RUNNING == pState->eState)
206 {
207 // Must take a "checkpoint" time reading
208 fResult = AccumulateTime(pState, &iElapsedTime);
209 if (FALSE == fResult)
210 goto exit;
211 }
212
213 // Convert clock ticks to nanoseconds.
214 // Use floating point for ease of math. If your platform really blows
215 // with floating point, replace this with appropriate integer calculation
216 // based on your clock interval.
217 pResults->iElapsedTime = (PERFTIMERTIME)((float)iElapsedTime *
218 ((float)NANOSECONDS_PER_SECOND / (float)CLOCKS_PER_SEC));
219 pResults->iTicksPerSecond = CLOCKS_PER_SEC;
220 pResults->iZeroTimeIntervals = pState->iZeroTimeIntervals;
221 fResult = TRUE;
222
223 exit:
224 return fResult;
225 } // PerfTimerGetResults
226
227
228
PerfTimerCopyStartTime(PERFTIMERSTATE * pDestPerfTimer,PERFTIMERSTATE * pSrcPerfTimer)229 Bool PerfTimerCopyStartTime(PERFTIMERSTATE *pDestPerfTimer,
230 PERFTIMERSTATE *pSrcPerfTimer)
231 {
232 Bool fResult = FALSE;
233
234 if (NULL == pDestPerfTimer)
235 {
236 TraceResult(E_INVALIDARG);
237 goto exit;
238 }
239
240 if (NULL == pSrcPerfTimer)
241 {
242 TraceResult(E_INVALIDARG);
243 goto exit;
244 }
245
246 // Check that both timers are in proper state - both must be running
247 if (CS_RUNNING != pDestPerfTimer->eState)
248 {
249 TraceResult(WM_E_INVALIDSTATE);
250 goto exit;
251 }
252
253 if (CS_RUNNING != pSrcPerfTimer->eState)
254 {
255 TraceResult(WM_E_INVALIDSTATE);
256 goto exit;
257 }
258
259 if (0 != pDestPerfTimer->iElapsedTime)
260 {
261 // If iElapsedTime is non-zero, caller won't get what he is expecting
262 // when he calls PerfTimerGetResults
263 TraceResult(WM_E_INVALIDSTATE);
264 goto exit;
265 }
266
267 pDestPerfTimer->iPrevStartTime = pSrcPerfTimer->iPrevStartTime;
268 fResult = TRUE;
269
270 exit:
271 return fResult;
272 } // PerfTimerCopyStartTime
273
274 #endif // DISABLE_PERF_MEASUREMENT
275