mbed TLS library

Dependents:   HTTPClient-SSL WS_SERVER

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers timing.c Source File

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