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 172 static int uprv_initFrequency(UTimer* timer) 173 { 174 return QueryPerformanceFrequency(&timer->placeHolder); 175 } 176 static void uprv_start(UTimer* timer) 177 { 178 QueryPerformanceCounter(&timer->start); 179 } 180 static double uprv_delta(UTimer* timer1, UTimer* timer2){ 181 return ((double)(timer2->start.QuadPart - timer1->start.QuadPart))/((double)timer1->placeHolder.QuadPart); 182 } 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 194 static int32_t uprv_initFrequency(UTimer* /*timer*/) 195 { 196 return 0; 197 } 198 static void uprv_start(UTimer* timer) 199 { 200 gettimeofday(&timer->start, 0); 201 } 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 } 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 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 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 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 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