Mercurial > ecos
view packages/kernel/current/tests/tm_basic.cxx @ 2348:73a01c1a35ba
* src/sched/mlqueue.cxx (add_thread, yield):
* src/sched/sched.cxx (unlock_inner, thread_entry):
* include/mlqueue.hxx (class Cyg_SchedThread_Implementation):
* include/kapidata.h (CYG_SCHEDTHREAD_TIMESLICE_MEMBER):
* include/bitmap.hxx (class Cyg_SchedThread_Implementation):
Reimplement timeslicing code. There is now a timeslice_count field
in each thread which is moved to and from the per-CPU counter
during thread dispatch. This approach has been taken to minimize
the changes needed to SMP code. Scheduler specific thread
functions handle counter save, restore and reset. These functions
are defined (as empty inlines) even when timeslicing is disabled,
or in non-timeslicing schedulers, to avoid adding ifdefs to the
code (this change actually removes some).
* tests/timeslice2.c:
* cdl/kernel.cdl: Added timeslice2 test to test behaviour of
timeslicing while being preempted.
| author | nickg |
|---|---|
| date | Mon, 08 Jan 2007 16:20:13 +0000 |
| parents | 275f1861b36f |
| children | b3804ba9e6b1 |
line wrap: on
line source
//========================================================================== // // tm_basic.cxx // // Basic timing test / scaffolding // //========================================================================== //####ECOSGPLCOPYRIGHTBEGIN#### // ------------------------------------------- // This file is part of eCos, the Embedded Configurable Operating System. // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. // Copyright (C) 2002, 2003 Gary Thomas // // 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., // 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. // // This exception does not invalidate any other reasons why a work based on // this file might be covered by the GNU General Public License. // // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. // at http://sources.redhat.com/ecos/ecos-license/ // ------------------------------------------- //####ECOSGPLCOPYRIGHTEND#### //========================================================================== //#####DESCRIPTIONBEGIN#### // // Author(s): gthomas // Contributors: gthomas // Date: 1998-10-19 // Description: Very simple kernel timing test //####DESCRIPTIONEND#### #include <pkgconf/kernel.h> #include <pkgconf/hal.h> #include <cyg/kernel/sched.hxx> #include <cyg/kernel/thread.hxx> #include <cyg/kernel/thread.inl> #include <cyg/kernel/mutex.hxx> #include <cyg/kernel/sema.hxx> #include <cyg/kernel/flag.hxx> #include <cyg/kernel/sched.inl> #include <cyg/kernel/clock.hxx> #include <cyg/kernel/clock.inl> #include <cyg/kernel/kapi.h> #include <cyg/infra/testcase.h> #include <cyg/infra/diag.h> #include <cyg/kernel/test/stackmon.h> #include CYGHWR_MEMORY_LAYOUT_H // 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 #if defined(CYGFUN_KERNEL_API_C) && \ defined(CYGSEM_KERNEL_SCHED_MLQUEUE) && \ defined(CYGVAR_KERNEL_COUNTERS_CLOCK) && \ !defined(CYGDBG_INFRA_DIAG_USE_DEVICE) && \ (CYGNUM_KERNEL_SCHED_PRIORITIES > 12) #define NTHREADS 1 #include "testaux.hxx" // Structure used to keep track of times typedef struct fun_times { cyg_uint32 start; cyg_uint32 end; } fun_times; #define STACK_SIZE (CYGNUM_HAL_STACK_SIZE_TYPICAL+4*1024) #ifdef CYGMEM_REGION_ram_SIZE #define CYG_THREAD_OVERHEAD (STACK_SIZE+sizeof(cyg_thread)+(sizeof(fun_times)*2)) #define NTEST_THREADS ((CYGMEM_REGION_ram_SIZE/16)/CYG_THREAD_OVERHEAD) #define CYG_MUTEX_OVERHEAD (sizeof(cyg_mutex_t)+sizeof(fun_times)) #define NMUTEXES ((CYGMEM_REGION_ram_SIZE/16)/CYG_MUTEX_OVERHEAD) #define CYG_MBOX_OVERHEAD (sizeof(cyg_mbox)+sizeof(fun_times)) #define NMBOXES ((CYGMEM_REGION_ram_SIZE/24)/CYG_MBOX_OVERHEAD) #define CYG_SEMAPHORE_OVERHEAD (sizeof(cyg_sem_t)+sizeof(fun_times)) #define NSEMAPHORES ((CYGMEM_REGION_ram_SIZE/16)/CYG_SEMAPHORE_OVERHEAD) #define CYG_COUNTER_OVERHEAD (sizeof(cyg_counter)+sizeof(fun_times)) #define NCOUNTERS ((CYGMEM_REGION_ram_SIZE/24)/CYG_COUNTER_OVERHEAD) #define CYG_FLAG_OVERHEAD (sizeof(cyg_flag_t)+sizeof(fun_times)) #define NFLAGS ((CYGMEM_REGION_ram_SIZE/24)/CYG_FLAG_OVERHEAD) #define CYG_ALARM_OVERHEAD (sizeof(cyg_alarm)+sizeof(fun_times)) #define NALARMS ((CYGMEM_REGION_ram_SIZE/16)/CYG_ALARM_OVERHEAD) #else // Defaults #define NTEST_THREADS 16 #define NMUTEXES 32 #define NMBOXES 32 #define NSEMAPHORES 32 #define NFLAGS 32 #define NCOUNTERS 32 #define NALARMS 32 #endif #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 NFLAGS_SIM 2 #define NCOUNTERS_SIM 2 #define NALARMS_SIM 2 static int nsamples; static int ntest_threads; static int nthread_switches; static int nmutexes; static int nmboxes; static int nsemaphores; static int nscheds; static int nflags; static int ncounters; static int nalarms; static char stacks[NTEST_THREADS][STACK_SIZE]; static cyg_thread test_threads[NTEST_THREADS]; static cyg_handle_t threads[NTEST_THREADS]; static int overhead; static cyg_sem_t synchro; static fun_times thread_ft[NTEST_THREADS]; static fun_times test2_ft[NTHREAD_SWITCHES]; static cyg_mutex_t test_mutexes[NMUTEXES]; static fun_times mutex_ft[NMUTEXES]; static cyg_thread mutex_test_thread; static cyg_handle_t mutex_test_thread_handle; static cyg_mbox test_mboxes[NMBOXES]; static cyg_handle_t test_mbox_handles[NMBOXES]; static fun_times mbox_ft[NMBOXES]; #ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT static cyg_thread mbox_test_thread; static cyg_handle_t mbox_test_thread_handle; #endif static cyg_sem_t test_semaphores[NSEMAPHORES]; static fun_times semaphore_ft[NSEMAPHORES]; static cyg_thread semaphore_test_thread; static cyg_handle_t semaphore_test_thread_handle; static fun_times sched_ft[NSCHEDS]; static cyg_counter test_counters[NCOUNTERS]; static cyg_handle_t counters[NCOUNTERS]; static fun_times counter_ft[NCOUNTERS]; static cyg_flag_t test_flags[NFLAGS]; static fun_times flag_ft[NFLAGS]; static cyg_alarm test_alarms[NALARMS]; static cyg_handle_t alarms[NALARMS]; static fun_times alarm_ft[NALARMS]; static long rtc_resolution[] = CYGNUM_KERNEL_COUNTERS_RTC_RESOLUTION; static long ns_per_system_clock; #if defined(CYGVAR_KERNEL_COUNTERS_CLOCK_LATENCY) && defined(HAL_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) && defined(HAL_CLOCK_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); void run_mutex_tests(void); void run_mutex_circuit_test(void); void run_mbox_tests(void); void run_mbox_circuit_test(void); void run_semaphore_tests(void); void run_semaphore_circuit_test(void); void run_counter_tests(void); void run_flag_tests(void); void run_alarm_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) && defined(HAL_CLOCK_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); diag_printf(" Mutexes: %5d\n", nmutexes); diag_printf(" Mailboxes: %5d\n", nmboxes); diag_printf(" Semaphores: %5d\n", nsemaphores); diag_printf(" Scheduler operations: %5d\n", nscheds); diag_printf(" Counters: %5d\n", ncounters); diag_printf(" Flags: %5d\n", nflags); diag_printf(" Alarms: %5d\n", nalarms); 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 "<<NULL>>"; // Not currently used } // test0 - null test, never executed void test0(cyg_uint32 indx) { #ifndef CYGPKG_KERNEL_SMP_SUPPORT // In SMP, somw of these threads will execute diag_printf("test0.%d executed?\n", indx); #endif cyg_thread_exit(); } // test1 - empty test, simply exit. Last thread signals parent. void test1(cyg_uint32 indx) { if (indx == (cyg_uint32)(ntest_threads-1)) { cyg_semaphore_post(&synchro); // Signal that last thread is dying } cyg_thread_exit(); } // test2 - measure thread switch times void test2(cyg_uint32 indx) { int i; for (i = 0; i < nthread_switches; i++) { if (indx == 0) { HAL_CLOCK_READ(&test2_ft[i].start); } else { HAL_CLOCK_READ(&test2_ft[i].end); } cyg_thread_yield(); } if (indx == 1) { cyg_semaphore_post(&synchro); } cyg_thread_exit(); } // Full-circuit mutex unlock/lock test void mutex_test(cyg_uint32 indx) { int i; cyg_mutex_lock(&test_mutexes[0]); for (i = 0; i < nmutexes; i++) { cyg_semaphore_wait(&synchro); wait_for_tick(); // Wait until the next clock tick to minimize aberations HAL_CLOCK_READ(&mutex_ft[i].start); cyg_mutex_unlock(&test_mutexes[0]); cyg_mutex_lock(&test_mutexes[0]); cyg_semaphore_post(&synchro); } cyg_thread_exit(); } // Full-circuit mbox put/get test 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(); } // Full-circuit semaphore post/wait test void semaphore_test(cyg_uint32 indx) { int i; for (i = 0; i < nsemaphores; i++) { cyg_semaphore_wait(&test_semaphores[0]); HAL_CLOCK_READ(&semaphore_ft[i].end); cyg_semaphore_post(&synchro); } cyg_thread_exit(); } // // This set of tests is used to measure kernel primitives that deal with threads // void run_thread_tests(void) { int i; cyg_priority_t prio; // Set my priority higher than any I plan to create cyg_thread_set_priority(cyg_thread_self(), 2); 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); cyg_thread_create(10, // Priority - just a number test0, // entry i, // index thread_name("thread", i), // Name &stacks[i][0], // Stack STACK_SIZE, // Size &threads[i], // Handle &test_threads[i] // Thread data structure ); 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); cyg_thread_yield(); HAL_CLOCK_READ(&thread_ft[i].end); } show_times(thread_ft, ntest_threads, "Yield thread [all suspended]"); 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); cyg_thread_suspend(threads[i]); HAL_CLOCK_READ(&thread_ft[i].end); } show_times(thread_ft, ntest_threads, "Suspend [suspended] 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); cyg_thread_resume(threads[i]); HAL_CLOCK_READ(&thread_ft[i].end); } show_times(thread_ft, ntest_threads, "Resume 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); cyg_thread_set_priority(threads[i], 11); 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); prio = cyg_thread_get_priority(threads[i]); HAL_CLOCK_READ(&thread_ft[i].end); } show_times(thread_ft, ntest_threads, "Get 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); cyg_thread_kill(threads[i]); HAL_CLOCK_READ(&thread_ft[i].end); } show_times(thread_ft, ntest_threads, "Kill [suspended] 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); cyg_thread_yield(); HAL_CLOCK_READ(&thread_ft[i].end); } show_times(thread_ft, ntest_threads, "Yield [no other] thread"); // Set my priority higher than any I plan to create cyg_thread_set_priority(cyg_thread_self(), 2); // Recreate the test set for (i = 0; i < ntest_threads; i++) { cyg_thread_create(10, // Priority - just a number test0, // entry i, // index thread_name("thread", i), // Name &stacks[i][0], // Stack STACK_SIZE, // Size &threads[i], // Handle &test_threads[i] // Thread data structure ); } 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); cyg_thread_resume(threads[i]); HAL_CLOCK_READ(&thread_ft[i].end); } show_times(thread_ft, ntest_threads, "Resume [suspended low prio] 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); cyg_thread_resume(threads[i]); HAL_CLOCK_READ(&thread_ft[i].end); } show_times(thread_ft, ntest_threads, "Resume [runnable low prio] 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); cyg_thread_suspend(threads[i]); HAL_CLOCK_READ(&thread_ft[i].end); } show_times(thread_ft, ntest_threads, "Suspend [runnable] 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); cyg_thread_yield(); HAL_CLOCK_READ(&thread_ft[i].end); } show_times(thread_ft, ntest_threads, "Yield [only low prio] 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); cyg_thread_suspend(threads[i]); HAL_CLOCK_READ(&thread_ft[i].end); } show_times(thread_ft, ntest_threads, "Suspend [runnable->not runnable]"); for (i = 0; i < ntest_threads; i++) { cyg_thread_resume(threads[i]); } 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); cyg_thread_kill(threads[i]); HAL_CLOCK_READ(&thread_ft[i].end); } show_times(thread_ft, ntest_threads, "Kill [runnable] 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); cyg_thread_delete(threads[i]); HAL_CLOCK_READ(&thread_ft[i].end); } show_times(thread_ft, ntest_threads, "Destroy [dead] thread"); // Recreate the test set for (i = 0; i < ntest_threads; i++) { cyg_thread_create(10, // Priority - just a number test0, // entry i, // index thread_name("thread", i), // Name &stacks[i][0], // Stack STACK_SIZE, // Size &threads[i], // Handle &test_threads[i] // Thread data structure ); cyg_thread_resume(threads[i]); } 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); cyg_thread_delete(threads[i]); HAL_CLOCK_READ(&thread_ft[i].end); } show_times(thread_ft, ntest_threads, "Destroy [runnable] thread"); // Set my priority lower than any I plan to create cyg_thread_set_priority(cyg_thread_self(), 3); // Set up the end-of-threads synchronizer cyg_semaphore_init(&synchro, 0); // Recreate the test set for (i = 0; i < ntest_threads; i++) { cyg_thread_create(2, // Priority - just a number test1, // entry i, // index thread_name("thread", i), // Name &stacks[i][0], // Stack STACK_SIZE, // Size &threads[i], // Handle &test_threads[i] // Thread data structure ); } 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); cyg_thread_resume(threads[i]); HAL_CLOCK_READ(&thread_ft[i].end); } show_times(thread_ft, ntest_threads, "Resume [high priority] thread"); cyg_semaphore_wait(&synchro); // Wait for all threads to finish // Make sure they are all dead for (i = 0; i < ntest_threads; i++) { cyg_thread_delete(threads[i]); } run_thread_switch_test(); end_of_test_group(); } void run_thread_switch_test(void) { int i; // Set up for thread context switch for (i = 0; i < 2; i++) { cyg_thread_create(10, // Priority - just a number test2, // entry i, // index thread_name("thread", i), // Name &stacks[i][0], // Stack STACK_SIZE, // Size &threads[i], // Handle &test_threads[i] // Thread data structure ); cyg_thread_resume(threads[i]); } // Set up the end-of-threads synchronizer cyg_semaphore_init(&synchro, 0); cyg_semaphore_wait(&synchro); wait_for_tick(); // Wait until the next clock tick to minimize aberations show_times(test2_ft, nthread_switches, "Thread switch"); // Clean up for (i = 0; i < 2; i++) { cyg_thread_delete(threads[i]); } } void run_mutex_tests(void) { int i; // 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); cyg_mutex_init(&test_mutexes[i]); 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); cyg_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); cyg_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); cyg_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); cyg_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++) { cyg_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); cyg_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; // Set my priority lower than any I plan to create cyg_thread_set_priority(cyg_thread_self(), 4); // Set up for full mutex unlock/lock test cyg_mutex_init(&test_mutexes[0]); cyg_semaphore_init(&synchro, 0); cyg_thread_create(3, // Priority - just a number mutex_test, // entry 0, // index thread_name("thread", 0), // Name &stacks[0][0], // Stack STACK_SIZE, // Size &mutex_test_thread_handle, // Handle &mutex_test_thread // Thread data structure ); cyg_thread_resume(mutex_test_thread_handle); // Need to raise priority so that this thread will block on the "lock" cyg_thread_set_priority(cyg_thread_self(), 2); for (i = 0; i < nmutexes; i++) { cyg_semaphore_post(&synchro); cyg_mutex_lock(&test_mutexes[0]); HAL_CLOCK_READ(&mutex_ft[i].end); cyg_mutex_unlock(&test_mutexes[0]); cyg_semaphore_wait(&synchro); } cyg_thread_delete(mutex_test_thread_handle); show_times(mutex_ft, nmutexes, "Unlock/Lock mutex"); } 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 } void run_semaphore_tests(void) { int i; cyg_count32 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); cyg_semaphore_init(&test_semaphores[i], 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); cyg_semaphore_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); cyg_semaphore_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); cyg_semaphore_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++) { cyg_semaphore_post(&test_semaphores[i]); HAL_CLOCK_READ(&semaphore_ft[i].start); cyg_semaphore_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); cyg_semaphore_peek(&test_semaphores[i], &sem_val); HAL_CLOCK_READ(&semaphore_ft[i].end); } show_times(semaphore_ft, nsemaphores, "Peek 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); cyg_semaphore_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; // Set my priority lower than any I plan to create cyg_thread_set_priority(cyg_thread_self(), 3); // Set up for full semaphore post/wait test cyg_semaphore_init(&test_semaphores[0], 0); cyg_semaphore_init(&synchro, 0); cyg_thread_create(2, // Priority - just a number semaphore_test, // entry 0, // index thread_name("thread", 0), // Name &stacks[0][0], // Stack STACK_SIZE, // Size &semaphore_test_thread_handle, // Handle &semaphore_test_thread // Thread data structure ); cyg_thread_resume(semaphore_test_thread_handle); 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); cyg_semaphore_post(&test_semaphores[0]); cyg_semaphore_wait(&synchro); } cyg_thread_delete(semaphore_test_thread_handle); show_times(semaphore_ft, nsemaphores, "Post/Wait semaphore"); } void run_counter_tests(void) { int i; cyg_tick_count_t val=0; wait_for_tick(); // Wait until the next clock tick to minimize aberations for (i = 0; i < ncounters; i++) { HAL_CLOCK_READ(&counter_ft[i].start); cyg_counter_create(&counters[i], &test_counters[i]); HAL_CLOCK_READ(&counter_ft[i].end); } show_times(counter_ft, ncounters, "Create counter"); wait_for_tick(); // Wait until the next clock tick to minimize aberations for (i = 0; i < ncounters; i++) { HAL_CLOCK_READ(&counter_ft[i].start); val = cyg_counter_current_value(counters[i]); HAL_CLOCK_READ(&counter_ft[i].end); } show_times(counter_ft, ncounters, "Get counter value"); wait_for_tick(); // Wait until the next clock tick to minimize aberations for (i = 0; i < ncounters; i++) { HAL_CLOCK_READ(&counter_ft[i].start); cyg_counter_set_value(counters[i], val); HAL_CLOCK_READ(&counter_ft[i].end); } show_times(counter_ft, ncounters, "Set counter value"); wait_for_tick(); // Wait until the next clock tick to minimize aberations for (i = 0; i < ncounters; i++) { HAL_CLOCK_READ(&counter_ft[i].start); cyg_counter_tick(counters[i]); HAL_CLOCK_READ(&counter_ft[i].end); } show_times(counter_ft, ncounters, "Tick counter"); wait_for_tick(); // Wait until the next clock tick to minimize aberations for (i = 0; i < ncounters; i++) { HAL_CLOCK_READ(&counter_ft[i].start); cyg_counter_delete(counters[i]); HAL_CLOCK_READ(&counter_ft[i].end); } show_times(counter_ft, ncounters, "Delete counter"); end_of_test_group(); } void run_flag_tests(void) { int i; cyg_flag_value_t val; wait_for_tick(); // Wait until the next clock tick to minimize aberations for (i = 0; i < nflags; i++) { HAL_CLOCK_READ(&flag_ft[i].start); cyg_flag_init(&test_flags[i]); HAL_CLOCK_READ(&flag_ft[i].end); } show_times(flag_ft, nflags, "Init flag"); wait_for_tick(); // Wait until the next clock tick to minimize aberations for (i = 0; i < nflags; i++) { HAL_CLOCK_READ(&flag_ft[i].start); cyg_flag_destroy(&test_flags[i]); HAL_CLOCK_READ(&flag_ft[i].end); } show_times(flag_ft, nflags, "Destroy flag"); // Recreate the flags - reused in the remaining tests for (i = 0; i < nflags; i++) { cyg_flag_init(&test_flags[i]); } wait_for_tick(); // Wait until the next clock tick to minimize aberations for (i = 0; i < nflags; i++) { HAL_CLOCK_READ(&flag_ft[i].start); cyg_flag_maskbits(&test_flags[i], 0); HAL_CLOCK_READ(&flag_ft[i].end); } show_times(flag_ft, nflags, "Mask bits in flag"); wait_for_tick(); // Wait until the next clock tick to minimize aberations for (i = 0; i < nflags; i++) { HAL_CLOCK_READ(&flag_ft[i].start); cyg_flag_setbits(&test_flags[i], 0x11); HAL_CLOCK_READ(&flag_ft[i].end); } show_times(flag_ft, nflags, "Set bits in flag [no waiters]"); wait_for_tick(); // Wait until the next clock tick to minimize aberations for (i = 0; i < nflags; i++) { cyg_flag_setbits(&test_flags[i], 0x11); HAL_CLOCK_READ(&flag_ft[i].start); cyg_flag_wait(&test_flags[i], 0x11, CYG_FLAG_WAITMODE_AND); HAL_CLOCK_READ(&flag_ft[i].end); } show_times(flag_ft, nflags, "Wait for flag [AND]"); wait_for_tick(); // Wait until the next clock tick to minimize aberations for (i = 0; i < nflags; i++) { cyg_flag_setbits(&test_flags[i], 0x11); HAL_CLOCK_READ(&flag_ft[i].start); cyg_flag_wait(&test_flags[i], 0x11, CYG_FLAG_WAITMODE_OR); HAL_CLOCK_READ(&flag_ft[i].end); } show_times(flag_ft, nflags, "Wait for flag [OR]"); wait_for_tick(); // Wait until the next clock tick to minimize aberations for (i = 0; i < nflags; i++) { cyg_flag_setbits(&test_flags[i], 0x11); HAL_CLOCK_READ(&flag_ft[i].start); cyg_flag_wait(&test_flags[i], 0x11, CYG_FLAG_WAITMODE_AND|CYG_FLAG_WAITMODE_CLR); HAL_CLOCK_READ(&flag_ft[i].end); } show_times(flag_ft, nflags, "Wait for flag [AND/CLR]"); wait_for_tick(); // Wait until the next clock tick to minimize aberations for (i = 0; i < nflags; i++) { cyg_flag_setbits(&test_flags[i], 0x11); HAL_CLOCK_READ(&flag_ft[i].start); cyg_flag_wait(&test_flags[i], 0x11, CYG_FLAG_WAITMODE_OR|CYG_FLAG_WAITMODE_CLR); HAL_CLOCK_READ(&flag_ft[i].end); } show_times(flag_ft, nflags, "Wait for flag [OR/CLR]"); wait_for_tick(); // Wait until the next clock tick to minimize aberations for (i = 0; i < nflags; i++) { cyg_flag_setbits(&test_flags[i], 0x11); HAL_CLOCK_READ(&flag_ft[i].start); val = cyg_flag_peek(&test_flags[i]); HAL_CLOCK_READ(&flag_ft[i].end); } show_times(flag_ft, nflags, "Peek on flag"); // Destroy flags - no longer needed for (i = 0; i < nflags; i++) { cyg_flag_destroy(&test_flags[i]); } end_of_test_group(); } // Alarm callback function void alarm_cb(cyg_handle_t alarm, cyg_addrword_t val) { // empty call back } // Callback used to test determinancy static volatile int alarm_cnt; void alarm_cb2(cyg_handle_t alarm, cyg_addrword_t indx) { if (alarm_cnt == nscheds) return; sched_ft[alarm_cnt].start = 0; HAL_CLOCK_READ(&sched_ft[alarm_cnt++].end); if (alarm_cnt == nscheds) { cyg_semaphore_post(&synchro); } } static void alarm_cb3(cyg_handle_t alarm, cyg_addrword_t indx) { if (alarm_cnt == nscheds) { cyg_semaphore_post(&synchro); } else { sched_ft[alarm_cnt].start = 0; cyg_thread_resume((cyg_handle_t)indx); } } // Null thread, used to keep scheduler busy void alarm_test(cyg_uint32 id) { while (true) { cyg_thread_yield(); } } // Thread that suspends itself at the first opportunity void alarm_test2(cyg_uint32 id) { cyg_handle_t me = cyg_thread_self(); while (true) { HAL_CLOCK_READ(&sched_ft[alarm_cnt++].end); cyg_thread_suspend(me); } } void run_alarm_tests(void) { int i; cyg_tick_count_t init_val, step_val; cyg_handle_t rtc_handle; wait_for_tick(); // Wait until the next clock tick to minimize aberations for (i = 0; i < ncounters; i++) { cyg_counter_create(&counters[i], &test_counters[i]); } for (i = 0; i < nalarms; i++) { HAL_CLOCK_READ(&alarm_ft[i].start); cyg_alarm_create(counters[0], alarm_cb, 0, &alarms[i], &test_alarms[i]); HAL_CLOCK_READ(&alarm_ft[i].end); } show_times(alarm_ft, nalarms, "Create alarm"); wait_for_tick(); // Wait until the next clock tick to minimize aberations init_val = 0; step_val = 0; for (i = 0; i < nalarms; i++) { HAL_CLOCK_READ(&alarm_ft[i].start); cyg_alarm_initialize(alarms[i], init_val, step_val); HAL_CLOCK_READ(&alarm_ft[i].end); } show_times(alarm_ft, nalarms, "Initialize alarm"); wait_for_tick(); // Wait until the next clock tick to minimize aberations init_val = 0; step_val = 0; for (i = 0; i < nalarms; i++) { HAL_CLOCK_READ(&alarm_ft[i].start); cyg_alarm_disable(alarms[i]); HAL_CLOCK_READ(&alarm_ft[i].end); } show_times(alarm_ft, nalarms, "Disable alarm"); wait_for_tick(); // Wait until the next clock tick to minimize aberations init_val = 0; step_val = 0; for (i = 0; i < nalarms; i++) { HAL_CLOCK_READ(&alarm_ft[i].start); cyg_alarm_enable(alarms[i]); HAL_CLOCK_READ(&alarm_ft[i].end); } show_times(alarm_ft, nalarms, "Enable alarm"); wait_for_tick(); // Wait until the next clock tick to minimize aberations for (i = 0; i < nalarms; i++) { HAL_CLOCK_READ(&alarm_ft[i].start); cyg_alarm_delete(alarms[i]); HAL_CLOCK_READ(&alarm_ft[i].end); } show_times(alarm_ft, nalarms, "Delete alarm"); wait_for_tick(); // Wait until the next clock tick to minimize aberations cyg_counter_create(&counters[0], &test_counters[0]); cyg_alarm_create(counters[0], alarm_cb, 0, &alarms[0], &test_alarms[0]); init_val = 9999; step_val = 9999; cyg_alarm_initialize(alarms[0], init_val, step_val); cyg_alarm_enable(alarms[0]); for (i = 0; i < ncounters; i++) { HAL_CLOCK_READ(&counter_ft[i].start); cyg_counter_tick(counters[0]); HAL_CLOCK_READ(&counter_ft[i].end); } show_times(counter_ft, ncounters, "Tick counter [1 alarm]"); wait_for_tick(); // Wait until the next clock tick to minimize aberations cyg_counter_create(&counters[0], &test_counters[0]); for (i = 0; i < nalarms; i++) { cyg_alarm_create(counters[0], alarm_cb, 0, &alarms[i], &test_alarms[i]); init_val = 9999; step_val = 9999; cyg_alarm_initialize(alarms[i], init_val, step_val); cyg_alarm_enable(alarms[i]); } for (i = 0; i < ncounters; i++) { HAL_CLOCK_READ(&counter_ft[i].start); cyg_counter_tick(counters[0]); HAL_CLOCK_READ(&counter_ft[i].end); } show_times(counter_ft, ncounters, "Tick counter [many alarms]"); wait_for_tick(); // Wait until the next clock tick to minimize aberations cyg_counter_create(&counters[0], &test_counters[0]); cyg_alarm_create(counters[0], alarm_cb, 0, &alarms[0], &test_alarms[0]); init_val = 1; step_val = 1; cyg_alarm_initialize(alarms[0], init_val, step_val); cyg_alarm_enable(alarms[0]); for (i = 0; i < ncounters; i++) { HAL_CLOCK_READ(&counter_ft[i].start); cyg_counter_tick(counters[0]); HAL_CLOCK_READ(&counter_ft[i].end); } show_times(counter_ft, ncounters, "Tick & fire counter [1 alarm]"); wait_for_tick(); // Wait until the next clock tick to minimize aberations cyg_counter_create(&counters[0], &test_counters[0]); for (i = 0; i < nalarms; i++) { cyg_alarm_create(counters[0], alarm_cb, i, &alarms[i], &test_alarms[i]); init_val = 1; step_val = 1; cyg_alarm_initialize(alarms[i], init_val, step_val); cyg_alarm_enable(alarms[i]); } for (i = 0; i < nalarms; i++) { HAL_CLOCK_READ(&alarm_ft[i].start); cyg_counter_tick(counters[0]); HAL_CLOCK_READ(&alarm_ft[i].end); } for (i = 0; i < nalarms; i++) { cyg_alarm_delete(alarms[i]); } show_times(alarm_ft, nalarms, "Tick & fire counters [>1 together]"); wait_for_tick(); // Wait until the next clock tick to minimize aberations cyg_counter_create(&counters[0], &test_counters[0]); for (i = 0; i < nalarms; i++) { cyg_alarm_create(counters[0], alarm_cb, i, &alarms[i], &test_alarms[i]); init_val = i+1; step_val = nalarms+1; cyg_alarm_initialize(alarms[i], init_val, step_val); cyg_alarm_enable(alarms[i]); } for (i = 0; i < nalarms; i++) { HAL_CLOCK_READ(&alarm_ft[i].start); cyg_counter_tick(counters[0]); HAL_CLOCK_READ(&alarm_ft[i].end); } for (i = 0; i < nalarms; i++) { cyg_alarm_delete(alarms[i]); } show_times(alarm_ft, nalarms, "Tick & fire counters [>1 separately]"); wait_for_tick(); // Wait until the next clock tick to minimize aberations cyg_clock_to_counter(cyg_real_time_clock(), &rtc_handle); cyg_alarm_create(rtc_handle, alarm_cb2, 0, &alarms[0], &test_alarms[0]); init_val = 5; step_val = 5; alarm_cnt = 0; cyg_alarm_initialize(alarms[0], init_val, step_val); cyg_semaphore_init(&synchro, 0); cyg_alarm_enable(alarms[0]); cyg_semaphore_wait(&synchro); cyg_alarm_disable(alarms[0]); cyg_alarm_delete(alarms[0]); show_times(sched_ft, nscheds, "Alarm latency [0 threads]"); // Set my priority higher than any I plan to create cyg_thread_set_priority(cyg_thread_self(), 2); for (i = 0; i < 2; i++) { cyg_thread_create(10, // Priority - just a number alarm_test, // entry i, // index thread_name("thread", i), // Name &stacks[i][0], // Stack STACK_SIZE, // Size &threads[i], // Handle &test_threads[i] // Thread data structure ); cyg_thread_resume(threads[i]); } wait_for_tick(); // Wait until the next clock tick to minimize aberations cyg_clock_to_counter(cyg_real_time_clock(), &rtc_handle); cyg_alarm_create(rtc_handle, alarm_cb2, 0, &alarms[0], &test_alarms[0]); init_val = 5; step_val = 5; alarm_cnt = 0; cyg_alarm_initialize(alarms[0], init_val, step_val); cyg_semaphore_init(&synchro, 0); cyg_alarm_enable(alarms[0]); cyg_semaphore_wait(&synchro); cyg_alarm_disable(alarms[0]); cyg_alarm_delete(alarms[0]); show_times(sched_ft, nscheds, "Alarm latency [2 threads]"); for (i = 0; i < 2; i++) { cyg_thread_suspend(threads[i]); cyg_thread_delete(threads[i]); } // Set my priority higher than any I plan to create cyg_thread_set_priority(cyg_thread_self(), 2); for (i = 0; i < ntest_threads; i++) { cyg_thread_create(10, // Priority - just a number alarm_test, // entry i, // index thread_name("thread", i), // Name &stacks[i][0], // Stack STACK_SIZE, // Size &threads[i], // Handle &test_threads[i] // Thread data structure ); cyg_thread_resume(threads[i]); } wait_for_tick(); // Wait until the next clock tick to minimize aberations cyg_clock_to_counter(cyg_real_time_clock(), &rtc_handle); cyg_alarm_create(rtc_handle, alarm_cb2, 0, &alarms[0], &test_alarms[0]); init_val = 5; step_val = 5; alarm_cnt = 0; cyg_alarm_initialize(alarms[0], init_val, step_val); cyg_semaphore_init(&synchro, 0); cyg_alarm_enable(alarms[0]); cyg_semaphore_wait(&synchro); cyg_alarm_disable(alarms[0]); cyg_alarm_delete(alarms[0]); show_times(sched_ft, nscheds, "Alarm latency [many threads]"); for (i = 0; i < ntest_threads; i++) { cyg_thread_suspend(threads[i]); cyg_thread_delete(threads[i]); } // Set my priority higher than any I plan to create cyg_thread_set_priority(cyg_thread_self(), 2); cyg_thread_create(10, // Priority - just a number alarm_test2, // entry i, // index thread_name("thread", 0), // Name &stacks[0][0], // Stack STACK_SIZE, // Size &threads[0], // Handle &test_threads[0] // Thread data structure ); wait_for_tick(); // Wait until the next clock tick to minimize aberations cyg_clock_to_counter(cyg_real_time_clock(), &rtc_handle); cyg_alarm_create(rtc_handle, alarm_cb3, threads[0], &alarms[0], &test_alarms[0]); init_val = 5; step_val = 5; alarm_cnt = 0; cyg_alarm_initialize(alarms[0], init_val, step_val); cyg_semaphore_init(&synchro, 0); cyg_alarm_enable(alarms[0]); cyg_semaphore_wait(&synchro); cyg_alarm_disable(alarms[0]); cyg_alarm_delete(alarms[0]); show_times(sched_ft, nscheds, "Alarm -> thread resume latency"); cyg_thread_suspend(threads[0]); cyg_thread_delete(threads[0]); end_of_test_group(); } void run_sched_tests(void) { int i; wait_for_tick(); // Wait until the next clock tick to minimize aberations for (i = 0; i < nscheds; i++) { HAL_CLOCK_READ(&sched_ft[i].start); cyg_scheduler_lock(); HAL_CLOCK_READ(&sched_ft[i].end); cyg_scheduler_unlock(); } show_times(sched_ft, nscheds, "Scheduler lock"); wait_for_tick(); // Wait until the next clock tick to minimize aberations for (i = 0; i < nscheds; i++) { cyg_scheduler_lock(); HAL_CLOCK_READ(&sched_ft[i].start); cyg_scheduler_unlock(); HAL_CLOCK_READ(&sched_ft[i].end); } show_times(sched_ft, nscheds, "Scheduler unlock [0 threads]"); // Set my priority higher than any I plan to create cyg_thread_set_priority(cyg_thread_self(), 2); for (i = 0; i < 1; i++) { cyg_thread_create(10, // Priority - just a number test0, // entry i, // index thread_name("thread", i), // Name &stacks[i][0], // Stack STACK_SIZE, // Size &threads[i], // Handle &test_threads[i] // Thread data structure ); } wait_for_tick(); // Wait until the next clock tick to minimize aberations for (i = 0; i < nscheds; i++) { cyg_scheduler_lock(); HAL_CLOCK_READ(&sched_ft[i].start); cyg_scheduler_unlock(); HAL_CLOCK_READ(&sched_ft[i].end); } show_times(sched_ft, nscheds, "Scheduler unlock [1 suspended]"); for (i = 0; i < 1; i++) { cyg_thread_delete(threads[i]); } // Set my priority higher than any I plan to create cyg_thread_set_priority(cyg_thread_self(), 2); for (i = 0; i < ntest_threads; i++) { cyg_thread_create(10, // Priority - just a number test0, // entry i, // index thread_name("thread", i), // Name &stacks[i][0], // Stack STACK_SIZE, // Size &threads[i], // Handle &test_threads[i] // Thread data structure ); } wait_for_tick(); // Wait until the next clock tick to minimize aberations for (i = 0; i < nscheds; i++) { cyg_scheduler_lock(); HAL_CLOCK_READ(&sched_ft[i].start); cyg_scheduler_unlock(); HAL_CLOCK_READ(&sched_ft[i].end); } show_times(sched_ft, nscheds, "Scheduler unlock [many suspended]"); for (i = 0; i < ntest_threads; i++) { cyg_thread_delete(threads[i]); } // Set my priority higher than any I plan to create cyg_thread_set_priority(cyg_thread_self(), 2); for (i = 0; i < ntest_threads; i++) { cyg_thread_create(10, // Priority - just a number test0, // entry i, // index thread_name("thread", i), // Name &stacks[i][0], // Stack STACK_SIZE, // Size &threads[i], // Handle &test_threads[i] // Thread data structure ); cyg_thread_resume(threads[i]); } wait_for_tick(); // Wait until the next clock tick to minimize aberations for (i = 0; i < nscheds; i++) { cyg_scheduler_lock(); HAL_CLOCK_READ(&sched_ft[i].start); cyg_scheduler_unlock(); HAL_CLOCK_READ(&sched_ft[i].end); } show_times(sched_ft, nscheds, "Scheduler unlock [many low prio]"); for (i = 0; i < ntest_threads; i++) { cyg_thread_delete(threads[i]); } end_of_test_group(); } static void _run_all_tests(CYG_ADDRESS id) { int i, j; cyg_uint32 tv[nsamples], tv0, tv1; cyg_uint32 min_stack, max_stack, total_stack, actual_stack; 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(); #ifndef CYGPKG_KERNEL_SMP_SUPPORT 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(); #endif 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]; wait_for_tick(); 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(); run_sched_tests(); run_mutex_tests(); run_mbox_tests(); run_semaphore_tests(); run_counter_tests(); run_flag_tests(); run_alarm_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) && defined(HAL_CLOCK_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 #ifndef CYGPKG_KERNEL_SMP_SUPPORT 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("%5ld %5d %5d (main stack: %5d) Thread stack used (%d total)\n", (unsigned long) total_stack/NTEST_THREADS, min_stack, max_stack, STACKSIZE - j, STACK_SIZE); 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" ); #endif enable_clock_latency_measurement(); ticks = cyg_current_time(); diag_printf("\nTiming complete - %d ms total\n\n", (int)((ticks*ns_per_system_clock)/1000)); } void run_all_tests(CYG_ADDRESS id) { #if CYGNUM_TESTS_RUN_COUNT < 0 while (1) #else int i; for (i = 0; i < CYGNUM_TESTS_RUN_COUNT; i++) #endif _run_all_tests(id); CYG_TEST_PASS_FINISH("Basic timing OK"); } void tm_basic_main( void ) { CYG_TEST_INIT(); if (cyg_test_is_simulator) { nsamples = NSAMPLES_SIM; ntest_threads = NTEST_THREADS_SIM; nthread_switches = NTHREAD_SWITCHES_SIM; nmutexes = NMUTEXES_SIM; nmboxes = NMBOXES_SIM; nsemaphores = NSEMAPHORES_SIM; nscheds = NSCHEDS_SIM; nflags = NFLAGS_SIM; ncounters = NCOUNTERS_SIM; nalarms = NALARMS_SIM; } else { nsamples = NSAMPLES; ntest_threads = NTEST_THREADS; nthread_switches = NTHREAD_SWITCHES; nmutexes = NMUTEXES; nmboxes = NMBOXES; nsemaphores = NSEMAPHORES; nscheds = NSCHEDS; nflags = NFLAGS; ncounters = NCOUNTERS; nalarms = NALARMS; } // Sanity #ifdef WORKHORSE_TEST ntest_threads = max(512, ntest_threads); nmutexes = max(1024, nmutexes); nsemaphores = max(1024, nsemaphores); nmboxes = max(1024, nmboxes); ncounters = max(1024, ncounters); nalarms = max(1024, nalarms); #else ntest_threads = max(64, ntest_threads); nmutexes = max(32, nmutexes); nsemaphores = max(32, nsemaphores); nmboxes = max(32, nmboxes); ncounters = max(32, ncounters); nflags = max(32, nflags); nalarms = max(32, nalarms); #endif new_thread(run_all_tests, 0); Cyg_Scheduler::scheduler.start(); } #ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG externC void cyg_hal_invoke_constructors(); #endif externC void cyg_start( void ) { #ifdef CYGSEM_HAL_STOP_CONSTRUCTORS_ON_FLAG cyg_hal_invoke_constructors(); #endif tm_basic_main(); } #else // CYGFUN_KERNEL_API_C externC void cyg_start( void ) { CYG_TEST_INIT(); CYG_TEST_INFO("Timing tests require:\n" "CYGFUN_KERNEL_API_C && \n" "CYGSEM_KERNEL_SCHED_MLQUEUE &&\n" "CYGVAR_KERNEL_COUNTERS_CLOCK &&\n" "!CYGDBG_INFRA_DIAG_USE_DEVICE &&\n" "(CYGNUM_KERNEL_SCHED_PRIORITIES > 12)\n"); CYG_TEST_NA("Timing tests requirements"); } #endif // CYGFUN_KERNEL_API_C, etc. // EOF tm_basic.cxx
