summaryrefslogtreecommitdiffstats
path: root/intl/icu/source/tools/ctestfw/unicode/utimer.h
blob: 10f80833cba266459748658c759672d6e174fa89 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
/*
************************************************************************
* Copyright (c) 1997-2012, International Business Machines
* Corporation and others.  All Rights Reserved.
************************************************************************
*/

#ifndef _UTIMER_H
#define _UTIMER_H

#include "unicode/utypes.h"

#if U_PLATFORM_USES_ONLY_WIN32_API
#   define VC_EXTRALEAN
#   define WIN32_LEAN_AND_MEAN
#   include <windows.h>
#else
#   if U_PLATFORM == U_PF_OS390 && !defined(__UU)
#     define __UU  /* Universal Unix - for struct timeval */
#   endif
#   include <time.h>
#   include <sys/time.h> 
#   include <unistd.h> 
#endif

/**
 * This API provides functions for performing performance measurement
 * There are 3 main usage scenarios.
 * i) Loop until a threshold time is reached:
 *    Example:
 *    <code>
 *      typedef Params Params;
 *      struct Params{
 *          char16_t* target;
 *          int32_t targetLen;
 *          const char16_t* source;
 *          int32_t sourceLen;
 *          UNormalizationMode mode;
 *      }
 *      void NormFn( void* param){
 *          Params* parameters = ( Params*) param;
 *          UErrorCode error = U_ZERO_ERROR;
 *          unorm_normalize(parameters->source, parameters->sourceLen, parameters->mode, 0, parameters->target, parameters->targetLen, &error);
 *          if(U_FAILURE(error)){
 *              printf("Normalization failed\n");
 *          }
 *      }
 *  
 *      int main(){
 *          // time the normalization function 
 *          double timeTaken = 0;
 *          Params param;
 *          param.source  // set up the source buffer 
 *          param.target   // set up the target buffer
 *          .... so on ...
 *          UTimer timer;
 *          // time the loop for 10 seconds at least and find out the loop count and time taken
 *          timeTaken = utimer_loopUntilDone((double)10,(void*) param, NormFn, &loopCount);
 *      }
 *     </code>
 *
 * ii) Measure the time taken
 *     Example:
 *     <code>
 *      double perfNormalization(NormFn fn,const char* mode,Line* fileLines,int32_t loopCount){
 *          int  line;
 *          int  loops;
 *          UErrorCode error = U_ZERO_ERROR;
 *          char16_t* dest=nullptr;
 *          int32_t destCapacity=0;
 *          int len =-1;
 *          double elapsedTime = 0; 
 *          int retVal=0;
 *
 *          char16_t arr[5000];
 *          dest=arr;
 *          destCapacity = 5000;
 *          UTimer start;
 *
 *          // Initialize cache and ensure the data is loaded.
 *          // This loop checks for errors in Normalization. Once we pass the initialization
 *          // without errors we can safelly assume that there are no errors while timing the 
 *          // function
 *          for (loops=0; loops<10; loops++) {
 *              for (line=0; line < gNumFileLines; line++) {
 *                  if (opt_uselen) {
 *                      len = fileLines[line].len;
 *                  }
 *
 *                  retVal= fn(fileLines[line].name,len,dest,destCapacity,&error);
 *      #if U_PLATFORM_HAS_WIN32_API
 *                  if(retVal==0 ){
 *                      fprintf(stderr,"Normalization of string in Windows API failed for mode %s. ErrorNo: %i at line number %i\n",mode,GetLastError(),line);
 *                      return 0;
 *                  }
 *      #endif
 *                  if(U_FAILURE(error)){
 *                      fprintf(stderr,"Normalization of string in ICU API failed for mode %s. Error: %s at line number %i\n",mode,u_errorName(error),line);
 *                      return 0;
 *                  }
 *        
 *              }
 *          }
 *
 *          //compute the time
 *
 *          utimer_getTime(&start);
 *          for (loops=0; loops<loopCount; loops++) {
 *              for (line=0; line < gNumFileLines; line++) {
 *                  if (opt_uselen) {
 *                      len = fileLines[line].len;
 *                  }
 *
 *                  retVal= fn(fileLines[line].name,len,dest,destCapacity,&error);
 *       
 *              }
 *          }
 *
 *          return utimer_getElapsedSeconds(&start);
 *      }
 *      </code>
 *
 * iii) Let a higher level function do the calculation of confidence levels etc.
 *     Example:
 *     <code>
 *       void perf(UTimer* timer, char16_t* source, int32_t sourceLen, char16_t* target, int32_t targetLen, int32_t loopCount,UNormalizationMode mode, UErrorCode* error){
 *              int32_t loops;
 *              for (loops=0; loops<loopCount; loops++) {
 *                  unorm_normalize(source,sourceLen,target, targetLen,mode,error);
 *              }
 *              utimer_getTime(timer);
 *       }
 *       void main(const char* argsc, int argv){
 *          // read the file and setup the data
 *          // set up options
 *          UTimer start,timer1, timer2, timer3, timer4;
 *          double NFDTimeTaken, NFCTimeTaken, FCDTimeTaken;
 *          switch(opt){
 *              case 0:
 *                  utimer_getTime(start);
 *                  perf(timer1, source,sourceLen, target, targetLen,loopCount,UNORM_NFD,&error);
 *                  NFDTimeTaken = utimer_getDeltaSeconds(start,timer1);
 *              case 1:
 *                  timer_getTime(start);
 *                  perf(timer2,source,sourceLen,target,targetLen,loopCount,UNORM_NFC,&error);
 *                  NFCTimeTaken = utimer_getDeltaSeconds(start,timer2);
 *                  perf(timer3, source, sourceLen, target,targetLen, loopCount, UNORM_FCD,&error);
 *              // ........so on .............          
 *           }
 *          // calculate confidence levels etc and print            
 *
 *       }
 *           
 *     </code>
 *      
 */

typedef struct UTimer UTimer;

typedef void FunctionToBeTimed(void* param);


#if U_PLATFORM_USES_ONLY_WIN32_API

    struct UTimer{
        LARGE_INTEGER start;
        LARGE_INTEGER placeHolder;
    };      
        
static    int uprv_initFrequency(UTimer* timer)
    {
        return QueryPerformanceFrequency(&timer->placeHolder);
    }
static    void uprv_start(UTimer* timer)
    {
        QueryPerformanceCounter(&timer->start);
    }
static    double uprv_delta(UTimer* timer1, UTimer* timer2){
        return ((double)(timer2->start.QuadPart - timer1->start.QuadPart))/((double)timer1->placeHolder.QuadPart);
    }
static    UBool uprv_compareFrequency(UTimer* timer1, UTimer* timer2){
        return (timer1->placeHolder.QuadPart == timer2->placeHolder.QuadPart);
    }

#else

    struct UTimer{
        struct timeval start;
        struct timeval placeHolder;
    };
    
static    int32_t uprv_initFrequency(UTimer* /*timer*/)
    {
        return 0;
    }
static    void uprv_start(UTimer* timer)
    {
        gettimeofday(&timer->start, 0);
    }
static    double uprv_delta(UTimer* timer1, UTimer* timer2){
        double t1, t2;

        t1 =  (double)timer1->start.tv_sec + (double)timer1->start.tv_usec/(1000*1000);
        t2 =  (double)timer2->start.tv_sec + (double)timer2->start.tv_usec/(1000*1000);
        return (t2-t1);
    }
static    UBool uprv_compareFrequency(UTimer* /*timer1*/, UTimer* /*timer2*/){
        return true;
    }

#endif
/**
 * Initializes the timer with the current time
 *
 * @param timer A pointer to UTimer struct to receive the current time
 */
static inline void U_EXPORT2
utimer_getTime(UTimer* timer){
    uprv_initFrequency(timer);
    uprv_start(timer);
}

/**
 * Returns the difference in times between timer1 and timer2 by subtracting
 * timer1's time from timer2's time
 *
 * @param timer1 A pointer to UTimer struct to be used as starting time
 * @param timer2 A pointer to UTimer struct to be used as end time
 * @return Time in seconds
 */
static inline double U_EXPORT2
utimer_getDeltaSeconds(UTimer* timer1, UTimer* timer2){
    if(uprv_compareFrequency(timer1,timer2)){
        return uprv_delta(timer1,timer2);
    }
    /* got error return -1 */
    return -1;
}

/**
 * Returns the time elapsed from the starting time represented by the 
 * UTimer struct pointer passed
 * @param timer A pointer to UTimer struct to be used as starting time
 * @return Time elapsed in seconds
 */
static inline double U_EXPORT2
utimer_getElapsedSeconds(UTimer* timer){
    UTimer temp;
    utimer_getTime(&temp);
    return uprv_delta(timer,&temp);
}

/**
 * Executes the function pointed to for a given time and returns exact time
 * taken and number of iterations of the loop
 * @param thresholTimeVal 
 * @param loopCount output param to receive the number of iterations
 * @param fn    The function to be executed
 * @param param Parameters to be passed to the fn
 * @return the time elapsed in seconds
 */
static inline double U_EXPORT2
utimer_loopUntilDone(double thresholdTimeVal,
                     int32_t* loopCount, 
                     FunctionToBeTimed fn, 
                     void* param){
    UTimer timer;
    double currentVal=0;
    *loopCount = 0;
    utimer_getTime(&timer);
    for(;currentVal<thresholdTimeVal;){
        fn(param);
        currentVal = utimer_getElapsedSeconds(&timer);
        (*loopCount)++;
    }
    return currentVal;
}

#endif