mbed TLS library
Dependents: HTTPClient-SSL WS_SERVER
timing.c
00001 /* 00002 * Portable interface to the CPU cycle counter 00003 * 00004 * Copyright (C) 2006-2014, ARM Limited, All Rights Reserved 00005 * 00006 * This file is part of mbed TLS (https://tls.mbed.org) 00007 * 00008 * This program is free software; you can redistribute it and/or modify 00009 * it under the terms of the GNU General Public License as published by 00010 * the Free Software Foundation; either version 2 of the License, or 00011 * (at your option) any later version. 00012 * 00013 * This program is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 * GNU General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU General Public License along 00019 * with this program; if not, write to the Free Software Foundation, Inc., 00020 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 00021 */ 00022 00023 #if !defined(POLARSSL_CONFIG_FILE) 00024 #include "polarssl/config.h" 00025 #else 00026 #include POLARSSL_CONFIG_FILE 00027 #endif 00028 00029 #if defined(POLARSSL_SELF_TEST) && defined(POLARSSL_PLATFORM_C) 00030 #include "polarssl/platform.h" 00031 #else 00032 #include <stdio.h> 00033 #define polarssl_printf printf 00034 #endif 00035 00036 #if defined(POLARSSL_TIMING_C) && !defined(POLARSSL_TIMING_ALT) 00037 00038 #include "polarssl/timing.h" 00039 00040 #if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) 00041 00042 #include <windows.h> 00043 #include <winbase.h> 00044 00045 struct _hr_time 00046 { 00047 LARGE_INTEGER start; 00048 }; 00049 00050 #else 00051 00052 #include <unistd.h> 00053 #include <sys/types.h> 00054 #include <sys/time.h> 00055 #include <signal.h> 00056 #include <time.h> 00057 00058 struct _hr_time 00059 { 00060 struct timeval start; 00061 }; 00062 00063 #endif /* _WIN32 && !EFIX64 && !EFI32 */ 00064 00065 #if !defined(POLARSSL_HAVE_HARDCLOCK) && defined(POLARSSL_HAVE_ASM) && \ 00066 ( defined(_MSC_VER) && defined(_M_IX86) ) || defined(__WATCOMC__) 00067 00068 #define POLARSSL_HAVE_HARDCLOCK 00069 00070 unsigned long hardclock( void ) 00071 { 00072 unsigned long tsc; 00073 __asm rdtsc 00074 __asm mov [tsc], eax 00075 return( tsc ); 00076 } 00077 #endif /* !POLARSSL_HAVE_HARDCLOCK && POLARSSL_HAVE_ASM && 00078 ( _MSC_VER && _M_IX86 ) || __WATCOMC__ */ 00079 00080 /* some versions of mingw-64 have 32-bit longs even on x84_64 */ 00081 #if !defined(POLARSSL_HAVE_HARDCLOCK) && defined(POLARSSL_HAVE_ASM) && \ 00082 defined(__GNUC__) && ( defined(__i386__) || ( \ 00083 ( defined(__amd64__) || defined( __x86_64__) ) && __SIZEOF_LONG__ == 4 ) ) 00084 00085 #define POLARSSL_HAVE_HARDCLOCK 00086 00087 unsigned long hardclock( void ) 00088 { 00089 unsigned long lo, hi; 00090 asm volatile( "rdtsc" : "=a" (lo), "=d" (hi) ); 00091 return( lo ); 00092 } 00093 #endif /* !POLARSSL_HAVE_HARDCLOCK && POLARSSL_HAVE_ASM && 00094 __GNUC__ && __i386__ */ 00095 00096 #if !defined(POLARSSL_HAVE_HARDCLOCK) && defined(POLARSSL_HAVE_ASM) && \ 00097 defined(__GNUC__) && ( defined(__amd64__) || defined(__x86_64__) ) 00098 00099 #define POLARSSL_HAVE_HARDCLOCK 00100 00101 unsigned long hardclock( void ) 00102 { 00103 unsigned long lo, hi; 00104 asm volatile( "rdtsc" : "=a" (lo), "=d" (hi) ); 00105 return( lo | ( hi << 32 ) ); 00106 } 00107 #endif /* !POLARSSL_HAVE_HARDCLOCK && POLARSSL_HAVE_ASM && 00108 __GNUC__ && ( __amd64__ || __x86_64__ ) */ 00109 00110 #if !defined(POLARSSL_HAVE_HARDCLOCK) && defined(POLARSSL_HAVE_ASM) && \ 00111 defined(__GNUC__) && ( defined(__powerpc__) || defined(__ppc__) ) 00112 00113 #define POLARSSL_HAVE_HARDCLOCK 00114 00115 unsigned long hardclock( void ) 00116 { 00117 unsigned long tbl, tbu0, tbu1; 00118 00119 do 00120 { 00121 asm volatile( "mftbu %0" : "=r" (tbu0) ); 00122 asm volatile( "mftb %0" : "=r" (tbl ) ); 00123 asm volatile( "mftbu %0" : "=r" (tbu1) ); 00124 } 00125 while( tbu0 != tbu1 ); 00126 00127 return( tbl ); 00128 } 00129 #endif /* !POLARSSL_HAVE_HARDCLOCK && POLARSSL_HAVE_ASM && 00130 __GNUC__ && ( __powerpc__ || __ppc__ ) */ 00131 00132 #if !defined(POLARSSL_HAVE_HARDCLOCK) && defined(POLARSSL_HAVE_ASM) && \ 00133 defined(__GNUC__) && defined(__sparc64__) 00134 00135 #if defined(__OpenBSD__) 00136 #warning OpenBSD does not allow access to tick register using software version instead 00137 #else 00138 #define POLARSSL_HAVE_HARDCLOCK 00139 00140 unsigned long hardclock( void ) 00141 { 00142 unsigned long tick; 00143 asm volatile( "rdpr %%tick, %0;" : "=&r" (tick) ); 00144 return( tick ); 00145 } 00146 #endif /* __OpenBSD__ */ 00147 #endif /* !POLARSSL_HAVE_HARDCLOCK && POLARSSL_HAVE_ASM && 00148 __GNUC__ && __sparc64__ */ 00149 00150 #if !defined(POLARSSL_HAVE_HARDCLOCK) && defined(POLARSSL_HAVE_ASM) && \ 00151 defined(__GNUC__) && defined(__sparc__) && !defined(__sparc64__) 00152 00153 #define POLARSSL_HAVE_HARDCLOCK 00154 00155 unsigned long hardclock( void ) 00156 { 00157 unsigned long tick; 00158 asm volatile( ".byte 0x83, 0x41, 0x00, 0x00" ); 00159 asm volatile( "mov %%g1, %0" : "=r" (tick) ); 00160 return( tick ); 00161 } 00162 #endif /* !POLARSSL_HAVE_HARDCLOCK && POLARSSL_HAVE_ASM && 00163 __GNUC__ && __sparc__ && !__sparc64__ */ 00164 00165 #if !defined(POLARSSL_HAVE_HARDCLOCK) && defined(POLARSSL_HAVE_ASM) && \ 00166 defined(__GNUC__) && defined(__alpha__) 00167 00168 #define POLARSSL_HAVE_HARDCLOCK 00169 00170 unsigned long hardclock( void ) 00171 { 00172 unsigned long cc; 00173 asm volatile( "rpcc %0" : "=r" (cc) ); 00174 return( cc & 0xFFFFFFFF ); 00175 } 00176 #endif /* !POLARSSL_HAVE_HARDCLOCK && POLARSSL_HAVE_ASM && 00177 __GNUC__ && __alpha__ */ 00178 00179 #if !defined(POLARSSL_HAVE_HARDCLOCK) && defined(POLARSSL_HAVE_ASM) && \ 00180 defined(__GNUC__) && defined(__ia64__) 00181 00182 #define POLARSSL_HAVE_HARDCLOCK 00183 00184 unsigned long hardclock( void ) 00185 { 00186 unsigned long itc; 00187 asm volatile( "mov %0 = ar.itc" : "=r" (itc) ); 00188 return( itc ); 00189 } 00190 #endif /* !POLARSSL_HAVE_HARDCLOCK && POLARSSL_HAVE_ASM && 00191 __GNUC__ && __ia64__ */ 00192 00193 #if !defined(POLARSSL_HAVE_HARDCLOCK) && defined(_MSC_VER) && \ 00194 !defined(EFIX64) && !defined(EFI32) 00195 00196 #define POLARSSL_HAVE_HARDCLOCK 00197 00198 unsigned long hardclock( void ) 00199 { 00200 LARGE_INTEGER offset; 00201 00202 QueryPerformanceCounter( &offset ); 00203 00204 return( (unsigned long)( offset.QuadPart ) ); 00205 } 00206 #endif /* !POLARSSL_HAVE_HARDCLOCK && _MSC_VER && !EFIX64 && !EFI32 */ 00207 00208 #if !defined(POLARSSL_HAVE_HARDCLOCK) 00209 00210 #define POLARSSL_HAVE_HARDCLOCK 00211 00212 static int hardclock_init = 0; 00213 static struct timeval tv_init; 00214 00215 unsigned long hardclock( void ) 00216 { 00217 struct timeval tv_cur; 00218 00219 if( hardclock_init == 0 ) 00220 { 00221 gettimeofday( &tv_init, NULL ); 00222 hardclock_init = 1; 00223 } 00224 00225 gettimeofday( &tv_cur, NULL ); 00226 return( ( tv_cur.tv_sec - tv_init.tv_sec ) * 1000000 00227 + ( tv_cur.tv_usec - tv_init.tv_usec ) ); 00228 } 00229 #endif /* !POLARSSL_HAVE_HARDCLOCK */ 00230 00231 volatile int alarmed = 0; 00232 00233 #if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) 00234 00235 unsigned long get_timer( struct hr_time *val, int reset ) 00236 { 00237 unsigned long delta; 00238 LARGE_INTEGER offset, hfreq; 00239 struct _hr_time *t = (struct _hr_time *) val; 00240 00241 QueryPerformanceCounter( &offset ); 00242 QueryPerformanceFrequency( &hfreq ); 00243 00244 delta = (unsigned long)( ( 1000 * 00245 ( offset.QuadPart - t->start.QuadPart ) ) / 00246 hfreq.QuadPart ); 00247 00248 if( reset ) 00249 QueryPerformanceCounter( &t->start ); 00250 00251 return( delta ); 00252 } 00253 00254 /* It's OK to use a global because alarm() is supposed to be global anyway */ 00255 static DWORD alarmMs; 00256 00257 static DWORD WINAPI TimerProc( LPVOID TimerContext ) 00258 { 00259 ((void) TimerContext); 00260 Sleep( alarmMs ); 00261 alarmed = 1; 00262 return( TRUE ); 00263 } 00264 00265 void set_alarm( int seconds ) 00266 { 00267 DWORD ThreadId; 00268 00269 alarmed = 0; 00270 alarmMs = seconds * 1000; 00271 CloseHandle( CreateThread( NULL, 0, TimerProc, NULL, 0, &ThreadId ) ); 00272 } 00273 00274 void m_sleep( int milliseconds ) 00275 { 00276 Sleep( milliseconds ); 00277 } 00278 00279 #else /* _WIN32 && !EFIX64 && !EFI32 */ 00280 00281 unsigned long get_timer( struct hr_time *val, int reset ) 00282 { 00283 unsigned long delta; 00284 struct timeval offset; 00285 struct _hr_time *t = (struct _hr_time *) val; 00286 00287 gettimeofday( &offset, NULL ); 00288 00289 if( reset ) 00290 { 00291 t->start.tv_sec = offset.tv_sec; 00292 t->start.tv_usec = offset.tv_usec; 00293 return( 0 ); 00294 } 00295 00296 delta = ( offset.tv_sec - t->start.tv_sec ) * 1000 00297 + ( offset.tv_usec - t->start.tv_usec ) / 1000; 00298 00299 return( delta ); 00300 } 00301 00302 #if defined(INTEGRITY) 00303 void m_sleep( int milliseconds ) 00304 { 00305 usleep( milliseconds * 1000 ); 00306 } 00307 00308 #else /* INTEGRITY */ 00309 00310 static void sighandler( int signum ) 00311 { 00312 alarmed = 1; 00313 signal( signum, sighandler ); 00314 } 00315 00316 void set_alarm( int seconds ) 00317 { 00318 alarmed = 0; 00319 signal( SIGALRM, sighandler ); 00320 alarm( seconds ); 00321 } 00322 00323 void m_sleep( int milliseconds ) 00324 { 00325 struct timeval tv; 00326 00327 tv.tv_sec = milliseconds / 1000; 00328 tv.tv_usec = ( milliseconds % 1000 ) * 1000; 00329 00330 select( 0, NULL, NULL, NULL, &tv ); 00331 } 00332 #endif /* INTEGRITY */ 00333 00334 #endif /* _WIN32 && !EFIX64 && !EFI32 */ 00335 00336 #if defined(POLARSSL_SELF_TEST) 00337 00338 /* To test net_usleep against our functions */ 00339 #if defined(POLARSSL_NET_C) && defined(POLARSSL_HAVE_TIME) 00340 #include "polarssl/net.h" 00341 #endif 00342 00343 /* 00344 * Busy-waits for the given number of milliseconds. 00345 * Used for testing hardclock. 00346 */ 00347 static void busy_msleep( unsigned long msec ) 00348 { 00349 struct hr_time hires; 00350 unsigned long i = 0; /* for busy-waiting */ 00351 volatile unsigned long j; /* to prevent optimisation */ 00352 00353 (void) get_timer( &hires, 1 ); 00354 00355 while( get_timer( &hires, 0 ) < msec ) 00356 i++; 00357 00358 j = i; 00359 (void) j; 00360 } 00361 00362 /* 00363 * Checkup routine 00364 * 00365 * Warning: this is work in progress, some tests may not be reliable enough 00366 * yet! False positives may happen. 00367 */ 00368 int timing_self_test( int verbose ) 00369 { 00370 unsigned long cycles, ratio; 00371 unsigned long millisecs, secs; 00372 int hardfail; 00373 struct hr_time hires; 00374 00375 if( verbose != 0 ) 00376 polarssl_printf( " TIMING tests note: will take some time!\n" ); 00377 00378 if( verbose != 0 ) 00379 polarssl_printf( " TIMING test #1 (m_sleep / get_timer): " ); 00380 00381 for( secs = 1; secs <= 3; secs++ ) 00382 { 00383 (void) get_timer( &hires, 1 ); 00384 00385 m_sleep( (int)( 500 * secs ) ); 00386 00387 millisecs = get_timer( &hires, 0 ); 00388 00389 if( millisecs < 450 * secs || millisecs > 550 * secs ) 00390 { 00391 if( verbose != 0 ) 00392 polarssl_printf( "failed\n" ); 00393 00394 return( 1 ); 00395 } 00396 } 00397 00398 if( verbose != 0 ) 00399 polarssl_printf( "passed\n" ); 00400 00401 if( verbose != 0 ) 00402 polarssl_printf( " TIMING test #2 (set_alarm / get_timer): " ); 00403 00404 for( secs = 1; secs <= 3; secs++ ) 00405 { 00406 (void) get_timer( &hires, 1 ); 00407 00408 set_alarm( (int) secs ); 00409 while( !alarmed ) 00410 ; 00411 00412 millisecs = get_timer( &hires, 0 ); 00413 00414 if( millisecs < 900 * secs || millisecs > 1100 * secs ) 00415 { 00416 if( verbose != 0 ) 00417 polarssl_printf( "failed\n" ); 00418 00419 return( 1 ); 00420 } 00421 } 00422 00423 if( verbose != 0 ) 00424 polarssl_printf( "passed\n" ); 00425 00426 if( verbose != 0 ) 00427 polarssl_printf( " TIMING test #3 (hardclock / get_timer): " ); 00428 00429 /* 00430 * Allow one failure for possible counter wrapping. 00431 * On a 4Ghz 32-bit machine the cycle counter wraps about once per second; 00432 * since the whole test is about 10ms, it shouldn't happen twice in a row. 00433 */ 00434 hardfail = 0; 00435 00436 hard_test: 00437 if( hardfail > 1 ) 00438 { 00439 if( verbose != 0 ) 00440 polarssl_printf( "failed\n" ); 00441 00442 return( 1 ); 00443 } 00444 00445 /* Get a reference ratio cycles/ms */ 00446 millisecs = 1; 00447 cycles = hardclock(); 00448 busy_msleep( millisecs ); 00449 cycles = hardclock() - cycles; 00450 ratio = cycles / millisecs; 00451 00452 /* Check that the ratio is mostly constant */ 00453 for( millisecs = 2; millisecs <= 4; millisecs++ ) 00454 { 00455 cycles = hardclock(); 00456 busy_msleep( millisecs ); 00457 cycles = hardclock() - cycles; 00458 00459 /* Allow variation up to 20% */ 00460 if( cycles / millisecs < ratio - ratio / 5 || 00461 cycles / millisecs > ratio + ratio / 5 ) 00462 { 00463 hardfail++; 00464 goto hard_test; 00465 } 00466 } 00467 00468 if( verbose != 0 ) 00469 polarssl_printf( "passed\n" ); 00470 00471 #if defined(POLARSSL_NET_C) && defined(POLARSSL_HAVE_TIME) 00472 if( verbose != 0 ) 00473 polarssl_printf( " TIMING test #4 (net_usleep/ get_timer): " ); 00474 00475 for( secs = 1; secs <= 3; secs++ ) 00476 { 00477 (void) get_timer( &hires, 1 ); 00478 00479 net_usleep( 500000 * secs ); 00480 00481 millisecs = get_timer( &hires, 0 ); 00482 00483 if( millisecs < 450 * secs || millisecs > 550 * secs ) 00484 { 00485 if( verbose != 0 ) 00486 polarssl_printf( "failed\n" ); 00487 00488 return( 1 ); 00489 } 00490 } 00491 00492 if( verbose != 0 ) 00493 polarssl_printf( "passed\n" ); 00494 #endif /* POLARSSL_NET_C */ 00495 00496 if( verbose != 0 ) 00497 polarssl_printf( "\n" ); 00498 00499 return( 0 ); 00500 } 00501 00502 #endif /* POLARSSL_SELF_TEST */ 00503 00504 #endif /* POLARSSL_TIMING_C && !POLARSSL_TIMING_ALT */ 00505
Generated on Tue Jul 12 2022 13:50:39 by 1.7.2