//========================================================================== // // tm_posix.cxx // // Basic timing test / scaffolding // //========================================================================== // ####ECOSGPLCOPYRIGHTBEGIN#### // ------------------------------------------- // This file is part of eCos, the Embedded Configurable Operating System. // Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. // // eCos is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the Free // Software Foundation; either version 2 or (at your option) any later // version. // // eCos is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License // for more details. // // You should have received a copy of the GNU General Public License // along with eCos; if not, write to the Free Software Foundation, Inc., // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. // // As a special exception, if other files instantiate templates or use // macros or inline functions from this file, or you compile this file // and link it with other works to produce a work based on this file, // this file does not by itself cause the resulting work to be covered by // the GNU General Public License. However the source code for this file // must still be made available in accordance with section (3) of the GNU // General Public License v2. // // This exception does not invalidate any other reasons why a work based // on this file might be covered by the GNU General Public License. // ------------------------------------------- // ####ECOSGPLCOPYRIGHTEND#### //========================================================================== //#####DESCRIPTIONBEGIN#### // // Author(s): gthomas,nickg // Contributors: jlarmour // Date: 1998-10-19 // Description: Very simple kernel timing test //####DESCRIPTIONEND#### //========================================================================== #include #include #include #include #ifdef CYGPKG_KERNEL #include #endif #ifndef CYGPKG_POSIX_SIGNALS #define NA_MSG "No POSIX signals" #elif !defined(CYGPKG_POSIX_TIMERS) #define NA_MSG "No POSIX timers" #elif !defined(CYGPKG_POSIX_PTHREAD) #define NA_MSG "POSIX threads not enabled" #elif !defined(CYGFUN_KERNEL_API_C) #define NA_MSG "Kernel C API not enabled" #elif !defined(CYGSEM_KERNEL_SCHED_MLQUEUE) #define NA_MSG "Kernel mlqueue scheduler not enabled" #elif !defined(CYGVAR_KERNEL_COUNTERS_CLOCK) #define NA_MSG "Kernel clock not enabled" #elif CYGNUM_KERNEL_SCHED_PRIORITIES <= 12 #define NA_MSG "Kernel scheduler properties <= 12" #elif !defined(CYGPKG_POSIX_SEMAPHORES) #define NA_MSG "POSIX semaphores not enabled" #endif //========================================================================== #ifdef NA_MSG extern "C" void cyg_start(void) { CYG_TEST_INIT(); CYG_TEST_NA(NA_MSG); } #else #include #include #include #include #include #include #include #include #include #include #include #include #include #include CYGHWR_MEMORY_LAYOUT_H // POSIX headers #include #include #include #include #include #include //========================================================================== // Define this to see the statistics with the first sample datum removed. // This can expose the effects of caches on the speed of operations. #undef STATS_WITHOUT_FIRST_SAMPLE //========================================================================== // Structure used to keep track of times typedef struct fun_times { cyg_uint32 start; cyg_uint32 end; } fun_times; //========================================================================== #define STACK_SIZE (PTHREAD_STACK_MIN*2) // Defaults #define NTEST_THREADS 16 #define NMUTEXES 32 #define NMBOXES 32 #define NSEMAPHORES 32 #define NTIMERS 32 #define NSAMPLES 32 #define NTHREAD_SWITCHES 128 #define NSCHEDS 128 #define NSAMPLES_SIM 2 #define NTEST_THREADS_SIM 2 #define NTHREAD_SWITCHES_SIM 4 #define NMUTEXES_SIM 2 #define NMBOXES_SIM 2 #define NSEMAPHORES_SIM 2 #define NSCHEDS_SIM 4 #define NTIMERS_SIM 2 //========================================================================== static int nsamples; static int ntest_threads; static int nthread_switches; #ifdef CYGPKG_POSIX_PTHREAD_MUTEX static int nmutexes; #endif static int nmboxes; static int nsemaphores; static int nscheds; static int ntimers; static char stacks[NTEST_THREADS][STACK_SIZE]; static pthread_t threads[NTEST_THREADS]; static int overhead; static sem_t synchro; static fun_times thread_ft[NTEST_THREADS]; static fun_times test2_ft[NTHREAD_SWITCHES]; #ifdef CYGPKG_POSIX_PTHREAD_MUTEX static pthread_mutex_t test_mutexes[NMUTEXES]; static fun_times mutex_ft[NMUTEXES]; static pthread_t mutex_test_thread_handle; #endif #if 0 static cyg_mbox test_mboxes[NMBOXES]; static cyg_handle_t test_mbox_handles[NMBOXES]; static fun_times mbox_ft[NMBOXES]; static cyg_thread mbox_test_thread; static cyg_handle_t mbox_test_thread_handle; #endif static sem_t test_semaphores[NSEMAPHORES]; static fun_times semaphore_ft[NSEMAPHORES]; static pthread_t semaphore_test_thread_handle; static fun_times sched_ft[NSCHEDS]; static timer_t timers[NTIMERS]; static fun_times timer_ft[NTIMERS]; static long rtc_resolution[] = CYGNUM_KERNEL_COUNTERS_RTC_RESOLUTION; static long ns_per_system_clock; #if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_LATENCY) // Data kept by kernel real time clock measuring clock interrupt latency extern cyg_tick_count total_clock_latency, total_clock_interrupts; extern cyg_int32 min_clock_latency, max_clock_latency; extern bool measure_clock_latency; #endif #if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_DSR_LATENCY) extern cyg_tick_count total_clock_dsr_latency, total_clock_dsr_calls; extern cyg_int32 min_clock_dsr_latency, max_clock_dsr_latency; extern bool measure_clock_latency; #endif //========================================================================== void run_sched_tests(void); void run_thread_tests(void); void run_thread_switch_test(void); #ifdef CYGPKG_POSIX_PTHREAD_MUTEX void run_mutex_tests(void); void run_mutex_circuit_test(void); #endif void run_mbox_tests(void); void run_mbox_circuit_test(void); void run_semaphore_tests(void); void run_semaphore_circuit_test(void); void run_timer_tests(void); //========================================================================== #ifndef max #define max(n,m) (m > n ? n : m) #endif //========================================================================== // Wait until a clock tick [real time clock] has passed. This should keep it // from happening again during a measurement, thus minimizing any fluctuations void wait_for_tick(void) { cyg_tick_count_t tv0, tv1; tv0 = cyg_current_time(); while (true) { tv1 = cyg_current_time(); if (tv1 != tv0) break; } } //-------------------------------------------------------------------------- // Display a number of ticks as microseconds // Note: for improved calculation significance, values are kept in ticks*1000 void show_ticks_in_us(cyg_uint32 ticks) { long long ns; ns = (ns_per_system_clock * (long long)ticks) / CYGNUM_KERNEL_COUNTERS_RTC_PERIOD; ns += 5; // for rounding to .01us diag_printf("%5d.%02d", (int)(ns/1000), (int)((ns%1000)/10)); } //-------------------------------------------------------------------------- // // If the kernel is instrumented to measure clock interrupt latency, these // measurements can be drastically perturbed by printing via "diag_printf()" // since that code may run with interrupts disabled for long periods. // // In order to get accurate/reasonable latency figures _for the kernel // primitive functions beint tested_, the kernel's latency measurements // are suspended while the printing actually takes place. // // The measurements are reenabled after the printing, thus allowing for // fair measurements of the kernel primitives, which are not distorted // by the printing mechanisms. #if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_LATENCY) && defined(HAL_CLOCK_LATENCY) void disable_clock_latency_measurement(void) { wait_for_tick(); measure_clock_latency = false; } void enable_clock_latency_measurement(void) { wait_for_tick(); measure_clock_latency = true; } // Ensure that the measurements are reasonable (no startup anomalies) void reset_clock_latency_measurement(void) { disable_clock_latency_measurement(); total_clock_latency = 0; total_clock_interrupts = 0; min_clock_latency = 0x7FFFFFFF; max_clock_latency = 0; #if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_DSR_LATENCY) total_clock_dsr_latency = 0; total_clock_dsr_calls = 0; min_clock_dsr_latency = 0x7FFFFFFF; max_clock_dsr_latency = 0; #endif enable_clock_latency_measurement(); } #else #define disable_clock_latency_measurement() #define enable_clock_latency_measurement() #define reset_clock_latency_measurement() #endif //-------------------------------------------------------------------------- void show_times_hdr(void) { disable_clock_latency_measurement(); diag_printf("\n"); diag_printf(" Confidence\n"); diag_printf(" Ave Min Max Var Ave Min Function\n"); diag_printf(" ====== ====== ====== ====== ========== ========\n"); enable_clock_latency_measurement(); } void show_times_detail(fun_times ft[], int nsamples, char *title, bool ignore_first) { int i, delta, min, max, con_ave, con_min, ave_dev; int start_sample, total_samples; cyg_int32 total, ave; if (ignore_first) { start_sample = 1; total_samples = nsamples-1; } else { start_sample = 0; total_samples = nsamples; } total = 0; min = 0x7FFFFFFF; max = 0; for (i = start_sample; i < nsamples; i++) { if (ft[i].end < ft[i].start) { // Clock wrapped around (timer tick) delta = (ft[i].end+CYGNUM_KERNEL_COUNTERS_RTC_PERIOD) - ft[i].start; } else { delta = ft[i].end - ft[i].start; } delta -= overhead; if (delta < 0) delta = 0; delta *= 1000; total += delta; if (delta < min) min = delta; if (delta > max) max = delta; } ave = total / total_samples; total = 0; ave_dev = 0; for (i = start_sample; i < nsamples; i++) { if (ft[i].end < ft[i].start) { // Clock wrapped around (timer tick) delta = (ft[i].end+CYGNUM_KERNEL_COUNTERS_RTC_PERIOD) - ft[i].start; } else { delta = ft[i].end - ft[i].start; } delta -= overhead; if (delta < 0) delta = 0; delta *= 1000; delta = delta - ave; if (delta < 0) delta = -delta; ave_dev += delta; } ave_dev /= total_samples; con_ave = 0; con_min = 0; for (i = start_sample; i < nsamples; i++) { if (ft[i].end < ft[i].start) { // Clock wrapped around (timer tick) delta = (ft[i].end+CYGNUM_KERNEL_COUNTERS_RTC_PERIOD) - ft[i].start; } else { delta = ft[i].end - ft[i].start; } delta -= overhead; if (delta < 0) delta = 0; delta *= 1000; if ((delta <= (ave+ave_dev)) && (delta >= (ave-ave_dev))) con_ave++; if ((delta <= (min+ave_dev)) && (delta >= (min-ave_dev))) con_min++; } con_ave = (con_ave * 100) / total_samples; con_min = (con_min * 100) / total_samples; show_ticks_in_us(ave); show_ticks_in_us(min); show_ticks_in_us(max); show_ticks_in_us(ave_dev); disable_clock_latency_measurement(); diag_printf(" %3d%% %3d%%", con_ave, con_min); diag_printf(" %s\n", title); enable_clock_latency_measurement(); } void show_times(fun_times ft[], int nsamples, char *title) { show_times_detail(ft, nsamples, title, false); #ifdef STATS_WITHOUT_FIRST_SAMPLE show_times_detail(ft, nsamples, "", true); #endif } //-------------------------------------------------------------------------- void show_test_parameters(void) { disable_clock_latency_measurement(); diag_printf("\nTesting parameters:\n"); diag_printf(" Clock samples: %5d\n", nsamples); diag_printf(" Threads: %5d\n", ntest_threads); diag_printf(" Thread switches: %5d\n", nthread_switches); #ifdef CYGPKG_POSIX_PTHREAD_MUTEX diag_printf(" Mutexes: %5d\n", nmutexes); #endif diag_printf(" Mailboxes: %5d\n", nmboxes); diag_printf(" Semaphores: %5d\n", nsemaphores); diag_printf(" Scheduler operations: %5d\n", nscheds); diag_printf(" Timers: %5d\n", ntimers); diag_printf("\n"); enable_clock_latency_measurement(); } void end_of_test_group(void) { disable_clock_latency_measurement(); diag_printf("\n"); enable_clock_latency_measurement(); } //-------------------------------------------------------------------------- // Compute a name for a thread char * thread_name(char *basename, int indx) { return "<>"; // Not currently used } //-------------------------------------------------------------------------- // test0 - null test, just return void * test0(void *indx) { return indx; } //-------------------------------------------------------------------------- // test3 - loop, yeilding repeatedly and checking for cancellation void * test3(void *indx) { for(;;) { sched_yield(); pthread_testcancel(); } return indx; } //-------------------------------------------------------------------------- // test1 - empty test, simply exit. Last thread signals parent. void * test1( void *indx) { if ((cyg_uint32)indx == (cyg_uint32)(ntest_threads-1)) { sem_post(&synchro); // Signal that last thread is dying } return indx; } //-------------------------------------------------------------------------- // test2 - measure thread switch times void * test2(void *indx) { int i; for (i = 0; i < nthread_switches; i++) { if ((int)indx == 0) { HAL_CLOCK_READ(&test2_ft[i].start); } else { HAL_CLOCK_READ(&test2_ft[i].end); } sched_yield(); } if ((int)indx == 1) { sem_post(&synchro); } return indx; } #ifdef CYGPKG_POSIX_PTHREAD_MUTEX //-------------------------------------------------------------------------- // Full-circuit mutex unlock/lock test void * mutex_test(void * indx) { int i; pthread_mutex_lock(&test_mutexes[0]); for (i = 0; i < nmutexes; i++) { sem_wait(&synchro); wait_for_tick(); // Wait until the next clock tick to minimize aberations HAL_CLOCK_READ(&mutex_ft[i].start); pthread_mutex_unlock(&test_mutexes[0]); pthread_mutex_lock(&test_mutexes[0]); sem_post(&synchro); } return indx; } //-------------------------------------------------------------------------- // Full-circuit mbox put/get test #if 0 void mbox_test(cyg_uint32 indx) { void *item; do { item = cyg_mbox_get(test_mbox_handles[0]); HAL_CLOCK_READ(&mbox_ft[(int)item].end); cyg_semaphore_post(&synchro); } while ((int)item != (nmboxes-1)); cyg_thread_exit(0); } #endif #endif //-------------------------------------------------------------------------- // Full-circuit semaphore post/wait test void * semaphore_test(void * indx) { int i; for (i = 0; i < nsemaphores; i++) { sem_wait(&test_semaphores[0]); HAL_CLOCK_READ(&semaphore_ft[i].end); sem_post(&synchro); } return indx; } //-------------------------------------------------------------------------- // // This set of tests is used to measure kernel primitives that deal with threads // void run_thread_tests(void) { int i; struct sched_param schedparam; pthread_attr_t attr; int policy; void *retval; // Set my priority higher than any I plan to create schedparam.sched_priority = 30; pthread_setschedparam( pthread_self(), SCHED_RR, &schedparam ); // Initiaize thread creation attributes pthread_attr_init( &attr ); pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED ); pthread_attr_setschedpolicy( &attr, SCHED_RR ); schedparam.sched_priority = 10; pthread_attr_setschedparam( &attr, &schedparam ); wait_for_tick(); // Wait until the next clock tick to minimize aberations for (i = 0; i < ntest_threads; i++) { HAL_CLOCK_READ(&thread_ft[i].start); pthread_attr_setstackaddr( &attr, &stacks[i][STACK_SIZE] ); pthread_attr_setstacksize( &attr, STACK_SIZE ); pthread_create( &threads[i], &attr, test0, (void *)i ); HAL_CLOCK_READ(&thread_ft[i].end); } show_times(thread_ft, ntest_threads, "Create thread"); wait_for_tick(); // Wait until the next clock tick to minimize aberations for (i = 0; i < ntest_threads; i++) { HAL_CLOCK_READ(&thread_ft[i].start); sched_yield(); HAL_CLOCK_READ(&thread_ft[i].end); } show_times(thread_ft, ntest_threads, "Yield thread [all lower priority]"); wait_for_tick(); // Wait until the next clock tick to minimize aberations for (i = 0; i < ntest_threads; i++) { HAL_CLOCK_READ(&thread_ft[i].start); schedparam.sched_priority = 11; pthread_attr_setschedparam( &attr, &schedparam ); pthread_setschedparam(threads[i], SCHED_RR, &schedparam); HAL_CLOCK_READ(&thread_ft[i].end); } show_times(thread_ft, ntest_threads, "Set priority"); wait_for_tick(); // Wait until the next clock tick to minimize aberations for (i = 0; i < ntest_threads; i++) { HAL_CLOCK_READ(&thread_ft[i].start); pthread_getschedparam( threads[i], &policy, &schedparam ); HAL_CLOCK_READ(&thread_ft[i].end); } show_times(thread_ft, ntest_threads, "Get priority"); cyg_thread_delay(1); // Let the test threads run wait_for_tick(); // Wait until the next clock tick to minimize aberations for (i = 0; i < ntest_threads; i++) { HAL_CLOCK_READ(&thread_ft[i].start); pthread_join(threads[i], &retval); HAL_CLOCK_READ(&thread_ft[i].end); } show_times(thread_ft, ntest_threads, "Join exited thread"); wait_for_tick(); // Wait until the next clock tick to minimize aberations for (i = 0; i < ntest_threads; i++) { HAL_CLOCK_READ(&thread_ft[i].start); sched_yield(); HAL_CLOCK_READ(&thread_ft[i].end); } show_times(thread_ft, ntest_threads, "Yield [no other] thread"); // Recreate the test set schedparam.sched_priority = 10; pthread_attr_setschedparam( &attr, &schedparam ); for (i = 0; i < ntest_threads; i++) { pthread_attr_setstackaddr( &attr, &stacks[i][STACK_SIZE] ); pthread_attr_setstacksize( &attr, STACK_SIZE ); pthread_create( &threads[i], &attr, test3, (void *)i ); } cyg_thread_delay(1); // Let the test threads run wait_for_tick(); // Wait until the next clock tick to minimize aberations for (i = 0; i < ntest_threads; i++) { HAL_CLOCK_READ(&thread_ft[i].start); pthread_cancel(threads[i]); HAL_CLOCK_READ(&thread_ft[i].end); } show_times(thread_ft, ntest_threads, "Cancel [running] thread"); cyg_thread_delay(1); // Let the test threads do their cancellations wait_for_tick(); // Wait until the next clock tick to minimize aberations for (i = 0; i < ntest_threads; i++) { HAL_CLOCK_READ(&thread_ft[i].start); pthread_join(threads[i], &retval); HAL_CLOCK_READ(&thread_ft[i].end); } show_times(thread_ft, ntest_threads, "Join [cancelled] thread"); // Set my priority lower than any I plan to create schedparam.sched_priority = 5; pthread_setschedparam( pthread_self(), SCHED_RR, &schedparam ); // Set up the end-of-threads synchronizer sem_init(&synchro, 0, 0); schedparam.sched_priority = 10; pthread_attr_setschedparam( &attr, &schedparam ); wait_for_tick(); // Wait until the next clock tick to minimize aberations for (i = 0; i < ntest_threads; i++) { HAL_CLOCK_READ(&thread_ft[i].start); pthread_attr_setstackaddr( &attr, &stacks[i][STACK_SIZE] ); pthread_attr_setstacksize( &attr, STACK_SIZE ); pthread_create( &threads[i], &attr, test2, (void *)i ); HAL_CLOCK_READ(&thread_ft[i].end); } show_times(thread_ft, ntest_threads, "Create [high priority] thread"); sem_wait(&synchro); // Wait for all threads to finish // Make sure they are all dead for (i = 0; i < ntest_threads; i++) { pthread_join(threads[i], &retval); } run_thread_switch_test(); end_of_test_group(); } //-------------------------------------------------------------------------- void run_thread_switch_test(void) { int i; struct sched_param schedparam; pthread_attr_t attr; void *retval; // Set my priority higher than any I plan to create schedparam.sched_priority = 30; pthread_setschedparam( pthread_self(), SCHED_RR, &schedparam ); // Initiaize thread creation attributes pthread_attr_init( &attr ); pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED ); pthread_attr_setschedpolicy( &attr, SCHED_RR ); schedparam.sched_priority = 10; pthread_attr_setschedparam( &attr, &schedparam ); // Set up the end-of-threads synchronizer sem_init(&synchro, 0, 0); // Set up for thread context switch for (i = 0; i < 2; i++) { pthread_attr_setstackaddr( &attr, &stacks[i][STACK_SIZE] ); pthread_attr_setstacksize( &attr, STACK_SIZE ); pthread_create( &threads[i], &attr, test2, (void *)i ); } wait_for_tick(); // Wait until the next clock tick to minimize aberations sem_wait(&synchro); show_times(test2_ft, nthread_switches, "Thread switch"); // Clean up for (i = 0; i < 2; i++) { pthread_join(threads[i], &retval); } } //-------------------------------------------------------------------------- #ifdef CYGPKG_POSIX_PTHREAD_MUTEX void run_mutex_tests(void) { int i; pthread_mutexattr_t attr; pthread_mutexattr_init( &attr ); // Mutex primitives wait_for_tick(); // Wait until the next clock tick to minimize aberations for (i = 0; i < nmutexes; i++) { HAL_CLOCK_READ(&mutex_ft[i].start); pthread_mutex_init(&test_mutexes[i], &attr); HAL_CLOCK_READ(&mutex_ft[i].end); } show_times(mutex_ft, nmutexes, "Init mutex"); wait_for_tick(); // Wait until the next clock tick to minimize aberations for (i = 0; i < nmutexes; i++) { HAL_CLOCK_READ(&mutex_ft[i].start); pthread_mutex_lock(&test_mutexes[i]); HAL_CLOCK_READ(&mutex_ft[i].end); } show_times(mutex_ft, nmutexes, "Lock [unlocked] mutex"); wait_for_tick(); // Wait until the next clock tick to minimize aberations for (i = 0; i < nmutexes; i++) { HAL_CLOCK_READ(&mutex_ft[i].start); pthread_mutex_unlock(&test_mutexes[i]); HAL_CLOCK_READ(&mutex_ft[i].end); } show_times(mutex_ft, nmutexes, "Unlock [locked] mutex"); wait_for_tick(); // Wait until the next clock tick to minimize aberations for (i = 0; i < nmutexes; i++) { HAL_CLOCK_READ(&mutex_ft[i].start); pthread_mutex_trylock(&test_mutexes[i]); HAL_CLOCK_READ(&mutex_ft[i].end); } show_times(mutex_ft, nmutexes, "Trylock [unlocked] mutex"); wait_for_tick(); // Wait until the next clock tick to minimize aberations for (i = 0; i < nmutexes; i++) { HAL_CLOCK_READ(&mutex_ft[i].start); pthread_mutex_trylock(&test_mutexes[i]); HAL_CLOCK_READ(&mutex_ft[i].end); } show_times(mutex_ft, nmutexes, "Trylock [locked] mutex"); // Must unlock mutices before destroying them. for (i = 0; i < nmutexes; i++) { pthread_mutex_unlock(&test_mutexes[i]); } wait_for_tick(); // Wait until the next clock tick to minimize aberations for (i = 0; i < nmutexes; i++) { HAL_CLOCK_READ(&mutex_ft[i].start); pthread_mutex_destroy(&test_mutexes[i]); HAL_CLOCK_READ(&mutex_ft[i].end); } show_times(mutex_ft, nmutexes, "Destroy mutex"); run_mutex_circuit_test(); end_of_test_group(); } //-------------------------------------------------------------------------- void run_mutex_circuit_test(void) { int i; pthread_mutexattr_t mattr; struct sched_param schedparam; pthread_attr_t attr; void *retval; // Set my priority lower than any I plan to create schedparam.sched_priority = 5; pthread_setschedparam( pthread_self(), SCHED_RR, &schedparam ); // Initiaize thread creation attributes pthread_attr_init( &attr ); pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED ); pthread_attr_setschedpolicy( &attr, SCHED_RR ); schedparam.sched_priority = 10; pthread_attr_setschedparam( &attr, &schedparam ); // Set up for full mutex unlock/lock test pthread_mutexattr_init( &mattr ); pthread_mutex_init(&test_mutexes[0], &mattr); sem_init(&synchro, 0, 0); pthread_attr_setstackaddr( &attr, &stacks[0][STACK_SIZE] ); pthread_attr_setstacksize( &attr, STACK_SIZE ); pthread_create( &mutex_test_thread_handle, &attr, mutex_test, (void *)0 ); // Need to raise priority so that this thread will block on the "lock" schedparam.sched_priority = 20; pthread_setschedparam( pthread_self(), SCHED_RR, &schedparam ); for (i = 0; i < nmutexes; i++) { sem_post(&synchro); pthread_mutex_lock(&test_mutexes[0]); HAL_CLOCK_READ(&mutex_ft[i].end); pthread_mutex_unlock(&test_mutexes[0]); sem_wait(&synchro); } pthread_join(mutex_test_thread_handle, &retval); show_times(mutex_ft, nmutexes, "Unlock/Lock mutex"); } #endif //-------------------------------------------------------------------------- // Message queue tests // Currently disabled, pending implementation of POSIX message queues #if 0 void run_mbox_tests(void) { int i, cnt; void *item; // Mailbox primitives wait_for_tick(); // Wait until the next clock tick to minimize aberations for (i = 0; i < nmboxes; i++) { HAL_CLOCK_READ(&mbox_ft[i].start); cyg_mbox_create(&test_mbox_handles[i], &test_mboxes[i]); HAL_CLOCK_READ(&mbox_ft[i].end); } show_times(mbox_ft, nmboxes, "Create mbox"); wait_for_tick(); // Wait until the next clock tick to minimize aberations for (i = 0; i < nmboxes; i++) { HAL_CLOCK_READ(&mbox_ft[i].start); cnt = cyg_mbox_peek(test_mbox_handles[i]); HAL_CLOCK_READ(&mbox_ft[i].end); } show_times(mbox_ft, nmboxes, "Peek [empty] mbox"); #ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT wait_for_tick(); // Wait until the next clock tick to minimize aberations for (i = 0; i < nmboxes; i++) { HAL_CLOCK_READ(&mbox_ft[i].start); cyg_mbox_put(test_mbox_handles[i], (void *)i); HAL_CLOCK_READ(&mbox_ft[i].end); } show_times(mbox_ft, nmboxes, "Put [first] mbox"); wait_for_tick(); // Wait until the next clock tick to minimize aberations for (i = 0; i < nmboxes; i++) { HAL_CLOCK_READ(&mbox_ft[i].start); cnt = cyg_mbox_peek(test_mbox_handles[i]); HAL_CLOCK_READ(&mbox_ft[i].end); } show_times(mbox_ft, nmboxes, "Peek [1 msg] mbox"); wait_for_tick(); // Wait until the next clock tick to minimize aberations for (i = 0; i < nmboxes; i++) { HAL_CLOCK_READ(&mbox_ft[i].start); cyg_mbox_put(test_mbox_handles[i], (void *)i); HAL_CLOCK_READ(&mbox_ft[i].end); } show_times(mbox_ft, nmboxes, "Put [second] mbox"); wait_for_tick(); // Wait until the next clock tick to minimize aberations for (i = 0; i < nmboxes; i++) { HAL_CLOCK_READ(&mbox_ft[i].start); cnt = cyg_mbox_peek(test_mbox_handles[i]); HAL_CLOCK_READ(&mbox_ft[i].end); } show_times(mbox_ft, nmboxes, "Peek [2 msgs] mbox"); wait_for_tick(); // Wait until the next clock tick to minimize aberations for (i = 0; i < nmboxes; i++) { HAL_CLOCK_READ(&mbox_ft[i].start); item = cyg_mbox_get(test_mbox_handles[i]); HAL_CLOCK_READ(&mbox_ft[i].end); } show_times(mbox_ft, nmboxes, "Get [first] mbox"); wait_for_tick(); // Wait until the next clock tick to minimize aberations for (i = 0; i < nmboxes; i++) { HAL_CLOCK_READ(&mbox_ft[i].start); item = cyg_mbox_get(test_mbox_handles[i]); HAL_CLOCK_READ(&mbox_ft[i].end); } show_times(mbox_ft, nmboxes, "Get [second] mbox"); #endif // ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT wait_for_tick(); // Wait until the next clock tick to minimize aberations for (i = 0; i < nmboxes; i++) { HAL_CLOCK_READ(&mbox_ft[i].start); cyg_mbox_tryput(test_mbox_handles[i], (void *)i); HAL_CLOCK_READ(&mbox_ft[i].end); } show_times(mbox_ft, nmboxes, "Tryput [first] mbox"); wait_for_tick(); // Wait until the next clock tick to minimize aberations for (i = 0; i < nmboxes; i++) { HAL_CLOCK_READ(&mbox_ft[i].start); item = cyg_mbox_peek_item(test_mbox_handles[i]); HAL_CLOCK_READ(&mbox_ft[i].end); } show_times(mbox_ft, nmboxes, "Peek item [non-empty] mbox"); wait_for_tick(); // Wait until the next clock tick to minimize aberations for (i = 0; i < nmboxes; i++) { HAL_CLOCK_READ(&mbox_ft[i].start); item = cyg_mbox_tryget(test_mbox_handles[i]); HAL_CLOCK_READ(&mbox_ft[i].end); } show_times(mbox_ft, nmboxes, "Tryget [non-empty] mbox"); wait_for_tick(); // Wait until the next clock tick to minimize aberations for (i = 0; i < nmboxes; i++) { HAL_CLOCK_READ(&mbox_ft[i].start); item = cyg_mbox_peek_item(test_mbox_handles[i]); HAL_CLOCK_READ(&mbox_ft[i].end); } show_times(mbox_ft, nmboxes, "Peek item [empty] mbox"); wait_for_tick(); // Wait until the next clock tick to minimize aberations for (i = 0; i < nmboxes; i++) { HAL_CLOCK_READ(&mbox_ft[i].start); item = cyg_mbox_tryget(test_mbox_handles[i]); HAL_CLOCK_READ(&mbox_ft[i].end); } show_times(mbox_ft, nmboxes, "Tryget [empty] mbox"); wait_for_tick(); // Wait until the next clock tick to minimize aberations for (i = 0; i < nmboxes; i++) { HAL_CLOCK_READ(&mbox_ft[i].start); cyg_mbox_waiting_to_get(test_mbox_handles[i]); HAL_CLOCK_READ(&mbox_ft[i].end); } show_times(mbox_ft, nmboxes, "Waiting to get mbox"); wait_for_tick(); // Wait until the next clock tick to minimize aberations for (i = 0; i < nmboxes; i++) { HAL_CLOCK_READ(&mbox_ft[i].start); cyg_mbox_waiting_to_put(test_mbox_handles[i]); HAL_CLOCK_READ(&mbox_ft[i].end); } show_times(mbox_ft, nmboxes, "Waiting to put mbox"); wait_for_tick(); // Wait until the next clock tick to minimize aberations for (i = 0; i < nmboxes; i++) { HAL_CLOCK_READ(&mbox_ft[i].start); cyg_mbox_delete(test_mbox_handles[i]); HAL_CLOCK_READ(&mbox_ft[i].end); } show_times(mbox_ft, nmboxes, "Delete mbox"); run_mbox_circuit_test(); end_of_test_group(); } //-------------------------------------------------------------------------- void run_mbox_circuit_test(void) { #ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT int i; // Set my priority lower than any I plan to create cyg_thread_set_priority(cyg_thread_self(), 3); // Set up for full mbox put/get test cyg_mbox_create(&test_mbox_handles[0], &test_mboxes[0]); cyg_semaphore_init(&synchro, 0); cyg_thread_create(2, // Priority - just a number mbox_test, // entry 0, // index thread_name("thread", 0), // Name &stacks[0][0], // Stack STACK_SIZE, // Size &mbox_test_thread_handle, // Handle &mbox_test_thread // Thread data structure ); cyg_thread_resume(mbox_test_thread_handle); for (i = 0; i < nmboxes; i++) { wait_for_tick(); // Wait until the next clock tick to minimize aberations HAL_CLOCK_READ(&mbox_ft[i].start); cyg_mbox_put(test_mbox_handles[0], (void *)i); cyg_semaphore_wait(&synchro); } cyg_thread_delete(mbox_test_thread_handle); show_times(mbox_ft, nmboxes, "Put/Get mbox"); #endif } #endif //-------------------------------------------------------------------------- void run_semaphore_tests(void) { int i; int sem_val; // Semaphore primitives wait_for_tick(); // Wait until the next clock tick to minimize aberations for (i = 0; i < nsemaphores; i++) { HAL_CLOCK_READ(&semaphore_ft[i].start); sem_init(&test_semaphores[i], 0, 0); HAL_CLOCK_READ(&semaphore_ft[i].end); } show_times(semaphore_ft, nsemaphores, "Init semaphore"); wait_for_tick(); // Wait until the next clock tick to minimize aberations for (i = 0; i < nsemaphores; i++) { HAL_CLOCK_READ(&semaphore_ft[i].start); sem_post(&test_semaphores[i]); HAL_CLOCK_READ(&semaphore_ft[i].end); } show_times(semaphore_ft, nsemaphores, "Post [0] semaphore"); wait_for_tick(); // Wait until the next clock tick to minimize aberations for (i = 0; i < nsemaphores; i++) { HAL_CLOCK_READ(&semaphore_ft[i].start); sem_wait(&test_semaphores[i]); HAL_CLOCK_READ(&semaphore_ft[i].end); } show_times(semaphore_ft, nsemaphores, "Wait [1] semaphore"); wait_for_tick(); // Wait until the next clock tick to minimize aberations for (i = 0; i < nsemaphores; i++) { HAL_CLOCK_READ(&semaphore_ft[i].start); sem_trywait(&test_semaphores[i]); HAL_CLOCK_READ(&semaphore_ft[i].end); } show_times(semaphore_ft, nsemaphores, "Trywait [0] semaphore"); wait_for_tick(); // Wait until the next clock tick to minimize aberations for (i = 0; i < nsemaphores; i++) { sem_post(&test_semaphores[i]); HAL_CLOCK_READ(&semaphore_ft[i].start); sem_trywait(&test_semaphores[i]); HAL_CLOCK_READ(&semaphore_ft[i].end); } show_times(semaphore_ft, nsemaphores, "Trywait [1] semaphore"); wait_for_tick(); // Wait until the next clock tick to minimize aberations for (i = 0; i < nsemaphores; i++) { HAL_CLOCK_READ(&semaphore_ft[i].start); sem_getvalue(&test_semaphores[i], &sem_val); HAL_CLOCK_READ(&semaphore_ft[i].end); } show_times(semaphore_ft, nsemaphores, "Get value of semaphore"); wait_for_tick(); // Wait until the next clock tick to minimize aberations for (i = 0; i < nsemaphores; i++) { HAL_CLOCK_READ(&semaphore_ft[i].start); sem_destroy(&test_semaphores[i]); HAL_CLOCK_READ(&semaphore_ft[i].end); } show_times(semaphore_ft, nsemaphores, "Destroy semaphore"); run_semaphore_circuit_test(); end_of_test_group(); } //-------------------------------------------------------------------------- void run_semaphore_circuit_test(void) { int i; struct sched_param schedparam; pthread_attr_t attr; void *retval; // Set my priority lower than any I plan to create schedparam.sched_priority = 5; pthread_setschedparam( pthread_self(), SCHED_RR, &schedparam ); // Initiaize thread creation attributes pthread_attr_init( &attr ); pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED ); pthread_attr_setschedpolicy( &attr, SCHED_RR ); schedparam.sched_priority = 10; pthread_attr_setschedparam( &attr, &schedparam ); // Set up for full semaphore post/wait test sem_init(&test_semaphores[0], 0, 0); sem_init(&synchro, 0, 0); pthread_attr_setstackaddr( &attr, &stacks[0][STACK_SIZE] ); pthread_attr_setstacksize( &attr, STACK_SIZE ); pthread_create( &semaphore_test_thread_handle, &attr, semaphore_test, (void *)0 ); for (i = 0; i < nsemaphores; i++) { wait_for_tick(); // Wait until the next clock tick to minimize aberations HAL_CLOCK_READ(&semaphore_ft[i].start); sem_post(&test_semaphores[0]); sem_wait(&synchro); } pthread_join(semaphore_test_thread_handle, &retval); show_times(semaphore_ft, nsemaphores, "Post/Wait semaphore"); } //-------------------------------------------------------------------------- // Timer callback function void sigrt0(int signo, siginfo_t *info, void *context) { diag_printf("sigrt0 called\n"); // empty call back } // Callback used to test determinancy static volatile int timer_cnt; void sigrt1(int signo, siginfo_t *info, void *context) { if (timer_cnt == nscheds) return; sched_ft[timer_cnt].start = 0; HAL_CLOCK_READ(&sched_ft[timer_cnt++].end); if (timer_cnt == nscheds) { sem_post(&synchro); } } static sem_t timer_sem; static void sigrt2(int signo, siginfo_t *info, void *context) { if (timer_cnt == nscheds) { sem_post(&synchro); sem_post(&timer_sem); } else { sched_ft[timer_cnt].start = 0; sem_post(&timer_sem); } } // Null thread, used to keep scheduler busy void * timer_test(void * id) { while (true) { cyg_thread_yield(); pthread_testcancel(); } return id; } // Thread that suspends itself at the first opportunity void * timer_test2(void *id) { while (timer_cnt != nscheds) { HAL_CLOCK_READ(&sched_ft[timer_cnt++].end); sem_wait(&timer_sem); } return id; } void run_timer_tests(void) { int res; int i; struct sigaction sa; struct sigevent sigev; struct itimerspec tp; // Install signal handlers sigemptyset( &sa.sa_mask ); sa.sa_flags = SA_SIGINFO; sa.sa_sigaction = sigrt0; sigaction( SIGRTMIN, &sa, NULL ); sa.sa_sigaction = sigrt1; sigaction( SIGRTMIN+1, &sa, NULL ); sa.sa_sigaction = sigrt2; sigaction( SIGRTMIN+2, &sa, NULL ); // Set up common bits of sigevent sigev.sigev_notify = SIGEV_SIGNAL; wait_for_tick(); // Wait until the next clock tick to minimize aberations for (i = 0; i < ntimers; i++) { HAL_CLOCK_READ(&timer_ft[i].start); sigev.sigev_signo = SIGRTMIN; sigev.sigev_value.sival_ptr = (void*)(&timers[i]); res = timer_create( CLOCK_REALTIME, &sigev, &timers[i]); HAL_CLOCK_READ(&timer_ft[i].end); CYG_ASSERT( res == 0 , "timer_create() returned error"); } show_times(timer_ft, ntimers, "Create timer"); wait_for_tick(); // Wait until the next clock tick to minimize aberations tp.it_value.tv_sec = 0; tp.it_value.tv_nsec = 0; tp.it_interval.tv_sec = 0; tp.it_interval.tv_nsec = 0; for (i = 0; i < ntimers; i++) { HAL_CLOCK_READ(&timer_ft[i].start); res = timer_settime( timers[i], 0, &tp, NULL ); HAL_CLOCK_READ(&timer_ft[i].end); CYG_ASSERT( res == 0 , "timer_settime() returned error"); } show_times(timer_ft, ntimers, "Initialize timer to zero"); wait_for_tick(); // Wait until the next clock tick to minimize aberations tp.it_value.tv_sec = 1; tp.it_value.tv_nsec = 250000000; tp.it_interval.tv_sec = 0; tp.it_interval.tv_nsec = 0; for (i = 0; i < ntimers; i++) { HAL_CLOCK_READ(&timer_ft[i].start); res = timer_settime( timers[i], 0, &tp, NULL ); HAL_CLOCK_READ(&timer_ft[i].end); CYG_ASSERT( res == 0 , "timer_settime() returned error"); } show_times(timer_ft, ntimers, "Initialize timer to 1.25 sec"); wait_for_tick(); // Wait until the next clock tick to minimize aberations tp.it_value.tv_sec = 0; tp.it_value.tv_nsec = 0; tp.it_interval.tv_sec = 0; tp.it_interval.tv_nsec = 0; for (i = 0; i < ntimers; i++) { HAL_CLOCK_READ(&timer_ft[i].start); res = timer_settime( timers[i], 0, &tp, NULL ); HAL_CLOCK_READ(&timer_ft[i].end); CYG_ASSERT( res == 0 , "timer_settime() returned error"); } show_times(timer_ft, ntimers, "Disable timer"); wait_for_tick(); // Wait until the next clock tick to minimize aberations for (i = 0; i < ntimers; i++) { HAL_CLOCK_READ(&timer_ft[i].start); res = timer_delete( timers[i] ); HAL_CLOCK_READ(&timer_ft[i].end); CYG_ASSERT( res == 0 , "timer_settime() returned error"); } show_times(timer_ft, ntimers, "Delete timer"); sigev.sigev_signo = SIGRTMIN+1; sigev.sigev_value.sival_ptr = (void*)(&timers[i]); res = timer_create( CLOCK_REALTIME, &sigev, &timers[0]); CYG_ASSERT( res == 0 , "timer_create() returned error"); tp.it_value.tv_sec = 0; tp.it_value.tv_nsec = 50000000; tp.it_interval.tv_sec = 0; tp.it_interval.tv_nsec = 50000000;; timer_cnt = 0; res = timer_settime( timers[0], 0, &tp, NULL ); CYG_ASSERT( res == 0 , "timer_settime() returned error"); sem_init(&synchro, 0, 0); wait_for_tick(); // Wait until the next clock tick to minimize aberations do { res = sem_wait(&synchro); } while( res == -1 && errno == EINTR ); CYG_ASSERT( res == 0 , "sem_wait() returned error"); tp.it_value.tv_sec = 0; tp.it_value.tv_nsec = 0; tp.it_interval.tv_sec = 0; tp.it_interval.tv_nsec = 0; res = timer_settime( timers[0], 0, &tp, NULL ); CYG_ASSERT( res == 0 , "timer_settime() returned error"); res = timer_delete( timers[0] ); CYG_ASSERT( res == 0 , "timer_delete() returned error"); show_times(sched_ft, nscheds, "Timer latency [0 threads]"); struct sched_param schedparam; pthread_attr_t attr; void *retval; // Set my priority higher than any I plan to create schedparam.sched_priority = 20; pthread_setschedparam( pthread_self(), SCHED_RR, &schedparam ); // Initiaize thread creation attributes pthread_attr_init( &attr ); pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED ); pthread_attr_setschedpolicy( &attr, SCHED_RR ); schedparam.sched_priority = 10; pthread_attr_setschedparam( &attr, &schedparam ); for (i = 0; i < 2; i++) { pthread_attr_setstackaddr( &attr, &stacks[i][STACK_SIZE] ); pthread_attr_setstacksize( &attr, STACK_SIZE ); res = pthread_create( &threads[i], &attr, timer_test, (void *)i ); CYG_ASSERT( res == 0 , "pthread_create() returned error"); } wait_for_tick(); // Wait until the next clock tick to minimize aberations sigev.sigev_signo = SIGRTMIN+1; sigev.sigev_value.sival_ptr = (void*)(&timers[i]); res = timer_create( CLOCK_REALTIME, &sigev, &timers[0]); CYG_ASSERT( res == 0 , "timer_create() returned error"); tp.it_value.tv_sec = 0; tp.it_value.tv_nsec = 50000000; tp.it_interval.tv_sec = 0; tp.it_interval.tv_nsec = 50000000;; timer_cnt = 0; res = timer_settime( timers[0], 0, &tp, NULL ); CYG_ASSERT( res == 0 , "timer_settime() returned error"); sem_init(&synchro, 0, 0); do { res = sem_wait(&synchro); } while( res == -1 && errno == EINTR ); CYG_ASSERT( res == 0 , "sem_wait() returned error"); res = timer_delete(timers[0]); CYG_ASSERT( res == 0 , "timerdelete() returned error"); show_times(sched_ft, nscheds, "Timer latency [2 threads]"); for (i = 0; i < 2; i++) { pthread_cancel(threads[i]); pthread_join(threads[i], &retval); } for (i = 0; i < ntest_threads; i++) { pthread_attr_setstackaddr( &attr, &stacks[i][STACK_SIZE] ); pthread_attr_setstacksize( &attr, STACK_SIZE ); res = pthread_create( &threads[i], &attr, timer_test, (void *)i ); CYG_ASSERT( res == 0 , "pthread_create() returned error"); } wait_for_tick(); // Wait until the next clock tick to minimize aberations sigev.sigev_signo = SIGRTMIN+1; sigev.sigev_value.sival_ptr = (void*)(&timers[i]); res = timer_create( CLOCK_REALTIME, &sigev, &timers[0]); CYG_ASSERT( res == 0 , "timer_create() returned error"); tp.it_value.tv_sec = 0; tp.it_value.tv_nsec = 50000000; tp.it_interval.tv_sec = 0; tp.it_interval.tv_nsec = 50000000;; timer_cnt = 0; res = timer_settime( timers[0], 0, &tp, NULL ); CYG_ASSERT( res == 0 , "timer_settime() returned error"); sem_init(&synchro, 0, 0); do { res = sem_wait(&synchro); } while( res == -1 && errno == EINTR ); CYG_ASSERT( res == 0 , "sem_wait() returned error"); res = timer_delete(timers[0]); CYG_ASSERT( res == 0 , "timerdelete() returned error"); show_times(sched_ft, nscheds, "Timer latency [many threads]"); for (i = 0; i < ntest_threads; i++) { pthread_cancel(threads[i]); pthread_join(threads[i], &retval); } sem_init(&synchro, 0, 0); sem_init(&timer_sem, 0, 0); pthread_attr_setstackaddr( &attr, &stacks[0][STACK_SIZE] ); pthread_attr_setstacksize( &attr, STACK_SIZE ); res = pthread_create( &threads[0], &attr, timer_test2, (void *)0 ); CYG_ASSERT( res == 0 , "pthread_create() returned error"); wait_for_tick(); // Wait until the next clock tick to minimize aberations sigev.sigev_signo = SIGRTMIN+2; sigev.sigev_value.sival_ptr = (void*)(threads[0]); res = timer_create( CLOCK_REALTIME, &sigev, &timers[0]); CYG_ASSERT( res == 0 , "timer_create() returned error"); tp.it_value.tv_sec = 0; tp.it_value.tv_nsec = 50000000; tp.it_interval.tv_sec = 0; tp.it_interval.tv_nsec = 50000000;; timer_cnt = 0; res = timer_settime( timers[0], 0, &tp, NULL ); CYG_ASSERT( res == 0 , "timer_settime() returned error"); do { res = sem_wait(&synchro); } while( res == -1 && errno == EINTR ); CYG_ASSERT( res == 0 , "sem_wait() returned error"); res = timer_delete(timers[0]); CYG_ASSERT( res == 0 , "timerdelete() returned error"); show_times(sched_ft, nscheds, "Timer -> thread post latency"); sem_post(&timer_sem); // pthread_cancel(threads[0]); pthread_join(threads[0], &retval); end_of_test_group(); } //-------------------------------------------------------------------------- void run_all_tests() { int i; cyg_uint32 tv[nsamples], tv0, tv1; // cyg_uint32 min_stack, max_stack, total_stack, actual_stack, j; cyg_tick_count_t ticks, tick0, tick1; #ifdef CYG_SCHEDULER_LOCK_TIMINGS cyg_uint32 lock_ave, lock_max; #endif #if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_LATENCY) && defined(HAL_CLOCK_LATENCY) cyg_int32 clock_ave; #endif disable_clock_latency_measurement(); // cyg_test_dump_thread_stack_stats( "Startup, main stack", thread[0] ); cyg_test_dump_interrupt_stack_stats( "Startup" ); cyg_test_dump_idlethread_stack_stats( "Startup" ); cyg_test_clear_interrupt_stack(); diag_printf("\neCos Kernel Timings\n"); diag_printf("Notes: all times are in microseconds (.000001) unless otherwise stated\n"); #ifdef STATS_WITHOUT_FIRST_SAMPLE diag_printf(" second line of results have first sample removed\n"); #endif cyg_thread_delay(2); // Make sure the clock is actually running ns_per_system_clock = 1000000/rtc_resolution[1]; for (i = 0; i < nsamples; i++) { HAL_CLOCK_READ(&tv[i]); } tv0 = 0; for (i = 1; i < nsamples; i++) { tv0 += tv[i] - tv[i-1]; } end_of_test_group(); overhead = tv0 / (nsamples-1); diag_printf("Reading the hardware clock takes %d 'ticks' overhead\n", overhead); diag_printf("... this value will be factored out of all other measurements\n"); // Try and measure how long the clock interrupt handling takes for (i = 0; i < nsamples; i++) { tick0 = cyg_current_time(); while (true) { tick1 = cyg_current_time(); if (tick0 != tick1) break; } HAL_CLOCK_READ(&tv[i]); } tv1 = 0; for (i = 0; i < nsamples; i++) { tv1 += tv[i] * 1000; } tv1 = tv1 / nsamples; tv1 -= overhead; // Adjust out the cost of getting the timer value diag_printf("Clock interrupt took"); show_ticks_in_us(tv1); diag_printf(" microseconds (%d raw clock ticks)\n", tv1/1000); enable_clock_latency_measurement(); ticks = cyg_current_time(); show_test_parameters(); show_times_hdr(); reset_clock_latency_measurement(); run_thread_tests(); #ifdef CYGPKG_POSIX_PTHREAD_MUTEX run_mutex_tests(); // run_mbox_tests(); #endif run_semaphore_tests(); run_timer_tests(); #ifdef CYG_SCHEDULER_LOCK_TIMINGS Cyg_Scheduler::get_lock_times(&lock_ave, &lock_max); diag_printf("\nMax lock:"); show_ticks_in_us(lock_max); diag_printf(", Ave lock:"); show_ticks_in_us(lock_ave); diag_printf("\n"); #endif #if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_LATENCY) && defined(HAL_CLOCK_LATENCY) // Display latency figures in same format as all other numbers disable_clock_latency_measurement(); clock_ave = (total_clock_latency*1000) / total_clock_interrupts; show_ticks_in_us(clock_ave); show_ticks_in_us(min_clock_latency*1000); show_ticks_in_us(max_clock_latency*1000); show_ticks_in_us(0); diag_printf(" Clock/interrupt latency\n\n"); enable_clock_latency_measurement(); #endif #if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_DSR_LATENCY) disable_clock_latency_measurement(); clock_ave = (total_clock_dsr_latency*1000) / total_clock_dsr_calls; show_ticks_in_us(clock_ave); show_ticks_in_us(min_clock_dsr_latency*1000); show_ticks_in_us(max_clock_dsr_latency*1000); show_ticks_in_us(0); diag_printf(" Clock DSR latency\n\n"); enable_clock_latency_measurement(); #endif #if 0 disable_clock_latency_measurement(); min_stack = STACK_SIZE; max_stack = 0; total_stack = 0; for (i = 0; i < (int)NTEST_THREADS; i++) { for (j = 0; j < STACK_SIZE; j++) { if (stacks[i][j]) break; } actual_stack = STACK_SIZE-j; if (actual_stack < min_stack) min_stack = actual_stack; if (actual_stack > max_stack) max_stack = actual_stack; total_stack += actual_stack; } for (j = 0; j < STACKSIZE; j++) { if (((char *)stack[0])[j]) break; } diag_printf("%5d %5d %5d (main stack: %5d) Thread stack used (%d total)\n", total_stack/NTEST_THREADS, min_stack, max_stack, STACKSIZE - j, STACK_SIZE); #endif // cyg_test_dump_thread_stack_stats( "All done, main stack", thread[0] ); cyg_test_dump_interrupt_stack_stats( "All done" ); cyg_test_dump_idlethread_stack_stats( "All done" ); enable_clock_latency_measurement(); ticks = cyg_current_time(); diag_printf("\nTiming complete - %d ms total\n\n", (int)((ticks*ns_per_system_clock)/1000)); CYG_TEST_PASS_FINISH("Basic timing OK"); } int main( int argc, char **argv ) { CYG_TEST_INIT(); if (cyg_test_is_simulator) { nsamples = NSAMPLES_SIM; ntest_threads = NTEST_THREADS_SIM; nthread_switches = NTHREAD_SWITCHES_SIM; #ifdef CYGPKG_POSIX_PTHREAD_MUTEX nmutexes = NMUTEXES_SIM; #endif nmboxes = NMBOXES_SIM; nsemaphores = NSEMAPHORES_SIM; nscheds = NSCHEDS_SIM; ntimers = NTIMERS_SIM; } else { nsamples = NSAMPLES; ntest_threads = NTEST_THREADS; nthread_switches = NTHREAD_SWITCHES; #ifdef CYGPKG_POSIX_PTHREAD_MUTEX nmutexes = NMUTEXES; #endif nmboxes = NMBOXES; nsemaphores = NSEMAPHORES; nscheds = NSCHEDS; ntimers = NTIMERS; } // Sanity #ifdef WORKHORSE_TEST ntest_threads = max(512, ntest_threads); #ifdef CYGPKG_POSIX_PTHREAD_MUTEX nmutexes = max(1024, nmutexes); #endif nsemaphores = max(1024, nsemaphores); nmboxes = max(1024, nmboxes); ncounters = max(1024, ncounters); ntimers = max(1024, ntimers); #else ntest_threads = max(64, ntest_threads); #ifdef CYGPKG_POSIX_PTHREAD_MUTEX nmutexes = max(32, nmutexes); #endif nsemaphores = max(32, nsemaphores); nmboxes = max(32, nmboxes); ntimers = max(32, ntimers); #endif run_all_tests(); } #endif // CYGFUN_KERNEL_API_C, etc. // EOF tm_posix.cxx