diff packages/kernel/current/tests/tm_basic.cxx @ 0:3111d98ba7b3 ecos-v1_1-release

Initial commit of eCos version 1.1
author jlarmour
date Tue, 11 May 1999 11:16:07 +0000
parents
children 443894e2e912
line wrap: on
line diff
new file mode 100644
--- /dev/null
+++ b/packages/kernel/current/tests/tm_basic.cxx
@@ -0,0 +1,1302 @@
+//==========================================================================
+//
+//        tm_basic.cxx
+//
+//        Basic timing test / scaffolding
+//
+//==========================================================================
+//####COPYRIGHTBEGIN####
+//
+// -------------------------------------------
+// The contents of this file are subject to the Cygnus eCos Public License
+// Version 1.0 (the "License"); you may not use this file except in
+// compliance with the License.  You may obtain a copy of the License at
+// http://sourceware.cygnus.com/ecos
+// 
+// Software distributed under the License is distributed on an "AS IS"
+// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the
+// License for the specific language governing rights and limitations under
+// the License.
+// 
+// The Original Code is eCos - Embedded Cygnus Operating System, released
+// September 30, 1998.
+// 
+// The Initial Developer of the Original Code is Cygnus.  Portions created
+// by Cygnus are Copyright (C) 1998 Cygnus Solutions.  All Rights Reserved.
+// -------------------------------------------
+//
+//####COPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):     gthomas
+// Contributors:  gthomas
+// Date:          1998-10-19
+// Description:   Very simple timing test setup
+//####DESCRIPTIONEND####
+
+#include <pkgconf/kernel.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/sched.inl>
+#include <cyg/kernel/clock.hxx>
+#include <cyg/kernel/clock.inl>
+#include <cyg/kernel/kapi.h>
+
+#include <cyg/infra/testcase.h>
+#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 NSAMPLES         10
+#define NTEST_THREADS    32
+#define NTHREAD_SWITCHES 128
+#define NMUTEXES         32
+#define NMBOXES          32
+#define NSEMAPHORES      32
+#define NSCHEDS          128
+#define NCOUNTERS        32
+#define NALARMS          32
+
+#define STACK_SIZE 2048     // Is this large enough?
+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];
+static cyg_thread mbox_test_thread;
+static cyg_handle_t mbox_test_thread_handle;
+
+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_alarm test_alarms[NALARMS];
+static cyg_handle_t alarms[NALARMS];
+static fun_times alarm_ft[NALARMS];
+
+externC void diag_printf(const char *, ...);
+externC void sprintf(char *, const char *, ...);
+
+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_alarm_tests(void);
+
+#ifdef HAL_CLOCK_LATENCY
+extern cyg_tick_count total_clock_latency, total_clock_interrupts;
+extern cyg_int32 min_clock_latency, max_clock_latency;
+#endif
+
+cyg_uint32
+ticks_to_us(cyg_uint32 ticks)
+{
+    int us;
+    // Assumes that the clock is set up for 10ms ticks
+    us = (10000 * ticks) / CYGNUM_KERNEL_COUNTERS_RTC_PERIOD;
+    return (us);
+}
+
+// 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_uint32 tv0, tv1;
+    HAL_CLOCK_READ(&tv0);
+    while (true) {
+        HAL_CLOCK_READ(&tv1);
+        if (tv1 < tv0) break;
+        tv0 = tv1;
+    }
+}
+
+// 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)
+{
+    diag_printf("test0.%d executed?\n", indx);
+    cyg_thread_exit();
+}
+
+// test1 - empty test, simply exit.  Last thread signals parent.
+void
+test1(cyg_uint32 indx)
+{
+    if (indx == (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();
+}
+
+void
+show_times_hdr(void)
+{
+    diag_printf("\n");
+    diag_printf("   Ave     Min     Max Variance   Function\n");
+    diag_printf("======  ======  ====== ========   ========\n");
+}
+
+void
+show_times(fun_times ft[], int nsamples, char *title)
+{
+    int i, delta, min, max;
+    cyg_uint32 total, ave, var;
+    total = 0;
+    min = 0x7FFFFFFF;
+    max = 0;
+    for (i = 0;  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 -= 2*overhead;
+        if (delta < 0) delta = 0;
+        total += delta;
+        if (delta < min) min = delta;
+        if (delta > max) max = delta;
+    }
+    ave = total / nsamples;
+    total = 0;
+    for (i = 0;  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 -= 2*overhead;
+        if (delta < 0) delta = 0;
+        total = (delta - ave) * (delta - ave);
+    }
+    var = total / (nsamples - 1);
+    diag_printf("%6d  %6d  %6d   %6d   %s\n",
+                ticks_to_us(ave),  ticks_to_us(min),  ticks_to_us(max), ticks_to_us(var), title);
+}
+
+void
+show_test_parameters(void)
+{
+    diag_printf("\nTesting parameters:\n");
+    diag_printf("   Clock samples:         %3d\n", NSAMPLES);
+    diag_printf("   Threads:               %3d\n", NTEST_THREADS);
+    diag_printf("   Thread switches:       %3d\n", NTHREAD_SWITCHES);
+    diag_printf("   Mutexes:               %3d\n", NMUTEXES);
+    diag_printf("   Mailboxes:             %3d\n", NMBOXES);
+    diag_printf("   Semaphores:            %3d\n", NSEMAPHORES);
+    diag_printf("   Scheduler operations:  %3d\n", NSCHEDS);
+    diag_printf("   Counters:              %3d\n", NCOUNTERS);
+    diag_printf("   Alarms:                %3d\n", NALARMS);
+    diag_printf("\n"); 
+}
+
+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 priority] 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 priority] 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] thread");
+    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");
+    // 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_kill(threads[i]);
+    }
+
+    run_thread_switch_test();
+}
+
+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_kill(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");
+
+    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();
+}
+
+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);
+    }
+    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");
+
+    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");
+
+    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();
+}
+
+void
+run_mbox_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 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);
+    }
+    show_times(mbox_ft, NMBOXES, "Put/Get mbox");
+}
+
+void
+run_semaphore_tests(void)
+{
+    int i;
+    cyg_ucount32 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();
+}
+
+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);
+    }
+    show_times(semaphore_ft, NSEMAPHORES, "Post/Wait semaphore");
+}
+
+void
+run_counter_tests(void)
+{
+    int i;
+    cyg_tick_count_t val;
+
+    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");
+}
+
+// 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);
+    }
+}
+
+// Null thread, used to keep scheduler busy
+void
+alarm_test(cyg_uint32 id)
+{
+    while (true) {
+        cyg_thread_yield();
+    }
+}
+
+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 < NCOUNTERS;  i++) {
+        HAL_CLOCK_READ(&counter_ft[i].start);
+        cyg_counter_tick(counters[0]);
+        HAL_CLOCK_READ(&counter_ft[i].end);
+    }
+    for (i = 0;  i < NALARMS;  i++) {
+        cyg_alarm_delete(alarms[i]);
+    }
+    show_times(counter_ft, NCOUNTERS, "Tick & fire counter [many alarms]");
+
+    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_kill(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_kill(threads[i]);
+    }
+}
+
+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 thread]");
+    for (i = 0;  i < 1;  i++) {
+        cyg_thread_kill(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 threads]");
+    for (i = 0;  i < NTEST_THREADS;  i++) {
+        cyg_thread_kill(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 threads]");
+    for (i = 0;  i < NTEST_THREADS;  i++) {
+        cyg_thread_kill(threads[i]);
+    }
+}
+
+void 
+run_all_tests(CYG_ADDRESS id)
+{
+    int i;
+    cyg_uint32 tv[NSAMPLES], tv0, tv1, us;
+    cyg_tick_count_t ticks;
+#ifdef CYG_SCHEDULER_LOCK_TIMINGS
+    cyg_uint32 lock_ave, lock_max;
+#endif
+#ifdef HAL_CLOCK_LATENCY
+    cyg_int32 clock_ave;
+#endif
+
+    for (i = 0;  i < NSAMPLES;  i++) {
+        HAL_CLOCK_READ(&tv[i]);
+    }
+    diag_printf("Clock: ");
+    tv0 = 0;
+    for (i = 0;  i < NSAMPLES;  i++) {
+        diag_printf("%x ", tv[i]);
+        if (i > 0) {
+            tv0 += tv[i] - tv[i-1];
+        }
+    }
+    diag_printf("\n");
+    
+    overhead = tv0 / (NSAMPLES-1);
+    diag_printf("Average %d clock ticks overhead\n", overhead);
+
+    // Try and measure how long the clock interrupt handling takes
+    HAL_CLOCK_READ(&tv0);
+    while (true) {
+        HAL_CLOCK_READ(&tv1);
+        if (tv1 < tv0) break;
+        tv0 = tv1;
+    }
+    tv1 -= overhead;  // Adjust out the cost of getting the timer value
+    us = ticks_to_us(tv1);
+    diag_printf("Clock interrupt took %d microseconds (%d clock ticks)\n", us, tv1);
+
+    ticks = cyg_current_time();
+    diag_printf("Ticks: %x\n", (int)ticks);
+
+    show_test_parameters();
+    show_times_hdr();
+
+    run_thread_tests();
+    run_sched_tests();
+    run_mutex_tests();
+    run_mbox_tests();
+    run_semaphore_tests();
+    run_counter_tests();
+    run_alarm_tests();
+
+#ifdef CYG_SCHEDULER_LOCK_TIMINGS
+    Cyg_Scheduler::get_lock_times(&lock_ave, &lock_max);
+    diag_printf("\nMax lock: %d, Ave lock: %d\n", ticks_to_us(lock_max), ticks_to_us(lock_ave));
+#endif
+
+#ifdef HAL_CLOCK_LATENCY
+    clock_ave = total_clock_latency / total_clock_interrupts;
+    diag_printf("\nClock/interrupt latency - ave: %d, min: %d, max: %d\n",
+                ticks_to_us(clock_ave), ticks_to_us(min_clock_latency), ticks_to_us(max_clock_latency));
+#endif
+
+    ticks = cyg_current_time();
+    diag_printf("\nTiming complete - %d ms total\n", (int)ticks*10);
+
+    CYG_TEST_PASS_FINISH("Basic timing OK");
+}
+
+void tm_basic_main( void )
+{
+    CYG_TEST_INIT();
+
+    new_thread(run_all_tests, 0);
+    
+    Cyg_Scheduler::scheduler.start();
+}
+
+externC void
+cyg_start( void )
+{
+    tm_basic_main();
+}   
+// EOF tm_basic.cxx