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
158typedef struct UTimer UTimer;
159
160typedef 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
170static    int uprv_initFrequency(UTimer* timer)
171    {
172        return QueryPerformanceFrequency(&timer->placeHolder);
173    }
174static    void uprv_start(UTimer* timer)
175    {
176        QueryPerformanceCounter(&timer->start);
177    }
178static    double uprv_delta(UTimer* timer1, UTimer* timer2){
179        return ((double)(timer2->start.QuadPart - timer1->start.QuadPart))/((double)timer1->placeHolder.QuadPart);
180    }
181static    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
192static    int32_t uprv_initFrequency(UTimer* /*timer*/)
193    {
194        return 0;
195    }
196static    void uprv_start(UTimer* timer)
197    {
198        gettimeofday(&timer->start, 0);
199    }
200static    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    }
207static    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 */
217static inline void U_EXPORT2
218utimer_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 */
231static inline double U_EXPORT2
232utimer_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 */
246static inline double U_EXPORT2
247utimer_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 */
262static inline double U_EXPORT2
263utimer_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