[rtems commit] Added Rhealstone benchmark to testsuites

Joel Sherrill joel at rtems.org
Sun Jan 5 17:10:23 UTC 2014


Module:    rtems
Branch:    master
Commit:    19e9bf88004008308e0c9c7039a166c49477e0d1
Changeset: http://git.rtems.org/rtems/commit/?id=19e9bf88004008308e0c9c7039a166c49477e0d1

Author:    Daniel Ramirez <javamonn at gmail.com>
Date:      Sat Jan  4 13:58:44 2014 -0600

Added Rhealstone benchmark to testsuites

The Rhealstone benchmarks six operations that are critical components
of a real-time system. It allows for an objective analysis to be
performed, and allows for comparisons between systems.
See rhealstone/README for more information.

---

 testsuites/configure.ac                            |    2 +-
 testsuites/rhealstone/Makefile.am                  |    6 +
 testsuites/rhealstone/README                       |   22 ++
 testsuites/rhealstone/configure.ac                 |   35 ++++
 testsuites/rhealstone/deadlockbrk/Makefile.am      |   23 +++
 testsuites/rhealstone/deadlockbrk/deadlockbrk.adoc |   37 ++++
 testsuites/rhealstone/deadlockbrk/deadlockbrk.c    |  206 ++++++++++++++++++++
 testsuites/rhealstone/ilatency/Makefile.am         |   23 +++
 testsuites/rhealstone/ilatency/ilatency.adoc       |   21 ++
 testsuites/rhealstone/ilatency/ilatency.c          |  119 +++++++++++
 testsuites/rhealstone/mlatency/Makefile.am         |   23 +++
 testsuites/rhealstone/mlatency/mlatency.adoc       |   22 ++
 testsuites/rhealstone/mlatency/mlatency.c          |  150 ++++++++++++++
 testsuites/rhealstone/semshuffle/Makefile.am       |   23 +++
 testsuites/rhealstone/semshuffle/semshuffle.adoc   |   26 +++
 testsuites/rhealstone/semshuffle/semshuffle.c      |  158 +++++++++++++++
 testsuites/rhealstone/taskpreempt/Makefile.am      |   23 +++
 testsuites/rhealstone/taskpreempt/taskpreempt.adoc |   36 ++++
 testsuites/rhealstone/taskpreempt/taskpreempt.c    |  113 +++++++++++
 testsuites/rhealstone/taskswitch/Makefile.am       |   23 +++
 testsuites/rhealstone/taskswitch/taskswitch.adoc   |   27 +++
 testsuites/rhealstone/taskswitch/taskswitch.c      |  116 +++++++++++
 22 files changed, 1233 insertions(+), 1 deletions(-)

diff --git a/testsuites/configure.ac b/testsuites/configure.ac
index df83c2a..db8efc7 100644
--- a/testsuites/configure.ac
+++ b/testsuites/configure.ac
@@ -41,7 +41,7 @@ if test "$enable_tests" = "yes"; then
     AC_CONFIG_SUBDIRS(smptests)
   fi
   # Now do performance tests
-  AC_CONFIG_SUBDIRS(tmtests psxtmtests)
+  AC_CONFIG_SUBDIRS(tmtests psxtmtests rhealstone)
 fi
 
 # Explicitly list all Makefiles here
diff --git a/testsuites/rhealstone/Makefile.am b/testsuites/rhealstone/Makefile.am
new file mode 100644
index 0000000..d67dcf4
--- /dev/null
+++ b/testsuites/rhealstone/Makefile.am
@@ -0,0 +1,6 @@
+ACLOCAL_AMFLAGS = -I ../aclocal
+
+SUBDIRS = taskswitch taskpreempt ilatency mlatency semshuffle deadlockbrk
+
+include $(top_srcdir)/../automake/subdirs.am
+include $(top_srcdir)/../automake/local.am
diff --git a/testsuites/rhealstone/README b/testsuites/rhealstone/README
new file mode 100644
index 0000000..5b4b6fb
--- /dev/null
+++ b/testsuites/rhealstone/README
@@ -0,0 +1,22 @@
+== Rhealstone Benchmark For RTEMS
+
+This is an implementation of the Rhealstone benchmarks for RTEMS.
+
+The Rhealstone metric is a set of benchmarks that aim to provide an independently
+verifiable objective measure of real-time performance in different systems. The
+Rhealstone metric is composed of six independent benchmarks, each of which measure
+an activity that is critical in real time systems:
+
+* Task switch time
+* Task preemption time
+* Interrupt latency time
+* Semaphore shuffle time
+* Deadlock breaking time
+* Intertask message latency
+
+An implementation of the Rhealstone metric allows for RTEMS performance to be
+compared with other real-time systems.
+
+The original proposal outlining the Rhealstone benchmark can be found http://collaboration.cmc.ec.gc.ca/science/rpn/biblio/ddj/Website/articles/DDJ/1989/8902/8902a/8902a.htm[here].
+
+Some other implementations can be seen in http://timsengineeringblog.weebly.com/masters-thesis.html[FreeRTOS] and http://collaboration.cmc.ec.gc.ca/science/rpn/biblio/ddj/Website/articles/DDJ/1990/9004/9004d/9004d.htm[iRMX].
diff --git a/testsuites/rhealstone/configure.ac b/testsuites/rhealstone/configure.ac
new file mode 100644
index 0000000..e61dc2e
--- /dev/null
+++ b/testsuites/rhealstone/configure.ac
@@ -0,0 +1,35 @@
+## Process this file with autoconf to produce a configure script.
+
+AC_PREREQ([2.69])
+AC_INIT([rtems-c-src-tests-rhealstone],[_RTEMS_VERSION],[http://www.rtems.org/bugzilla])
+AC_CONFIG_SRCDIR([taskswitch])
+AC_CONFIG_HEADER([config.h])
+RTEMS_TOP([../..],[..])
+
+RTEMS_CANONICAL_TARGET_CPU
+
+AM_INIT_AUTOMAKE([no-define foreign 1.12.2])
+AM_MAINTAINER_MODE
+
+RTEMS_ENV_RTEMSBSP
+
+RTEMS_CHECK_RTEMS_TEST_NO_PAUSE
+
+RTEMS_PROJECT_ROOT
+
+RTEMS_PROG_CC_FOR_TARGET
+
+RTEMS_CANONICALIZE_TOOLS
+
+RTEMS_CHECK_CUSTOM_BSP(RTEMS_BSP)
+
+# Explicitly list all Makefiles here
+AC_CONFIG_FILES([Makefile
+taskswitch/Makefile
+taskpreempt/Makefile
+ilatency/Makefile
+mlatency/Makefile
+semshuffle/Makefile
+deadlockbrk/Makefile
+])
+AC_OUTPUT
diff --git a/testsuites/rhealstone/deadlockbrk/Makefile.am b/testsuites/rhealstone/deadlockbrk/Makefile.am
new file mode 100644
index 0000000..8db2141
--- /dev/null
+++ b/testsuites/rhealstone/deadlockbrk/Makefile.am
@@ -0,0 +1,23 @@
+MANAGERS = all
+
+rtems_tests_PROGRAMS = deadlockbrk
+deadlockbrk_SOURCES  = deadlockbrk.c
+deadlockbrk_SOURCES += ../../tmtests/include/timesys.h
+
+dist_rtems_tests_DATA = deadlockbrk.adoc
+
+include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP at .cfg
+include $(top_srcdir)/../automake/compile.am
+include $(top_srcdir)/../automake/leaf.am
+
+AM_CPPFLAGS += -I$(top_srcdir)/../tmtests/include
+AM_CPPFLAGS += -I$(top_srcdir)/../support/include
+
+LINK_OBJS = $(deadlockbrk_OBJECTS) $(deadlockbrk_LDADD)
+LINK_LIBS = $(deadlockbrk_LDLIBS)
+
+deadlockbrk$(EXEEXT): $(deadlockbrk_OBJECTS) $(deadlockbrk_DEPENDENCIES)
+	@rm -f deadlockbrk$(EXEEXT)
+	$(make-exe)
+
+include $(top_srcdir)/../automake/local.am
diff --git a/testsuites/rhealstone/deadlockbrk/deadlockbrk.adoc b/testsuites/rhealstone/deadlockbrk/deadlockbrk.adoc
new file mode 100644
index 0000000..a26cd47
--- /dev/null
+++ b/testsuites/rhealstone/deadlockbrk/deadlockbrk.adoc
@@ -0,0 +1,37 @@
+= Deadlock Break Benchmark
+
+This benchmark measures the average time to break a deadlock that occurs
+when a high priority task preempts a low priority task that is holding a
+resource that the high priority task needs. In RTEMS, these situations
+are mitigated through use of a semaphore with priority inheritance. A
+task holding a semaphore with priority inheritance enabled has its
+priority boosted to match that of the highest priority task blocked on
+that semaphore.
+
+== Directives
+
+  * rtems_semaphore_obtain
+  * rtems_semaphore_release
+  * rtems_task_suspend
+  * rtems_task_resume
+
+
+== Methodology
+
+This benchmark is structured in a way that is very similar to the semaphore-
+shuffle benchmark, but instead uses three tasks of differing priorities and
+suspend/resume instead of yield directives.
+
+The benchmark is run and timed once with no semaphore operations. This is the
+overhead time. The benchmark starts with the high priority task, which suspends
+itself, passing control to the mid priority task. The mid priority task then
+suspends itself, passing control to the low priority task. The low priority task
+resumes the mid priority task, which then resumes the high priority task. The
+process is repeated a total of BENCHMARKS times. This process is then executed
+with the low priority task holding a semaphore that the high priority task blocks
+on when trying to obtain. Due to priority inheritance (the deadlock break
+mechanism) the low priority task will execute instead of the mid priority task.
+The same system of suspend/resumes then occurs.
+
+The average is found and the overhead (the time of the first run) is subtracted
+out in the call to put_time.
diff --git a/testsuites/rhealstone/deadlockbrk/deadlockbrk.c b/testsuites/rhealstone/deadlockbrk/deadlockbrk.c
new file mode 100644
index 0000000..f8d30b9
--- /dev/null
+++ b/testsuites/rhealstone/deadlockbrk/deadlockbrk.c
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 2014 Daniel Ramirez. (javamonn at gmail.com)
+ *
+ * This file's license is 2-clause BSD as in this distribution's LICENSE file.
+ */
+
+#include <rtems/timerdrv.h>
+#include <timesys.h>
+
+#define BENCHMARKS 20000
+
+rtems_task Task01( rtems_task_argument ignored );
+rtems_task Task02( rtems_task_argument ignored );
+rtems_task Task03( rtems_task_argument ignored );
+rtems_task Init( rtems_task_argument ignored );
+
+rtems_id           Task_id[3];
+rtems_name         Task_name[3];
+rtems_id           sem_id;
+rtems_name         sem_name;
+rtems_status_code  status;
+
+uint32_t count;
+uint32_t telapsed;
+uint32_t tswitch_overhead;
+uint32_t tobtain_overhead;
+uint32_t sem_exe;
+
+rtems_task Init( rtems_task_argument ignored )
+{
+  rtems_attribute      sem_attr;
+  rtems_task_priority  pri;
+  rtems_mode           prev_mode;
+
+  sem_attr = RTEMS_INHERIT_PRIORITY | RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY;
+
+  sem_name = rtems_build_name( 'S','0',' ',' ' );
+  status = rtems_semaphore_create(
+    sem_name,
+    1,
+    sem_attr,
+    0,
+    &sem_id
+  );
+  directive_failed( status, "rtems_semaphore_create of S0" );
+
+  Task_name[0] = rtems_build_name( 'T','A','0','1' );
+  status = rtems_task_create(
+    Task_name[0],
+    26,  /* High priority task */
+    RTEMS_MINIMUM_STACK_SIZE,
+    RTEMS_DEFAULT_MODES,
+    RTEMS_DEFAULT_ATTRIBUTES,
+    &Task_id[0]
+  );
+  directive_failed( status, "rtems_task_create of TA01" );
+
+  Task_name[1] = rtems_build_name( 'T','A','0','2' );
+  status = rtems_task_create(
+    Task_name[1],
+    28,  /* Mid priority task */
+    RTEMS_MINIMUM_STACK_SIZE,
+    RTEMS_DEFAULT_MODES,
+    RTEMS_DEFAULT_ATTRIBUTES,
+    &Task_id[1]
+  );
+  directive_failed( status, "rtems_task_create of TA02" );
+
+  Task_name[2] = rtems_build_name( 'T','A','0','3' );
+  status = rtems_task_create(
+    Task_name[2],
+    30,  /* Low priority task */
+    RTEMS_MINIMUM_STACK_SIZE,
+    RTEMS_DEFAULT_MODES,
+    RTEMS_DEFAULT_ATTRIBUTES,
+    &Task_id[2]
+  );
+  directive_failed( status, "rtems_task_create of TA03" );
+
+  /* find overhead of obtaining semaphore */
+  benchmark_timer_initialize();
+  rtems_semaphore_obtain( sem_id, RTEMS_WAIT, 0 );
+  tobtain_overhead = benchmark_timer_read();
+  rtems_semaphore_release( sem_id );
+
+  rtems_task_mode( RTEMS_PREEMPT, RTEMS_PREEMPT_MASK, &prev_mode );
+  /* Lower own priority so tasks can start up and run */
+  rtems_task_set_priority( RTEMS_SELF, 40, &pri );
+
+  /* Get time of benchmark with no semaphores involved, i.e. find overhead */
+  sem_exe = 0;
+  status = rtems_task_start( Task_id[2], Task03, 0 );
+  directive_failed( status, "rtems_task_start of TA03" );
+
+  /* Get time of benchmark with semaphores */
+  sem_exe = 1;
+  status = rtems_task_restart( Task_id[2], 0 );
+  directive_failed( status, "rtems_task_start of TA03" );
+
+  /* Should never reach here */
+  rtems_test_assert( false );
+}
+
+rtems_task Task01( rtems_task_argument ignored )
+{
+  /* All tasks have had time to start up once TA01 is running */
+
+  /* Benchmark code */
+  benchmark_timer_initialize();
+  for ( count = 0; count < BENCHMARKS; count++ ) {
+    if ( sem_exe == 1 ) {
+      /* Block on call */
+      rtems_semaphore_obtain( sem_id, RTEMS_WAIT, 0 );
+    }
+
+    if ( sem_exe == 1 ) {
+      /* Release semaphore immediately after obtaining it */
+      rtems_semaphore_release( sem_id );
+    }
+
+    /* Suspend self, go to TA02 */
+    rtems_task_suspend( RTEMS_SELF );
+  }
+  telapsed = benchmark_timer_read();
+
+  /* Check which run this was */
+  if (sem_exe == 0) {
+    tswitch_overhead = telapsed;
+    rtems_task_suspend( Task_id[1] );
+    rtems_task_suspend( Task_id[2] );
+    rtems_task_suspend( RTEMS_SELF );
+  } else {
+    put_time(
+       "Rhealstone: Deadlock Break",
+       telapsed,
+       BENCHMARKS,              /* Total number of times deadlock broken*/
+       tswitch_overhead,        /* Overhead of loop and task switches */
+       tobtain_overhead
+    );
+    rtems_test_exit( 0 );
+  }
+
+}
+
+rtems_task Task02( rtems_task_argument ignored )
+{
+  /* Start up TA01, get preempted */
+  if ( sem_exe == 1) {
+    status = rtems_task_restart( Task_id[0], 0);
+    directive_failed( status, "rtems_task_start of TA01");
+  } else {
+    status = rtems_task_start( Task_id[0], Task01, 0);
+    directive_failed( status, "rtems_task_start of TA01");
+  }
+
+  /* Benchmark code */
+  for ( ; count < BENCHMARKS ; ) {
+    /* Suspend self, go to TA01 */
+    rtems_task_suspend( RTEMS_SELF );
+
+    /* Wake up TA01, get preempted */
+    rtems_task_resume( Task_id[0] );
+  }
+}
+
+rtems_task Task03( rtems_task_argument ignored )
+{
+  if (sem_exe == 1) {
+    /* Low priority task holds mutex */
+    rtems_semaphore_obtain( sem_id, RTEMS_WAIT, 0 );
+  }
+
+  /* Start up TA02, get preempted */
+  if ( sem_exe == 1) {
+    status = rtems_task_restart( Task_id[1], 0);
+    directive_failed( status, "rtems_task_start of TA02");
+  } else {
+    status = rtems_task_start( Task_id[1], Task02, 0);
+    directive_failed( status, "rtems_task_start of TA02");
+  }
+
+  /* Benchmark code */
+  for ( ; count < BENCHMARKS ; ) {
+    if ( sem_exe == 1 ) {
+      /* Preempted by TA01 upon release */
+      rtems_semaphore_release( sem_id );
+    }
+
+    if ( sem_exe == 1 ) {
+      /* Prepare for next Benchmark */
+      rtems_semaphore_obtain( sem_id, RTEMS_WAIT, 0 );
+    }
+    /* Wake up TA02, get preempted */
+    rtems_task_resume( Task_id[1] );
+  }
+}
+
+/* configuration information */
+#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
+#define CONFIGURE_APPLICATION_NEEDS_TIMER_DRIVER
+#define CONFIGURE_TICKS_PER_TIMESLICE        0
+#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
+#define CONFIGURE_MAXIMUM_SEMAPHORES 1
+#define CONFIGURE_MAXIMUM_TASKS 4
+#define CONFIGURE_INIT
+#include <rtems/confdefs.h>
diff --git a/testsuites/rhealstone/ilatency/Makefile.am b/testsuites/rhealstone/ilatency/Makefile.am
new file mode 100644
index 0000000..3cd696e
--- /dev/null
+++ b/testsuites/rhealstone/ilatency/Makefile.am
@@ -0,0 +1,23 @@
+MANAGERS = all
+
+rtems_tests_PROGRAMS = ilatency
+ilatency_SOURCES  = ilatency.c
+ilatency_SOURCES += ../../tmtests/include/timesys.h
+
+dist_rtems_tests_DATA = ilatency.adoc
+
+include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP at .cfg
+include $(top_srcdir)/../automake/compile.am
+include $(top_srcdir)/../automake/leaf.am
+
+AM_CPPFLAGS += -I$(top_srcdir)/../tmtests/include
+AM_CPPFLAGS += -I$(top_srcdir)/../support/include
+
+LINK_OBJS = $(ilatency_OBJECTS) $(ilatency_LDADD)
+LINK_LIBS = $(ilatency_LDLIBS)
+
+ilatency$(EXEEXT): $(ilatency_OBJECTS) $(ilatency_DEPENDENCIES)
+	@rm -f ilatency$(EXEEXT)
+	$(make-exe)
+
+include $(top_srcdir)/../automake/local.am
diff --git a/testsuites/rhealstone/ilatency/ilatency.adoc b/testsuites/rhealstone/ilatency/ilatency.adoc
new file mode 100644
index 0000000..2f8a980
--- /dev/null
+++ b/testsuites/rhealstone/ilatency/ilatency.adoc
@@ -0,0 +1,21 @@
+= Interrupt Latency Benchmark
+
+This benchmark measures the time between the CPU's receipt of an interrupt
+request and the execution of the first intruction in that interrupt service
+routine.
+
+== Directives
+
+  * Intall_tm27_vector
+  * Cause_tm27_intr
+
+
+== Methodology
+
+This benchmark takes advantage of the existing tm27 test support implemented
+by most BSP's to achieve as much hardware independence as possible. Most BSPs
+have an instruction to install an interrupt vector, and then provide code for
+the ISR. rtems/testsuites/tmtests/tm27 uses this to test a variety of interrupt
+related concepts. The benchmark is simple, the vector is installed, the time
+is started, the interrupt is caused, and the time is ended in the first
+instruction of the ISR. This is the only Rhealstone that is not an average.
diff --git a/testsuites/rhealstone/ilatency/ilatency.c b/testsuites/rhealstone/ilatency/ilatency.c
new file mode 100644
index 0000000..df21341
--- /dev/null
+++ b/testsuites/rhealstone/ilatency/ilatency.c
@@ -0,0 +1,119 @@
+/* Copyright 2014 Daniel Ramirez (javamonn at gmail.com)
+ *
+ * This file's license is 2-clause BSD as in this distribution's LICENSE.2 file.
+ */
+
+/*
+ *  WARNING!!!!!!!!!
+ *
+ *  THIS TEST USES INTERNAL RTEMS VARIABLES!!!
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#define CONFIGURE_INIT
+#include <timesys.h>
+#include <rtems/timerdrv.h>
+#include <coverhd.h>
+
+/* configuration information */
+#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
+#define CONFIGURE_APPLICATION_NEEDS_TIMER_DRIVER
+#define CONFIGURE_MAXIMUM_TASKS              2
+#define CONFIGURE_TICKS_PER_TIMESLICE        0
+#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
+#define CONFIGURE_SCHEDULER_PRIORITY
+
+#include <rtems/confdefs.h>
+
+#include <bsp.h>
+
+#define _RTEMS_TMTEST27
+#include <tm27.h>
+
+#define BENCHMARKS 50000
+
+rtems_task Task_1(
+  rtems_task_argument argument
+);
+
+uint32_t   Interrupt_nest;
+uint32_t   timer_overhead;
+uint32_t   Interrupt_enter_time;
+
+rtems_isr Isr_handler(
+  rtems_vector_number vector
+);
+
+rtems_task Init(
+  rtems_task_argument argument
+)
+{
+  rtems_status_code status;
+  rtems_id Task_id
+
+  Print_Warning();
+
+  if (_Scheduler.Operations.initialize != _Scheduler_priority_Initialize) {
+    puts( "  Error ==> " );
+    puts( "Test only supported for deterministic priority scheduler\n" );
+    rtems_test_exit( 0 );
+  }
+
+#define LOW_PRIORITY (RTEMS_MAXIMUM_PRIORITY - 1u)
+  status = rtems_task_create(
+    rtems_build_name( 'T', 'A', '1', ' ' ),
+    LOW_PRIORITY,
+    RTEMS_MINIMUM_STACK_SIZE,
+    RTEMS_DEFAULT_MODES,
+    RTEMS_DEFAULT_ATTRIBUTES,
+    &Task_id
+  );
+  directive_failed( status, "rtems_task_create Task_1" );
+
+  status = rtems_task_start( Task_id, Task_1, 0 );
+  directive_failed( status, "rtems_task_start Task_1" );
+
+  benchmark_timer_initialize();
+  benchmark_timer_read();
+  benchmark_timer_initialize();
+  timer_overhead = benchmark_timer_read();
+
+  status = rtems_task_delete( RTEMS_SELF );
+  directive_failed( status, "rtems_task_delete of RTEMS_SELF" );
+}
+
+rtems_task Task_1(
+  rtems_task_argument argument
+)
+{
+  Install_tm27_vector( Isr_handler ) ;
+  Interrupt_nest = 0;
+  _Thread_Dispatch_set_disable_level( 0 );
+
+  /* Benchmark code */
+  benchmark_timer_initialize();
+  /* goes to Isr_handler */
+  Cause_tm27_intr();
+
+  put_time(
+    "Rhealstone: Interrupt Latency",
+    Interrupt_enter_time,
+    1,                             /* Only Rhealstone that isn't an average */
+    timer_overhead,
+    0
+  );
+
+  rtems_test_exit( 0 );
+}
+
+rtems_isr Isr_handler(
+  rtems_vector_number vector
+)
+{
+  /* See how long it took system to recognize interrupt */
+  Interrupt_enter_time = benchmark_timer_read();
+  Clear_tm27_intr();
+}
diff --git a/testsuites/rhealstone/mlatency/Makefile.am b/testsuites/rhealstone/mlatency/Makefile.am
new file mode 100644
index 0000000..0984438
--- /dev/null
+++ b/testsuites/rhealstone/mlatency/Makefile.am
@@ -0,0 +1,23 @@
+MANAGERS = all
+
+rtems_tests_PROGRAMS = mlatency
+mlatency_SOURCES  = mlatency.c
+mlatency_SOURCES += ../../tmtests/include/timesys.h
+
+dist_rtems_tests_DATA = mlatency.adoc
+
+include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP at .cfg
+include $(top_srcdir)/../automake/compile.am
+include $(top_srcdir)/../automake/leaf.am
+
+AM_CPPFLAGS += -I$(top_srcdir)/../tmtests/include
+AM_CPPFLAGS += -I$(top_srcdir)/../support/include
+
+LINK_OBJS = $(mlatency_OBJECTS) $(mlatency_LDADD)
+LINK_LIBS = $(mlatency_LDLIBS)
+
+mlatency$(EXEEXT): $(mlatency_OBJECTS) $(mlatency_DEPENDENCIES)
+	@rm -f mlatency$(EXEEXT)
+	$(make-exe)
+
+include $(top_srcdir)/../automake/local.am
diff --git a/testsuites/rhealstone/mlatency/mlatency.adoc b/testsuites/rhealstone/mlatency/mlatency.adoc
new file mode 100644
index 0000000..fd445ca
--- /dev/null
+++ b/testsuites/rhealstone/mlatency/mlatency.adoc
@@ -0,0 +1,22 @@
+= Message Latency Benchmark
+
+This benchmark measures the intertask message latency. This is the delay within
+RTEMS between a running task using the rtems_message_queue to send a message to
+a waiting task and that task waking up and receiving the message.
+
+== Directives
+
+  * rtems_message_queue_send
+  * rtems_message_queue_receive
+
+
+== Methodology
+
+This benchmark consists of a high priority task and a low priority task. The
+benchmark starts in the high priority task, which blocks on a call to rtems_
+message_queue recieve. By accounting for the overhead of the task switch from
+the high priority task to the low priority task, and the actual time to recieve
+the message, the intertask message latency is found.
+
+The average is found and the overhead (the time of the first run) is subtracted
+out in the call to put_time.
diff --git a/testsuites/rhealstone/mlatency/mlatency.c b/testsuites/rhealstone/mlatency/mlatency.c
new file mode 100644
index 0000000..3752eed
--- /dev/null
+++ b/testsuites/rhealstone/mlatency/mlatency.c
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2014 Daniel Ramirez. (javamonn at gmail.com)
+ *
+ * This file's license is 2-clause BSD as in this distribution's LICENSE file.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <timesys.h>
+#include <rtems/timerdrv.h>
+
+#define MESSAGE_SIZE (sizeof(long) * 4)
+#define BENCHMARKS 50000
+
+rtems_task Init( rtems_task_argument ignored );
+rtems_task Task01( rtems_task_argument ignored );
+rtems_task Task02( rtems_task_argument ignored );
+
+uint32_t    telapsed;
+uint32_t    tloop_overhead;
+uint32_t    treceive_overhead;
+uint32_t    count;
+rtems_id    Task_id[2];
+rtems_name  Task_name[2];
+rtems_id    Queue_id;
+long        Buffer[4];
+
+void Init(
+  rtems_task_argument argument
+)
+{
+  rtems_status_code status;
+
+  status = rtems_message_queue_create(
+    rtems_build_name( 'M', 'Q', '1', ' '  ),
+    1,
+    MESSAGE_SIZE,
+    RTEMS_DEFAULT_ATTRIBUTES,
+    &Queue_id
+  );
+  directive_failed( status, "rtems_message_queue_create" );
+
+  Task_name[0] = rtems_build_name( 'T','A','0','1' );
+  status = rtems_task_create(
+    Task_name[0],
+    30,               /* TA01 is low priority task */
+    RTEMS_MINIMUM_STACK_SIZE,
+    RTEMS_DEFAULT_MODES,
+    RTEMS_DEFAULT_ATTRIBUTES,
+    &Task_id[0]
+  );
+  directive_failed( status, "rtems_task_create of TA01");
+
+  Task_name[1] = rtems_build_name( 'T','A','0','2' );
+  status = rtems_task_create(
+    Task_name[1],
+    28,               /* High priority task */
+    RTEMS_MINIMUM_STACK_SIZE,
+    RTEMS_DEFAULT_MODES,
+    RTEMS_DEFAULT_ATTRIBUTES,
+    &Task_id[1]
+  );
+  directive_failed( status, "rtems_task_create of TA01" );
+
+  benchmark_timer_initialize();
+  for ( count = 0; count < BENCHMARKS - 1; count++ ) {
+    /* message send/recieve */
+  }
+  tloop_overhead = benchmark_timer_read();
+
+  status = rtems_task_start( Task_id[0], Task01, 0 );
+  directive_failed( status, "rtems_task_start of TA01" );
+
+  status = rtems_task_delete( RTEMS_SELF );
+  directive_failed( status, "rtems_task_delete of RTEMS_SELF" );
+}
+
+rtems_task Task01( rtems_task_argument ignored )
+{
+  rtems_status_code status;
+
+  /* Put a message in the queue so recieve overhead can be found. */
+  (void) rtems_message_queue_send( Queue_id, Buffer, MESSAGE_SIZE );
+
+  /* Start up second task, get preempted */
+  status = rtems_task_start( Task_id[1], Task02, 0 );
+  directive_failed( status, "rtems_task_start" );
+
+  for ( ; count < BENCHMARKS; count++ ) {
+    (void) rtems_message_queue_send( Queue_id, Buffer, MESSAGE_SIZE );
+  }
+
+  /* Should never reach here */
+  rtems_test_assert( false );
+
+}
+
+rtems_task Task02( rtems_task_argument ignored )
+{
+  size_t size;
+
+  /* find recieve overhead - no preempt or task switch */
+  benchmark_timer_initialize();
+  (void) rtems_message_queue_receive(
+             Queue_id,
+             (long (*)[4]) Buffer,
+             &size,
+             RTEMS_DEFAULT_OPTIONS,
+             RTEMS_NO_TIMEOUT
+           );
+  treceive_overhead = benchmark_timer_read();
+
+  /* Benchmark code */
+  benchmark_timer_initialize();
+  for ( count = 0; count < BENCHMARKS - 1; count++ ) {
+    (void) rtems_message_queue_receive(
+             Queue_id,
+             (long (*)[4]) Buffer,
+             &size,
+             RTEMS_DEFAULT_OPTIONS,
+             RTEMS_NO_TIMEOUT
+           );
+  }
+  telapsed = benchmark_timer_read();
+
+  put_time(
+     "Rhealstone: Intertask Message Latency",
+     telapsed,                     /* Total time of all benchmarks */
+     BENCHMARKS - 1,               /* Total benchmarks */
+     tloop_overhead,               /* Overhead of loops */
+     treceive_overhead             /* Overhead of recieve call and task switch */
+  );
+
+  rtems_test_exit( 0 );
+}
+
+/* configuration information */
+
+#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
+#define CONFIGURE_APPLICATION_NEEDS_TIMER_DRIVER
+
+#define CONFIGURE_MAXIMUM_TASKS              3
+#define CONFIGURE_MAXIMUM_MESSAGE_QUEUES     1
+#define CONFIGURE_TICKS_PER_TIMESLICE        0
+#define CONFIGURE_INIT
+#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
+
+#include <rtems/confdefs.h>
diff --git a/testsuites/rhealstone/semshuffle/Makefile.am b/testsuites/rhealstone/semshuffle/Makefile.am
new file mode 100644
index 0000000..eab0fe5
--- /dev/null
+++ b/testsuites/rhealstone/semshuffle/Makefile.am
@@ -0,0 +1,23 @@
+MANAGERS = all
+
+rtems_tests_PROGRAMS = semshuffle
+semshuffle_SOURCES  = semshuffle.c
+semshuffle_SOURCES += ../../tmtests/include/timesys.h
+
+dist_rtems_tests_DATA = semshuffle.adoc
+
+include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP at .cfg
+include $(top_srcdir)/../automake/compile.am
+include $(top_srcdir)/../automake/leaf.am
+
+AM_CPPFLAGS += -I$(top_srcdir)/../tmtests/include
+AM_CPPFLAGS += -I$(top_srcdir)/../support/include
+
+LINK_OBJS = $(semshuffle_OBJECTS) $(semshuffle_LDADD)
+LINK_LIBS = $(semshuffle_LDLIBS)
+
+semshuffle$(EXEEXT): $(semshuffle_OBJECTS) $(semshuffle_DEPENDENCIES)
+	@rm -f semshuffle$(EXEEXT)
+	$(make-exe)
+
+include $(top_srcdir)/../automake/local.am
diff --git a/testsuites/rhealstone/semshuffle/semshuffle.adoc b/testsuites/rhealstone/semshuffle/semshuffle.adoc
new file mode 100644
index 0000000..c2fc2e4
--- /dev/null
+++ b/testsuites/rhealstone/semshuffle/semshuffle.adoc
@@ -0,0 +1,26 @@
+= Semaphore Shuffle Benchmark
+
+This benchmark measures the average delay between a task's release of a
+semaphore and the activation of another task blocked on that semaphore.
+
+== Directives
+
+  * rtems_semaphore_obtain
+  * rtems_semaphore_release
+  * rtems_task_wake_after
+
+
+== Methodology
+
+This benchmark has two equal priority tasks switch between themselves a total
+of BENCHMARKS * 2 times. This is timed, and then execute the same code but
+having the tasks pass a semphore between themselves. A task obtains the
+semphore, then yields to the other task, which blocks on the semaphore. The
+task owning the semaphore then releases it and yields. This process is
+repeated by the other task.
+
+This benchmark has overhead, especially in the time it takes to switch between
+the two tasks, which happens a total of 2 times per semaphore shuffle. By first
+timing how long it takes the tasks to switch between themselves without any
+semaphore related calls, the overhead time is found. This time is then subtracted
+from the total time of the benchmark, with semaphore shuffling occuring.
diff --git a/testsuites/rhealstone/semshuffle/semshuffle.c b/testsuites/rhealstone/semshuffle/semshuffle.c
new file mode 100644
index 0000000..81242f1
--- /dev/null
+++ b/testsuites/rhealstone/semshuffle/semshuffle.c
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2014 Daniel Ramirez. (javamonn at gmail.com)
+ *
+ * This file's license is 2-clause BSD as in this distribution's LICENSE file.
+ */
+
+#include <rtems/timerdrv.h>
+#include <timesys.h>
+
+#define BENCHMARKS 50000
+
+rtems_task Task01( rtems_task_argument ignored );
+rtems_task Task02( rtems_task_argument ignored );
+rtems_task Init( rtems_task_argument ignored );
+
+rtems_id   Task_id[2];
+rtems_name Task_name[2];
+rtems_id    sem_id;
+rtems_name  sem_name;
+
+uint32_t    telapsed;
+uint32_t    tswitch_overhead;
+uint32_t    count;
+uint32_t    sem_exe;
+
+rtems_task Init( rtems_task_argument ignored )
+{
+  rtems_status_code    status;
+  rtems_attribute      sem_attr;
+  rtems_task_priority  pri;
+  rtems_mode           prev_mode;
+
+  sem_attr =  RTEMS_BINARY_SEMAPHORE | RTEMS_PRIORITY;
+
+  sem_name = rtems_build_name( 'S','0',' ',' ' );
+  status = rtems_semaphore_create(
+    sem_name,
+    1,
+    sem_attr,
+    0,
+    &sem_id
+  );
+  directive_failed( status, "rtems_semaphore_create of S0" );
+
+  Task_name[0] = rtems_build_name( 'T','A','0','1' );
+  status = rtems_task_create(
+    Task_name[0],
+    30,
+    RTEMS_MINIMUM_STACK_SIZE,
+    RTEMS_DEFAULT_MODES,
+    RTEMS_DEFAULT_ATTRIBUTES,
+    &Task_id[0]
+  );
+  directive_failed( status, "rtems_task_create of TA01" );
+
+  Task_name[1] = rtems_build_name( 'T','A','0','2' );
+  status = rtems_task_create(
+    Task_name[1],
+    30,
+    RTEMS_MINIMUM_STACK_SIZE,
+    RTEMS_DEFAULT_MODES,
+    RTEMS_DEFAULT_ATTRIBUTES,
+    &Task_id[1]
+  );
+  directive_failed( status , "rtems_task_create of TA02\n" );
+
+  rtems_task_mode( RTEMS_PREEMPT, RTEMS_PREEMPT_MASK, &prev_mode );
+  /* Lower own priority so TA01 can start up and run */
+  rtems_task_set_priority( RTEMS_SELF, 40, &pri);
+
+  /* Get time of benchmark with no semaphore shuffling */
+  sem_exe = 0;
+  status = rtems_task_start( Task_id[0], Task01, 0 );
+  directive_failed( status, "rtems_task_start of TA01" );
+
+  /* Get time of benchmark with semaphore shuffling */
+  sem_exe = 1;
+  status = rtems_task_restart( Task_id[0], 0 );
+  directive_failed( status, "rtems_task_restart of TA01" );
+
+  /* Should never reach here */
+  rtems_test_assert( false );
+}
+
+rtems_task Task01( rtems_task_argument ignored )
+{
+  rtems_status_code status;
+
+  /* Start up TA02, yield so it can run */
+  if ( sem_exe == 0 ) {
+    status = rtems_task_start( Task_id[1], Task02, 0 );
+    directive_failed( status, "rtems_task_start of TA02" );
+  } else {
+    status = rtems_task_restart( Task_id[1], 0 );
+    directive_failed( status, "rtems_task_restart of TA02" );
+  }
+  rtems_task_wake_after( RTEMS_YIELD_PROCESSOR );
+
+  /* Benchmark code */
+  for ( ; count < BENCHMARKS ; ) {
+    if ( sem_exe == 1 ) {
+      rtems_semaphore_obtain( sem_id, RTEMS_WAIT, 0 );
+    }
+    rtems_task_wake_after( RTEMS_YIELD_PROCESSOR );
+
+    if ( sem_exe == 1 ) {
+      rtems_semaphore_release( sem_id );
+    }
+    rtems_task_wake_after( RTEMS_YIELD_PROCESSOR );
+  }
+
+  /* Should never reach here */
+  rtems_test_assert( false );
+}
+
+rtems_task Task02( rtems_task_argument ignored )
+{
+
+  /* Benchmark code */
+  benchmark_timer_initialize();
+  for ( count = 0; count < BENCHMARKS; count++ ) {
+    if ( sem_exe == 1 ) {
+      rtems_semaphore_obtain( sem_id, RTEMS_WAIT, 0 );
+    }
+    rtems_task_wake_after( RTEMS_YIELD_PROCESSOR );
+
+    if ( sem_exe == 1 ) {
+      rtems_semaphore_release( sem_id );
+    }
+    rtems_task_wake_after( RTEMS_YIELD_PROCESSOR );
+  }
+  telapsed = benchmark_timer_read();
+
+  /* Check which run this was */
+  if (sem_exe == 0) {
+    tswitch_overhead = telapsed;
+    rtems_task_suspend( Task_id[0] );
+    rtems_task_suspend( RTEMS_SELF );
+  } else {
+    put_time(
+       "Rhealstone: Semaphore Shuffle",
+       telapsed,
+       (BENCHMARKS * 2),        /* Total number of semaphore-shuffles*/
+       tswitch_overhead,        /* Overhead of loop and task switches */
+       0
+    );
+    rtems_test_exit( 0 );
+  }
+}
+
+/* configuration information */
+#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
+#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
+#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
+#define CONFIGURE_MAXIMUM_TASKS 3
+#define CONFIGURE_MAXIMUM_SEMAPHORES 1
+#define CONFIGURE_INIT
+#include <rtems/confdefs.h>
diff --git a/testsuites/rhealstone/taskpreempt/Makefile.am b/testsuites/rhealstone/taskpreempt/Makefile.am
new file mode 100644
index 0000000..ee4a0f6
--- /dev/null
+++ b/testsuites/rhealstone/taskpreempt/Makefile.am
@@ -0,0 +1,23 @@
+MANAGERS = all
+
+rtems_tests_PROGRAMS = taskpreempt
+taskpreempt_SOURCES  = taskpreempt.c
+taskpreempt_SOURCES += ../../tmtests/include/timesys.h
+
+dist_rtems_tests_DATA = taskpreempt.adoc
+
+include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP at .cfg
+include $(top_srcdir)/../automake/compile.am
+include $(top_srcdir)/../automake/leaf.am
+
+AM_CPPFLAGS += -I$(top_srcdir)/../tmtests/include
+AM_CPPFLAGS += -I$(top_srcdir)/../support/include
+
+LINK_OBJS = $(taskpreempt_OBJECTS) $(taskpreempt_LDADD)
+LINK_LIBS = $(taskpreempt_LDLIBS)
+
+taskpreempt$(EXEEXT): $(taskpreempt_OBJECTS) $(taskpreempt_DEPENDENCIES)
+	@rm -f taskpreempt$(EXEEXT)
+	$(make-exe)
+
+include $(top_srcdir)/../automake/local.am
diff --git a/testsuites/rhealstone/taskpreempt/taskpreempt.adoc b/testsuites/rhealstone/taskpreempt/taskpreempt.adoc
new file mode 100644
index 0000000..ee53cc8
--- /dev/null
+++ b/testsuites/rhealstone/taskpreempt/taskpreempt.adoc
@@ -0,0 +1,36 @@
+= Task Preemption Benchmark
+
+This benchmark measures the average time it takes the system to recognize
+a ready higher priority task and switch to it from a lower priority task.
+This differs from a task-switch in the sense that there is no explicit
+yield, the system forces the context switch.
+
+== Directives
+
+  * rtems_task_suspend
+  * rtems_task_resume
+
+== Methodology
+
+Preemption usually occurs in a program when a high priority task moves from
+a suspended or idle state to a ready state in response to an event. This is
+achieved in the benchmark by using rtems_task_suspend and rtems_task_resume
+to move the high priority task in between states.
+
+As this is an average, we structure the benchmark code in a way that results
+in some overhead being included that inflates the total elapsed time. This
+overhead includes:
+  * loop overhead (minimal)
+  * the time it takes to task-switch from the high priority task back to
+    the low priority task.
+  * The time it takes to change the state of a task (suspend/resume).
+
+We instantiate two tasks, one with a higher priority than the other. The
+benchmark starts with the high priority task suspended. The benchmark code
+has the lower priority task resume the high priority task, at which point
+the preemption we are seeking to time occurs. The high priority task, now
+executing, suspends it self, and a non-preemptive task switch back to the
+low priority task occurs. This is repeated a total of BENCHMARKS times.
+
+The average time is found by using put_time to divide the total elapsed time
+by the number of benchmarks, and subtracting out the overhead found earlier.
diff --git a/testsuites/rhealstone/taskpreempt/taskpreempt.c b/testsuites/rhealstone/taskpreempt/taskpreempt.c
new file mode 100644
index 0000000..576e32d
--- /dev/null
+++ b/testsuites/rhealstone/taskpreempt/taskpreempt.c
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2014 Daniel Ramirez. (javamonn at gmail.com)
+ *
+ * This file's license is 2-clause BSD as in this distribution's LICENSE file.
+ */
+
+#include <timesys.h>
+#include <rtems/timerdrv.h>
+#define BENCHMARKS 50000   /* Number of benchmarks to run and average over */
+
+rtems_task Task02( rtems_task_argument ignored );
+rtems_task Task01( rtems_task_argument ignored );
+rtems_task Init( rtems_task_argument ignored );
+
+rtems_id           Task_id[2];
+rtems_name         Task_name[2];
+
+uint32_t           telapsed;          /* total time elapsed during benchmark */
+uint32_t           tloop_overhead;    /* overhead of loops */
+uint32_t           tswitch_overhead;  /* overhead of time it takes to switch
+                                       * from TA02 to TA01, includes rtems_suspend
+                                       * overhead
+                                       */
+unsigned long      count1;
+rtems_status_code  status;
+
+rtems_task Task01( rtems_task_argument ignored )
+{
+  /* Start up TA02, get preempted */
+  status = rtems_task_start( Task_id[1], Task02, 0);
+  directive_failed( status, "rtems_task_start of TA02");
+
+  tswitch_overhead = benchmark_timer_read();
+
+  benchmark_timer_initialize();
+  /* Benchmark code */
+  for ( count1 = 0; count1 < BENCHMARKS; count1++ ) {
+    rtems_task_resume( Task_id[1] );  /* Awaken TA02, preemption occurs */
+  }
+
+  /* Should never reach here */
+  rtems_test_assert( false );
+}
+
+rtems_task Task02( rtems_task_argument ignored )
+{
+  /* Find overhead of task switch back to TA01 (not a preemption) */
+  benchmark_timer_initialize();
+  rtems_task_suspend( RTEMS_SELF );
+
+  /* Benchmark code */
+  for ( ; count1 < BENCHMARKS - 1; ) {
+    rtems_task_suspend( RTEMS_SELF );
+  }
+
+  telapsed = benchmark_timer_read();
+  put_time(
+     "Rhealstone: Task Preempt",
+     telapsed,                     /* Total time of all benchmarks */
+     BENCHMARKS - 1,               /* BENCHMARKS - 1 total preemptions */
+     tloop_overhead,               /* Overhead of loops */
+     tswitch_overhead              /* Overhead of task switch back to TA01 */
+  );
+
+  rtems_test_exit( 0 );
+}
+
+rtems_task Init( rtems_task_argument ignored )
+{
+  Task_name[0] = rtems_build_name( 'T','A','0','1' );
+  status = rtems_task_create(
+    Task_name[0],
+    30,               /* TA01 is low priority task */
+    RTEMS_MINIMUM_STACK_SIZE,
+    RTEMS_DEFAULT_MODES,
+    RTEMS_DEFAULT_ATTRIBUTES,
+    &Task_id[0]
+  );
+  directive_failed( status, "rtems_task_create of TA01");
+
+  Task_name[1] = rtems_build_name( 'T','A','0','2' );
+  status = rtems_task_create(
+    Task_name[1],
+    28,               /* TA02 is high priority task */
+    RTEMS_MINIMUM_STACK_SIZE,
+    RTEMS_DEFAULT_MODES,
+    RTEMS_DEFAULT_ATTRIBUTES,
+    &Task_id[1]
+  );
+  directive_failed( status, "rtems_task_create of TA02");
+
+  /* Find loop overhead */
+  benchmark_timer_initialize();
+  for ( count1 = 0; count1 < ( BENCHMARKS * 2 ) - 1; count1++ ); {
+     /* rtems_task_resume( Task_id[1] ); */
+  }
+  tloop_overhead = benchmark_timer_read();
+
+  status = rtems_task_start( Task_id[0], Task01, 0 );
+  directive_failed( status, "rtems_task_start of TA01");
+
+  status = rtems_task_delete( RTEMS_SELF );
+  directive_failed( status, "rtems_task_delete of INIT");
+}
+
+/* configuration information */
+#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
+#define CONFIGURE_APPLICATION_NEEDS_TIMER_DRIVER
+#define CONFIGURE_TICKS_PER_TIMESLICE        0
+#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
+#define CONFIGURE_MAXIMUM_TASKS 3
+#define CONFIGURE_INIT
+#include <rtems/confdefs.h>
diff --git a/testsuites/rhealstone/taskswitch/Makefile.am b/testsuites/rhealstone/taskswitch/Makefile.am
new file mode 100644
index 0000000..d8c4172
--- /dev/null
+++ b/testsuites/rhealstone/taskswitch/Makefile.am
@@ -0,0 +1,23 @@
+MANAGERS = all
+
+rtems_tests_PROGRAMS = taskswitch
+taskswitch_SOURCES  = taskswitch.c
+taskswitch_SOURCES += ../../tmtests/include/timesys.h
+
+dist_rtems_tests_DATA = taskswitch.adoc
+
+include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP at .cfg
+include $(top_srcdir)/../automake/compile.am
+include $(top_srcdir)/../automake/leaf.am
+
+AM_CPPFLAGS += -I$(top_srcdir)/../tmtests/include
+AM_CPPFLAGS += -I$(top_srcdir)/../support/include
+
+LINK_OBJS = $(taskswitch_OBJECTS) $(taskswitch_LDADD)
+LINK_LIBS = $(taskswitch_LDLIBS)
+
+taskswitch$(EXEEXT): $(taskswitch_OBJECTS) $(taskswitch_DEPENDENCIES)
+	@rm -f taskswitch$(EXEEXT)
+	$(make-exe)
+
+include $(top_srcdir)/../automake/local.am
diff --git a/testsuites/rhealstone/taskswitch/taskswitch.adoc b/testsuites/rhealstone/taskswitch/taskswitch.adoc
new file mode 100644
index 0000000..9b2d10a
--- /dev/null
+++ b/testsuites/rhealstone/taskswitch/taskswitch.adoc
@@ -0,0 +1,27 @@
+== Task Switch Benchmark
+
+This benchmark measures the average time it takes the system to switch between
+two independent and active tasks of equal priority. Task switching is synchronous
+and non-preemptive.
+
+=== Directives
+
+  * rtems_task_wake_after
+
+
+=== Methodology
+
+This benchmark utilizes rtems_task_wake_after( RTEMS_YIELD_PROCESSOR ) to
+achieve a synchronous, non-preemptive task switch. rtems_task_wake_after
+used in this context is essentially just a yield.
+
+As this is an average, we structure the benchmark code in a way that results
+in some overhead being included that inflates the total elapsed time. This
+overhead includes:
+  * the time it takes to iterate through the for loops (minimal
+  * overhead code in rtems_task_wake_after
+
+We instantiate two tasks, and time how long it takes for them to switch back
+and forth between themselves a total of BENCHMARKS * 2 times. We then use
+the put_time call to divide this total elapsed time by BENCHMARKS * 2, giving
+an average, and subtract out the overhead time we found earlier.
diff --git a/testsuites/rhealstone/taskswitch/taskswitch.c b/testsuites/rhealstone/taskswitch/taskswitch.c
new file mode 100644
index 0000000..b864c88
--- /dev/null
+++ b/testsuites/rhealstone/taskswitch/taskswitch.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2014 Daniel Ramirez. (javamonn at gmail.com)
+ *
+ * This file's license is 2-clause BSD as in this distribution's LICENSE file.
+ */
+
+#include <rtems/timerdrv.h>
+#include <timesys.h>
+
+#define BENCHMARKS 50000
+
+rtems_task Task01( rtems_task_argument ignored );
+rtems_task Task02( rtems_task_argument ignored );
+rtems_task Init( rtems_task_argument ignored );
+
+rtems_id           Task_id[2];
+rtems_name         Task_name[2];
+uint32_t           loop_overhead;
+uint32_t           dir_overhead;
+unsigned long      count1, count2;
+rtems_status_code  status;
+
+rtems_task Task02( rtems_task_argument ignored )
+{
+  uint32_t telapsed;
+
+  /* All overhead accounted for now, we can begin benchmark */
+  benchmark_timer_initialize();
+
+  for ( count1 = 0; count1 < BENCHMARKS - 1; count1++ ) {
+    rtems_task_wake_after( RTEMS_YIELD_PROCESSOR );
+  }
+
+  telapsed = benchmark_timer_read();
+  put_time(
+     "Rhealstone: Task switch",
+     telapsed,
+     ( BENCHMARKS * 2 ) - 1,   /* ( BENCHMARKS * 2 ) - 1 total benchmarks */
+     loop_overhead,            /* Overhead of loop */
+     dir_overhead              /* Overhead of rtems_task_wake_after directive */
+  );
+
+  rtems_test_exit( 0 );
+}
+
+rtems_task Task01( rtems_task_argument ignored )
+{
+  status = rtems_task_start( Task_id[1], Task02, 0 );
+  directive_failed( status, "rtems_task_start of TA02" );
+
+  /* Yield processor so second task can startup and run */
+  rtems_task_wake_after( RTEMS_YIELD_PROCESSOR );
+
+  for ( count2 = 0; count2 < BENCHMARKS; count2++ ) {
+    rtems_task_wake_after( RTEMS_YIELD_PROCESSOR );
+  }
+
+  /* Should never reach here */
+  rtems_test_assert( false );
+
+}
+
+rtems_task Init( rtems_task_argument ignored )
+{
+  Task_name[0] = rtems_build_name( 'T','A','0','1' );
+  status = rtems_task_create(
+    Task_name[0],
+    30,
+    RTEMS_MINIMUM_STACK_SIZE,
+    RTEMS_DEFAULT_MODES,
+    RTEMS_DEFAULT_ATTRIBUTES,
+    &Task_id[0]
+  );
+  directive_failed( status, "rtems_task_create of TA01" );
+
+  Task_name[1] = rtems_build_name( 'T','A','0','2' );
+  status = rtems_task_create(
+    Task_name[1],
+    30,
+    RTEMS_MINIMUM_STACK_SIZE,
+    RTEMS_DEFAULT_MODES,
+    RTEMS_DEFAULT_ATTRIBUTES,
+    &Task_id[1]
+  );
+  directive_failed( status, "rtems_task_create of TA02" );
+
+  /* find overhead of routine (no task switches) */
+  benchmark_timer_initialize();
+  for ( count1 = 0; count1 < BENCHMARKS - 1; count1++ ) {
+    /* rtems_task_wake_after( RTEMS_YIELD_PROCESSOR ) */
+  }
+  for ( count2 = 0; count2 < BENCHMARKS; count2++ ) {
+    /* rtems_task_wake_after( RTEMS_YIELD_PROCESSOR ) */
+  }
+  loop_overhead = benchmark_timer_read();
+
+  /* find overhead of rtems_task_wake_after call (no task switches) */
+  benchmark_timer_initialize();
+  rtems_task_wake_after( RTEMS_YIELD_PROCESSOR );
+  dir_overhead = benchmark_timer_read();
+
+  status = rtems_task_start( Task_id[0], Task01, 0);
+  directive_failed( status, "rtems_task_start of TA01" );
+
+  status = rtems_task_delete( RTEMS_SELF);
+  directive_failed( status, "rtems_task_delete of INIT" );
+}
+
+/* configuration information */
+#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
+#define CONFIGURE_APPLICATION_NEEDS_TIMER_DRIVER
+#define CONFIGURE_TICKS_PER_TIMESLICE        0
+#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
+#define CONFIGURE_MAXIMUM_TASKS 3
+#define CONFIGURE_INIT
+#include <rtems/confdefs.h>




More information about the vc mailing list