1 /*
2 ************************************************************************
3 * Copyright (c) 1997-2012, International Business Machines
4 * Corporation and others.  All Rights Reserved.
5 ************************************************************************
6 */
7 
8 #ifndef _UTIMER_H
9 #define _UTIMER_H
10 
11 #include "unicode/utypes.h"
12 
13 #if U_PLATFORM_HAS_WIN32_API
14 #   define VC_EXTRALEAN
15 #   define WIN32_LEAN_AND_MEAN
16 #   include <windows.h>
17 #else
18 #   if U_PLATFORM == U_PF_OS390 && !defined(__UU)
19 #     define __UU  /* Universal Unix - for struct timeval */
20 #   endif
21 #   include <time.h>
22 #   include <sys/time.h>
23 #   include <unistd.h>
24 #endif
25 
26 /**
27  * This API provides functions for performing performance measurement
28  * There are 3 main usage scenarios.
29  * i) Loop until a threshold time is reached:
30  *    Example:
31  *    <code>
32  *      typedef Params Params;
33  *      struct Params{
34  *          UChar* target;
35  *          int32_t targetLen;
36  *          const UChar* source;
37  *          int32_t sourceLen;
38  *          UNormalizationMode mode;
39  *      }
40  *      void NormFn( void* param){
41  *          Params* parameters = ( Params*) param;
42  *          UErrorCode error = U_ZERO_ERROR;
43  *          unorm_normalize(parameters->source, parameters->sourceLen, parameters->mode, 0, parameters->target, parameters->targetLen, &error);
44  *          if(U_FAILURE(error)){
45  *              printf("Normalization failed\n");
46  *          }
47  *      }
48  *
49  *      int main(){
50  *          // time the normalization function
51  *          double timeTaken = 0;
52  *          Params param;
53  *          param.source  // set up the source buffer
54  *          param.target   // set up the target buffer
55  *          .... so on ...
56  *          UTimer timer;
57  *          // time the loop for 10 seconds at least and find out the loop count and time taken
58  *          timeTaken = utimer_loopUntilDone((double)10,(void*) param, NormFn, &loopCount);
59  *      }
60  *     </code>
61  *
62  * ii) Measure the time taken
63  *     Example:
64  *     <code>
65  *      double perfNormalization(NormFn fn,const char* mode,Line* fileLines,int32_t loopCount){
66  *          int  line;
67  *          int  loops;
68  *          UErrorCode error = U_ZERO_ERROR;
69  *          UChar* dest=NULL;
70  *          int32_t destCapacity=0;
71  *          int len =-1;
72  *          double elapsedTime = 0;
73  *          int retVal=0;
74  *
75  *          UChar arr[5000];
76  *          dest=arr;
77  *          destCapacity = 5000;
78  *          UTimer start;
79  *
80  *          // Initialize cache and ensure the data is loaded.
81  *          // This loop checks for errors in Normalization. Once we pass the initialization
82  *          // without errors we can safelly assume that there are no errors while timing the
83  *          // funtion
84  *          for (loops=0; loops<10; loops++) {
85  *              for (line=0; line < gNumFileLines; line++) {
86  *                  if (opt_uselen) {
87  *                      len = fileLines[line].len;
88  *                  }
89  *
90  *                  retVal= fn(fileLines[line].name,len,dest,destCapacity,&error);
91  *      #if U_PLATFORM_HAS_WIN32_API
92  *                  if(retVal==0 ){
93  *                      fprintf(stderr,"Normalization of string in Windows API failed for mode %s. ErrorNo: %i at line number %i\n",mode,GetLastError(),line);
94  *                      return 0;
95  *                  }
96  *      #endif
97  *                  if(U_FAILURE(error)){
98  *                      fprintf(stderr,"Normalization of string in ICU API failed for mode %s. Error: %s at line number %i\n",mode,u_errorName(error),line);
99  *                      return 0;
100  *                  }
101  *
102  *              }
103  *          }
104  *
105  *          //compute the time
106  *
107  *          utimer_getTime(&start);
108  *          for (loops=0; loops<loopCount; loops++) {
109  *              for (line=0; line < gNumFileLines; line++) {
110  *                  if (opt_uselen) {
111  *                      len = fileLines[line].len;
112  *                  }
113  *
114  *                  retVal= fn(fileLines[line].name,len,dest,destCapacity,&error);
115  *
116  *              }
117  *          }
118  *
119  *          return utimer_getElapsedSeconds(&start);
120  *      }
121  *      </code>
122  *
123  * iii) Let a higher level function do the calculation of confidence levels etc.
124  *     Example:
125  *     <code>
126  *       void perf(UTimer* timer, UChar* source, int32_t sourceLen, UChar* target, int32_t targetLen, int32_t loopCount,UNormalizationMode mode, UErrorCode* error){
127  *              int32_t loops;
128  *              for (loops=0; loops<loopCount; loops++) {
129  *                  unorm_normalize(source,sourceLen,target, targetLen,mode,error);
130  *              }
131  *              utimer_getTime(timer);
132  *       }
133  *       void main(const char* argsc, int argv){
134  *          // read the file and setup the data
135  *          // set up options
136  *          UTimer start,timer1, timer2, timer3, timer4;
137  *          double NFDTimeTaken, NFCTimeTaken, FCDTimeTaken;
138  *          switch(opt){
139  *              case 0:
140  *                  utimer_getTime(start);
141  *                  perf(timer1, source,sourceLen, target, targetLen,loopCount,UNORM_NFD,&error);
142  *                  NFDTimeTaken = utimer_getDeltaSeconds(start,timer1);
143  *              case 1:
144  *                  timer_getTime(start);
145  *                  perf(timer2,source,sourceLen,target,targetLen,loopCount,UNORM_NFC,&error);
146  *                  NFCTimeTaken = utimer_getDeltaSeconds(start,timer2);
147  *                  perf(timer3, source, sourceLen, target,targetLen, loopCount, UNORM_FCD,&error);
148  *              // ........so on .............
149  *           }
150  *          // calculate confidence levels etc and print
151  *
152  *       }
153  *
154  *     </code>
155  *
156  */
157 
158 typedef struct UTimer UTimer;
159 
160 typedef void FuntionToBeTimed(void* param);
161 
162 
163 #if U_PLATFORM_HAS_WIN32_API
164 
165     struct UTimer{
166         LARGE_INTEGER start;
167         LARGE_INTEGER placeHolder;
168     };
169 
uprv_initFrequency(UTimer * timer)170 static    int uprv_initFrequency(UTimer* timer)
171     {
172         return QueryPerformanceFrequency(&timer->placeHolder);
173     }
uprv_start(UTimer * timer)174 static    void uprv_start(UTimer* timer)
175     {
176         QueryPerformanceCounter(&timer->start);
177     }
uprv_delta(UTimer * timer1,UTimer * timer2)178 static    double uprv_delta(UTimer* timer1, UTimer* timer2){
179         return ((double)(timer2->start.QuadPart - timer1->start.QuadPart))/((double)timer1->placeHolder.QuadPart);
180     }
uprv_compareFrequency(UTimer * timer1,UTimer * timer2)181 static    UBool uprv_compareFrequency(UTimer* timer1, UTimer* timer2){
182         return (timer1->placeHolder.QuadPart == timer2->placeHolder.QuadPart);
183     }
184 
185 #else
186 
187     struct UTimer{
188         struct timeval start;
189         struct timeval placeHolder;
190     };
191 
uprv_initFrequency(UTimer *)192 static    int32_t uprv_initFrequency(UTimer* /*timer*/)
193     {
194         return 0;
195     }
uprv_start(UTimer * timer)196 static    void uprv_start(UTimer* timer)
197     {
198         gettimeofday(&timer->start, 0);
199     }
uprv_delta(UTimer * timer1,UTimer * timer2)200 static    double uprv_delta(UTimer* timer1, UTimer* timer2){
201         double t1, t2;
202 
203         t1 =  (double)timer1->start.tv_sec + (double)timer1->start.tv_usec/(1000*1000);
204         t2 =  (double)timer2->start.tv_sec + (double)timer2->start.tv_usec/(1000*1000);
205         return (t2-t1);
206     }
uprv_compareFrequency(UTimer *,UTimer *)207 static    UBool uprv_compareFrequency(UTimer* /*timer1*/, UTimer* /*timer2*/){
208         return TRUE;
209     }
210 
211 #endif
212 /**
213  * Intializes the timer with the current time
214  *
215  * @param timer A pointer to UTimer struct to recieve the current time
216  */
217 static inline void U_EXPORT2
utimer_getTime(UTimer * timer)218 utimer_getTime(UTimer* timer){
219     uprv_initFrequency(timer);
220     uprv_start(timer);
221 }
222 
223 /**
224  * Returns the difference in times between timer1 and timer2 by subtracting
225  * timer1's time from timer2's time
226  *
227  * @param timer1 A pointer to UTimer struct to be used as starting time
228  * @param timer2 A pointer to UTimer struct to be used as end time
229  * @return Time in seconds
230  */
231 static inline double U_EXPORT2
utimer_getDeltaSeconds(UTimer * timer1,UTimer * timer2)232 utimer_getDeltaSeconds(UTimer* timer1, UTimer* timer2){
233     if(uprv_compareFrequency(timer1,timer2)){
234         return uprv_delta(timer1,timer2);
235     }
236     /* got error return -1 */
237     return -1;
238 }
239 
240 /**
241  * Returns the time elapsed from the starting time represented by the
242  * UTimer struct pointer passed
243  * @param timer A pointer to UTimer struct to be used as starting time
244  * @return Time elapsed in seconds
245  */
246 static inline double U_EXPORT2
utimer_getElapsedSeconds(UTimer * timer)247 utimer_getElapsedSeconds(UTimer* timer){
248     UTimer temp;
249     utimer_getTime(&temp);
250     return uprv_delta(timer,&temp);
251 }
252 
253 /**
254  * Executes the function pointed to for a given time and returns exact time
255  * taken and number of iterations of the loop
256  * @param thresholTimeVal
257  * @param loopCount output param to recieve the number of iterations
258  * @param fn    The funtion to be executed
259  * @param param Parameters to be passed to the fn
260  * @return the time elapsed in seconds
261  */
262 static inline double U_EXPORT2
utimer_loopUntilDone(double thresholdTimeVal,int32_t * loopCount,FuntionToBeTimed fn,void * param)263 utimer_loopUntilDone(double thresholdTimeVal,
264                      int32_t* loopCount,
265                      FuntionToBeTimed fn,
266                      void* param){
267     UTimer timer;
268     double currentVal=0;
269     *loopCount = 0;
270     utimer_getTime(&timer);
271     for(;currentVal<thresholdTimeVal;){
272         fn(param);
273         currentVal = utimer_getElapsedSeconds(&timer);
274         (*loopCount)++;
275     }
276     return currentVal;
277 }
278 
279 #endif
280 
281