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
160typedef struct UTimer UTimer;
161
162typedef 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
172static    int uprv_initFrequency(UTimer* timer)
173    {
174        return QueryPerformanceFrequency(&timer->placeHolder);
175    }
176static    void uprv_start(UTimer* timer)
177    {
178        QueryPerformanceCounter(&timer->start);
179    }
180static    double uprv_delta(UTimer* timer1, UTimer* timer2){
181        return ((double)(timer2->start.QuadPart - timer1->start.QuadPart))/((double)timer1->placeHolder.QuadPart);
182    }
183static    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
194static    int32_t uprv_initFrequency(UTimer* /*timer*/)
195    {
196        return 0;
197    }
198static    void uprv_start(UTimer* timer)
199    {
200        gettimeofday(&timer->start, 0);
201    }
202static    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    }
209static    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 */
219static inline void U_EXPORT2
220utimer_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 */
233static inline double U_EXPORT2
234utimer_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 */
248static inline double U_EXPORT2
249utimer_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 */
264static inline double U_EXPORT2
265utimer_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