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