blob: f22591d4778dffabd8d56c928c70ab219ed9d79d [file] [log] [blame]
Paul Bakker5121ce52009-01-03 21:22:43 +00001/*
2 * Portable interface to the CPU cycle counter
3 *
Paul Bakkerf2561b32014-02-06 15:11:55 +01004 * Copyright (C) 2006-2014, Brainspark B.V.
Paul Bakkerb96f1542010-07-18 20:36:00 +00005 *
6 * This file is part of PolarSSL (http://www.polarssl.org)
Paul Bakker84f12b72010-07-18 10:13:04 +00007 * Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
Paul Bakkerb96f1542010-07-18 20:36:00 +00008 *
Paul Bakker77b385e2009-07-28 17:23:11 +00009 * All rights reserved.
Paul Bakkere0ccd0a2009-01-04 16:27:10 +000010 *
Paul Bakker5121ce52009-01-03 21:22:43 +000011 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License along
22 * with this program; if not, write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 */
25
Manuel Pégourié-Gonnardcef4ad22014-04-29 12:39:06 +020026#if !defined(POLARSSL_CONFIG_FILE)
Paul Bakker40e46942009-01-03 21:51:57 +000027#include "polarssl/config.h"
Manuel Pégourié-Gonnardcef4ad22014-04-29 12:39:06 +020028#else
29#include POLARSSL_CONFIG_FILE
30#endif
Paul Bakker5121ce52009-01-03 21:22:43 +000031
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +010032#if defined(POLARSSL_SELF_TEST) && defined(POLARSSL_PLATFORM_C)
33#include "polarssl/platform.h"
34#else
35#include <stdio.h>
36#define polarssl_printf printf
37#endif
38
Paul Bakkerf2561b32014-02-06 15:11:55 +010039#if defined(POLARSSL_TIMING_C) && !defined(POLARSSL_TIMING_ALT)
Paul Bakker5121ce52009-01-03 21:22:43 +000040
Paul Bakker40e46942009-01-03 21:51:57 +000041#include "polarssl/timing.h"
Paul Bakker5121ce52009-01-03 21:22:43 +000042
Paul Bakkerfa6a6202013-10-28 18:48:30 +010043#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32)
Paul Bakker5121ce52009-01-03 21:22:43 +000044
45#include <windows.h>
46#include <winbase.h>
47
48struct _hr_time
49{
50 LARGE_INTEGER start;
51};
52
53#else
54
55#include <unistd.h>
56#include <sys/types.h>
57#include <sys/time.h>
58#include <signal.h>
59#include <time.h>
60
61struct _hr_time
62{
63 struct timeval start;
64};
65
66#endif
67
Paul Bakkerbb0139c2012-10-31 09:53:08 +000068#if !defined(POLARSSL_HAVE_HARDCLOCK) && defined(POLARSSL_HAVE_ASM) && \
Manuel Pégourié-Gonnard487588d2014-03-27 19:02:07 +010069 (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
Paul Bakker5121ce52009-01-03 21:22:43 +000070
Paul Bakkerbb0139c2012-10-31 09:53:08 +000071#define POLARSSL_HAVE_HARDCLOCK
72
Paul Bakker5121ce52009-01-03 21:22:43 +000073unsigned long hardclock( void )
74{
75 unsigned long tsc;
76 __asm rdtsc
77 __asm mov [tsc], eax
78 return( tsc );
79}
Paul Bakkerbb0139c2012-10-31 09:53:08 +000080#endif
Paul Bakker5121ce52009-01-03 21:22:43 +000081
Paul Bakkerbb0139c2012-10-31 09:53:08 +000082#if !defined(POLARSSL_HAVE_HARDCLOCK) && defined(POLARSSL_HAVE_ASM) && \
83 defined(__GNUC__) && defined(__i386__)
84
85#define POLARSSL_HAVE_HARDCLOCK
Paul Bakker5121ce52009-01-03 21:22:43 +000086
87unsigned long hardclock( void )
88{
Paul Bakkerca410102011-10-19 14:27:36 +000089 unsigned long lo, hi;
Manuel Pégourié-Gonnardd6aebe12014-03-27 21:15:40 +010090 asm volatile( "rdtsc" : "=a" (lo), "=d" (hi) );
Paul Bakkerca410102011-10-19 14:27:36 +000091 return( lo );
Paul Bakker5121ce52009-01-03 21:22:43 +000092}
Paul Bakkerbb0139c2012-10-31 09:53:08 +000093#endif
Paul Bakker5121ce52009-01-03 21:22:43 +000094
Paul Bakkerbb0139c2012-10-31 09:53:08 +000095#if !defined(POLARSSL_HAVE_HARDCLOCK) && defined(POLARSSL_HAVE_ASM) && \
96 defined(__GNUC__) && (defined(__amd64__) || defined(__x86_64__))
97
98#define POLARSSL_HAVE_HARDCLOCK
Paul Bakker5121ce52009-01-03 21:22:43 +000099
100unsigned long hardclock( void )
101{
102 unsigned long lo, hi;
Manuel Pégourié-Gonnardd6aebe12014-03-27 21:15:40 +0100103 asm volatile( "rdtsc" : "=a" (lo), "=d" (hi) );
Paul Bakker5121ce52009-01-03 21:22:43 +0000104 return( lo | (hi << 32) );
105}
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000106#endif
Paul Bakker5121ce52009-01-03 21:22:43 +0000107
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000108#if !defined(POLARSSL_HAVE_HARDCLOCK) && defined(POLARSSL_HAVE_ASM) && \
109 defined(__GNUC__) && (defined(__powerpc__) || defined(__ppc__))
110
111#define POLARSSL_HAVE_HARDCLOCK
Paul Bakker5121ce52009-01-03 21:22:43 +0000112
113unsigned long hardclock( void )
114{
115 unsigned long tbl, tbu0, tbu1;
116
117 do
118 {
Manuel Pégourié-Gonnardd6aebe12014-03-27 21:15:40 +0100119 asm volatile( "mftbu %0" : "=r" (tbu0) );
120 asm volatile( "mftb %0" : "=r" (tbl ) );
121 asm volatile( "mftbu %0" : "=r" (tbu1) );
Paul Bakker5121ce52009-01-03 21:22:43 +0000122 }
123 while( tbu0 != tbu1 );
124
125 return( tbl );
126}
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000127#endif
Paul Bakker5121ce52009-01-03 21:22:43 +0000128
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000129#if !defined(POLARSSL_HAVE_HARDCLOCK) && defined(POLARSSL_HAVE_ASM) && \
130 defined(__GNUC__) && defined(__sparc64__)
131
132#if defined(__OpenBSD__)
133#warning OpenBSD does not allow access to tick register using software version instead
Paul Bakker5121ce52009-01-03 21:22:43 +0000134#else
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000135#define POLARSSL_HAVE_HARDCLOCK
136
137unsigned long hardclock( void )
138{
139 unsigned long tick;
Manuel Pégourié-Gonnardd6aebe12014-03-27 21:15:40 +0100140 asm volatile( "rdpr %%tick, %0;" : "=&r" (tick) );
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000141 return( tick );
142}
143#endif
144#endif
145
146#if !defined(POLARSSL_HAVE_HARDCLOCK) && defined(POLARSSL_HAVE_ASM) && \
147 defined(__GNUC__) && defined(__sparc__) && !defined(__sparc64__)
148
149#define POLARSSL_HAVE_HARDCLOCK
Paul Bakker5121ce52009-01-03 21:22:43 +0000150
151unsigned long hardclock( void )
152{
153 unsigned long tick;
Manuel Pégourié-Gonnardd6aebe12014-03-27 21:15:40 +0100154 asm volatile( ".byte 0x83, 0x41, 0x00, 0x00" );
155 asm volatile( "mov %%g1, %0" : "=r" (tick) );
Paul Bakker5121ce52009-01-03 21:22:43 +0000156 return( tick );
157}
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000158#endif
Paul Bakker5121ce52009-01-03 21:22:43 +0000159
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000160#if !defined(POLARSSL_HAVE_HARDCLOCK) && defined(POLARSSL_HAVE_ASM) && \
161 defined(__GNUC__) && defined(__alpha__)
162
163#define POLARSSL_HAVE_HARDCLOCK
Paul Bakker5121ce52009-01-03 21:22:43 +0000164
165unsigned long hardclock( void )
166{
167 unsigned long cc;
Manuel Pégourié-Gonnardd6aebe12014-03-27 21:15:40 +0100168 asm volatile( "rpcc %0" : "=r" (cc) );
Paul Bakker5121ce52009-01-03 21:22:43 +0000169 return( cc & 0xFFFFFFFF );
170}
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000171#endif
Paul Bakker5121ce52009-01-03 21:22:43 +0000172
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000173#if !defined(POLARSSL_HAVE_HARDCLOCK) && defined(POLARSSL_HAVE_ASM) && \
174 defined(__GNUC__) && defined(__ia64__)
175
176#define POLARSSL_HAVE_HARDCLOCK
Paul Bakker5121ce52009-01-03 21:22:43 +0000177
178unsigned long hardclock( void )
179{
180 unsigned long itc;
Manuel Pégourié-Gonnardd6aebe12014-03-27 21:15:40 +0100181 asm volatile( "mov %0 = ar.itc" : "=r" (itc) );
Paul Bakker5121ce52009-01-03 21:22:43 +0000182 return( itc );
183}
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000184#endif
Paul Bakker5121ce52009-01-03 21:22:43 +0000185
Paul Bakkerfa6a6202013-10-28 18:48:30 +0100186#if !defined(POLARSSL_HAVE_HARDCLOCK) && defined(_MSC_VER) && \
187 !defined(EFIX64) && !defined(EFI32)
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000188
189#define POLARSSL_HAVE_HARDCLOCK
Paul Bakker2eee9022011-04-24 15:28:55 +0000190
191unsigned long hardclock( void )
192{
193 LARGE_INTEGER offset;
Paul Bakkerfa6a6202013-10-28 18:48:30 +0100194
Manuel Pégourié-Gonnard487588d2014-03-27 19:02:07 +0100195 QueryPerformanceCounter( &offset );
Paul Bakker2eee9022011-04-24 15:28:55 +0000196
Manuel Pégourié-Gonnard487588d2014-03-27 19:02:07 +0100197 return (unsigned long)( offset.QuadPart );
Paul Bakker2eee9022011-04-24 15:28:55 +0000198}
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000199#endif
Paul Bakker2eee9022011-04-24 15:28:55 +0000200
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000201#if !defined(POLARSSL_HAVE_HARDCLOCK)
202
203#define POLARSSL_HAVE_HARDCLOCK
Paul Bakker5121ce52009-01-03 21:22:43 +0000204
205static int hardclock_init = 0;
206static struct timeval tv_init;
207
208unsigned long hardclock( void )
209{
210 struct timeval tv_cur;
211
212 if( hardclock_init == 0 )
213 {
214 gettimeofday( &tv_init, NULL );
215 hardclock_init = 1;
216 }
217
218 gettimeofday( &tv_cur, NULL );
219 return( ( tv_cur.tv_sec - tv_init.tv_sec ) * 1000000
220 + ( tv_cur.tv_usec - tv_init.tv_usec ) );
221}
Paul Bakkerbb0139c2012-10-31 09:53:08 +0000222#endif
Paul Bakker5121ce52009-01-03 21:22:43 +0000223
Paul Bakker2eee9022011-04-24 15:28:55 +0000224volatile int alarmed = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000225
Paul Bakkerfa6a6202013-10-28 18:48:30 +0100226#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32)
Paul Bakker5121ce52009-01-03 21:22:43 +0000227
228unsigned long get_timer( struct hr_time *val, int reset )
229{
230 unsigned long delta;
231 LARGE_INTEGER offset, hfreq;
232 struct _hr_time *t = (struct _hr_time *) val;
233
234 QueryPerformanceCounter( &offset );
235 QueryPerformanceFrequency( &hfreq );
236
237 delta = (unsigned long)( ( 1000 *
238 ( offset.QuadPart - t->start.QuadPart ) ) /
239 hfreq.QuadPart );
240
241 if( reset )
242 QueryPerformanceCounter( &t->start );
243
244 return( delta );
245}
246
247DWORD WINAPI TimerProc( LPVOID uElapse )
Manuel Pégourié-Gonnard487588d2014-03-27 19:02:07 +0100248{
Paul Bakker5121ce52009-01-03 21:22:43 +0000249 Sleep( (DWORD) uElapse );
Manuel Pégourié-Gonnard487588d2014-03-27 19:02:07 +0100250 alarmed = 1;
Paul Bakker5121ce52009-01-03 21:22:43 +0000251 return( TRUE );
252}
253
254void set_alarm( int seconds )
Manuel Pégourié-Gonnard487588d2014-03-27 19:02:07 +0100255{
Paul Bakker5121ce52009-01-03 21:22:43 +0000256 DWORD ThreadId;
257
Manuel Pégourié-Gonnard487588d2014-03-27 19:02:07 +0100258 alarmed = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000259 CloseHandle( CreateThread( NULL, 0, TimerProc,
260 (LPVOID) ( seconds * 1000 ), 0, &ThreadId ) );
261}
262
263void m_sleep( int milliseconds )
264{
265 Sleep( milliseconds );
266}
267
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100268#else /* _WIN32 && !EFIX64 && !EFI32 */
Paul Bakker5121ce52009-01-03 21:22:43 +0000269
270unsigned long get_timer( struct hr_time *val, int reset )
271{
272 unsigned long delta;
273 struct timeval offset;
274 struct _hr_time *t = (struct _hr_time *) val;
275
276 gettimeofday( &offset, NULL );
277
278 delta = ( offset.tv_sec - t->start.tv_sec ) * 1000
279 + ( offset.tv_usec - t->start.tv_usec ) / 1000;
280
281 if( reset )
282 {
283 t->start.tv_sec = offset.tv_sec;
284 t->start.tv_usec = offset.tv_usec;
285 }
286
287 return( delta );
288}
289
Paul Bakker49d75672012-09-26 15:22:07 +0000290#if defined(INTEGRITY)
291void m_sleep( int milliseconds )
292{
293 usleep( milliseconds * 1000 );
294}
295
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100296#else /* INTEGRITY */
Paul Bakker49d75672012-09-26 15:22:07 +0000297
Paul Bakker5121ce52009-01-03 21:22:43 +0000298static void sighandler( int signum )
Manuel Pégourié-Gonnard487588d2014-03-27 19:02:07 +0100299{
Paul Bakker5121ce52009-01-03 21:22:43 +0000300 alarmed = 1;
301 signal( signum, sighandler );
302}
303
304void set_alarm( int seconds )
305{
306 alarmed = 0;
307 signal( SIGALRM, sighandler );
308 alarm( seconds );
309}
310
311void m_sleep( int milliseconds )
312{
313 struct timeval tv;
314
315 tv.tv_sec = milliseconds / 1000;
Manuel Pégourié-Gonnarddfbf9c72014-02-20 22:16:43 +0100316 tv.tv_usec = ( milliseconds % 1000 ) * 1000;
Paul Bakker5121ce52009-01-03 21:22:43 +0000317
318 select( 0, NULL, NULL, NULL, &tv );
319}
Paul Bakker49d75672012-09-26 15:22:07 +0000320#endif /* INTEGRITY */
Paul Bakker5121ce52009-01-03 21:22:43 +0000321
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100322#endif /* _WIN32 && !EFIX64 && !EFI32 */
Paul Bakker5121ce52009-01-03 21:22:43 +0000323
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100324#if defined(POLARSSL_SELF_TEST)
325
Manuel Pégourié-Gonnard79e58422014-04-02 18:42:01 +0200326/* To test net_usleep against our functions */
327#if defined(POLARSSL_NET_C)
328#include "polarssl/net.h"
329#endif
330
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100331/*
332 * Checkup routine
Manuel Pégourié-Gonnard0f79bab2014-04-09 09:56:16 +0200333 *
334 * Warning: this is work in progress, some tests may not be reliable enough
335 * yet! False positives may happen.
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100336 */
337int timing_self_test( int verbose )
338{
339 unsigned long cycles, ratio;
340 unsigned long millisecs, secs;
341 int hardfail;
342 struct hr_time hires;
343
344 if( verbose != 0)
345 polarssl_printf( " TIMING tests warning: will take some time!\n" );
346
347 if( verbose != 0 )
348 polarssl_printf( " TIMING test #1 (m_sleep / get_timer): " );
349
350 for( secs = 1; secs <= 3; secs++ )
351 {
352 (void) get_timer( &hires, 1 );
353
Manuel Pégourié-Gonnard79e58422014-04-02 18:42:01 +0200354 m_sleep( 500 * secs );
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100355
356 millisecs = get_timer( &hires, 0 );
357
Manuel Pégourié-Gonnard79e58422014-04-02 18:42:01 +0200358 if( millisecs < 450 * secs || millisecs > 550 * secs )
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100359 {
360 if( verbose != 0 )
361 polarssl_printf( "failed\n" );
362
363 return( 1 );
364 }
365 }
366
367 if( verbose != 0 )
368 polarssl_printf( "passed\n" );
369
370 if( verbose != 0 )
371 polarssl_printf( " TIMING test #2 (set_alarm / get_timer): " );
372
373 for( secs = 1; secs <= 3; secs++ )
374 {
375 (void) get_timer( &hires, 1 );
376
377 set_alarm( secs );
378 while( !alarmed )
379 ;
380
381 millisecs = get_timer( &hires, 0 );
382
383 if( millisecs < 900 * secs || millisecs > 1100 * secs )
384 {
385 if( verbose != 0 )
386 polarssl_printf( "failed\n" );
387
388 return( 1 );
389 }
390 }
391
392 if( verbose != 0 )
393 polarssl_printf( "passed\n" );
394
395 if( verbose != 0 )
396 polarssl_printf( " TIMING test #3 (hardclock / m_sleep ): " );
397
398 /*
399 * Allow one failure for possible counter wrapping.
400 * On a 4Ghz 32-bit machine the cycle counter wraps about once per second;
401 * since the whole test is about 10ms, it shouldn't happen twice in a row.
402 */
403 hardfail = 0;
404
405hard_test:
406 if( hardfail > 1 )
407 {
408 if( verbose != 0 )
409 polarssl_printf( "failed\n" );
410
411 return( 1 );
412 }
413
414 /* Get a reference ratio cycles/ms */
415 cycles = hardclock();
416 m_sleep( 1 );
417 cycles = hardclock() - cycles;
418 ratio = cycles / 1;
419
420 for( millisecs = 2; millisecs <= 4; millisecs++ )
421 {
422 cycles = hardclock();
423 m_sleep( millisecs );
424 cycles = hardclock() - cycles;
425
426 /* Allow variation up to 20% */
427 if( cycles / millisecs < ratio - ratio / 5 ||
428 cycles / millisecs > ratio + ratio / 5 )
429 {
430 hardfail++;
431 goto hard_test;
432 }
433 }
434
435 if( verbose != 0 )
436 polarssl_printf( "passed\n" );
437
438 if( verbose != 0 )
439 polarssl_printf( "\n" );
440
Manuel Pégourié-Gonnard79e58422014-04-02 18:42:01 +0200441#if defined(POLARSSL_NET_C)
442 if( verbose != 0 )
443 polarssl_printf( " TIMING test #4 (net_usleep/ get_timer): " );
444
445 for( secs = 1; secs <= 3; secs++ )
446 {
447 (void) get_timer( &hires, 1 );
448
449 net_usleep( 500000 * secs );
450
451 millisecs = get_timer( &hires, 0 );
452
453 if( millisecs < 450 * secs || millisecs > 550 * secs )
454 {
455 if( verbose != 0 )
456 polarssl_printf( "failed\n" );
457
458 return( 1 );
459 }
460 }
461
462 if( verbose != 0 )
463 polarssl_printf( "passed\n" );
464#endif
465
Manuel Pégourié-Gonnard470fc932014-03-27 20:07:08 +0100466 return( 0 );
467}
468
469#endif /* POLARSSL_SELF_TEST */
470
471#endif /* POLARSSL_TIMING_C && !POLARSSL_TIMING_ALT */