summaryrefslogtreecommitdiffstats
path: root/testsuites/rhealstone
diff options
context:
space:
mode:
authorDaniel Ramirez <javamonn@gmail.com>2014-01-04 13:58:44 -0600
committerJoel Sherrill <joel.sherrill@oarcorp.com>2014-01-05 09:58:39 -0600
commit19e9bf88004008308e0c9c7039a166c49477e0d1 (patch)
treedfdc847c722a17cc7e1b3e33afd83da809bf4e9d /testsuites/rhealstone
parentsp09: Remove partition specific parts (diff)
downloadrtems-19e9bf88004008308e0c9c7039a166c49477e0d1.tar.bz2
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.
Diffstat (limited to 'testsuites/rhealstone')
-rw-r--r--testsuites/rhealstone/Makefile.am6
-rw-r--r--testsuites/rhealstone/README22
-rw-r--r--testsuites/rhealstone/configure.ac35
-rw-r--r--testsuites/rhealstone/deadlockbrk/Makefile.am23
-rw-r--r--testsuites/rhealstone/deadlockbrk/deadlockbrk.adoc37
-rw-r--r--testsuites/rhealstone/deadlockbrk/deadlockbrk.c206
-rw-r--r--testsuites/rhealstone/ilatency/Makefile.am23
-rw-r--r--testsuites/rhealstone/ilatency/ilatency.adoc21
-rw-r--r--testsuites/rhealstone/ilatency/ilatency.c119
-rw-r--r--testsuites/rhealstone/mlatency/Makefile.am23
-rw-r--r--testsuites/rhealstone/mlatency/mlatency.adoc22
-rw-r--r--testsuites/rhealstone/mlatency/mlatency.c150
-rw-r--r--testsuites/rhealstone/semshuffle/Makefile.am23
-rw-r--r--testsuites/rhealstone/semshuffle/semshuffle.adoc26
-rw-r--r--testsuites/rhealstone/semshuffle/semshuffle.c158
-rw-r--r--testsuites/rhealstone/taskpreempt/Makefile.am23
-rw-r--r--testsuites/rhealstone/taskpreempt/taskpreempt.adoc36
-rw-r--r--testsuites/rhealstone/taskpreempt/taskpreempt.c113
-rw-r--r--testsuites/rhealstone/taskswitch/Makefile.am23
-rw-r--r--testsuites/rhealstone/taskswitch/taskswitch.adoc27
-rw-r--r--testsuites/rhealstone/taskswitch/taskswitch.c116
21 files changed, 1232 insertions, 0 deletions
diff --git a/testsuites/rhealstone/Makefile.am b/testsuites/rhealstone/Makefile.am
new file mode 100644
index 0000000000..d67dcf4974
--- /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 0000000000..5b4b6fb82b
--- /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 0000000000..e61dc2ebbb
--- /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 0000000000..8db2141ff6
--- /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@.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 0000000000..a26cd47f86
--- /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 0000000000..f8d30b9d0d
--- /dev/null
+++ b/testsuites/rhealstone/deadlockbrk/deadlockbrk.c
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 2014 Daniel Ramirez. (javamonn@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 0000000000..3cd696edf0
--- /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@.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 0000000000..2f8a980142
--- /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 0000000000..df21341285
--- /dev/null
+++ b/testsuites/rhealstone/ilatency/ilatency.c
@@ -0,0 +1,119 @@
+/* Copyright 2014 Daniel Ramirez (javamonn@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 0000000000..098443813d
--- /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@.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 0000000000..fd445ca3ff
--- /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 0000000000..3752eedcf9
--- /dev/null
+++ b/testsuites/rhealstone/mlatency/mlatency.c
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2014 Daniel Ramirez. (javamonn@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 0000000000..eab0fe5e1d
--- /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@.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 0000000000..c2fc2e49f0
--- /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 0000000000..81242f1711
--- /dev/null
+++ b/testsuites/rhealstone/semshuffle/semshuffle.c
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2014 Daniel Ramirez. (javamonn@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 0000000000..ee4a0f64f2
--- /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@.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 0000000000..ee53cc87dc
--- /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 0000000000..576e32db0f
--- /dev/null
+++ b/testsuites/rhealstone/taskpreempt/taskpreempt.c
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2014 Daniel Ramirez. (javamonn@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 0000000000..d8c417236b
--- /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@.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 0000000000..9b2d10a40c
--- /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 0000000000..b864c88404
--- /dev/null
+++ b/testsuites/rhealstone/taskswitch/taskswitch.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2014 Daniel Ramirez. (javamonn@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>