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