Benchmarks added to Nil test suite.

git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@12654 110e8d01-0319-4d1e-a829-52ad28d1bb01
This commit is contained in:
Giovanni Di Sirio 2019-02-10 17:13:55 +00:00
parent d6fa7fed19
commit 14b7df7ccc
14 changed files with 1370 additions and 46 deletions

View File

@ -5,7 +5,7 @@
# Compiler options here. # Compiler options here.
ifeq ($(USE_OPT),) ifeq ($(USE_OPT),)
USE_OPT = -O0 -ggdb -fomit-frame-pointer -falign-functions=16 USE_OPT = -O2 -ggdb -fomit-frame-pointer -falign-functions=16
endif endif
# C specific options here (added to USE_OPT). # C specific options here (added to USE_OPT).

View File

@ -284,21 +284,21 @@
* *
* @note The default is @p FALSE. * @note The default is @p FALSE.
*/ */
#define CH_DBG_SYSTEM_STATE_CHECK TRUE #define CH_DBG_SYSTEM_STATE_CHECK FALSE
/** /**
* @brief Debug option, parameters checks. * @brief Debug option, parameters checks.
* *
* @note The default is @p FALSE. * @note The default is @p FALSE.
*/ */
#define CH_DBG_ENABLE_CHECKS TRUE #define CH_DBG_ENABLE_CHECKS FALSE
/** /**
* @brief System assertions. * @brief System assertions.
* *
* @note The default is @p FALSE. * @note The default is @p FALSE.
*/ */
#define CH_DBG_ENABLE_ASSERTS TRUE #define CH_DBG_ENABLE_ASSERTS FALSE
/** /**
* @brief Stack check. * @brief Stack check.

View File

@ -1049,6 +1049,29 @@ struct nil_system {
port_unlock_from_isr(); \ port_unlock_from_isr(); \
} }
/**
* @brief Puts the current thread to sleep into the specified state.
*
* @param[in] newstate the new thread state or a semaphore pointer
* @return The wakeup message.
*
* @sclass
*/
#define chSchGoSleepS(newstate) chSchGoSleepTimeoutS(newstate, TIME_INFINITE)
/**
* @brief Wakes up a thread.
*
* @param[in] ntp the thread to be made ready
* @param[in] msg the wakeup message
*
* @sclass
*/
#define chSchWakeupS(ntp, msg) do { \
chSchReadyI(ntp, msg); \
chSchRescheduleS(); \
} while (0)
/** /**
* @brief Evaluates if a reschedule is required. * @brief Evaluates if a reschedule is required.
* *
@ -1203,6 +1226,22 @@ struct nil_system {
#define chVTTimeElapsedSinceX(start) \ #define chVTTimeElapsedSinceX(start) \
chTimeDiffX((start), chVTGetSystemTimeX()) chTimeDiffX((start), chVTGetSystemTimeX())
/**
* @brief Checks if the current system time is within the specified time
* window.
* @note When start==end then the function returns always true because the
* whole time range is specified.
*
* @param[in] start the start of the time window (inclusive)
* @param[in] end the end of the time window (non inclusive)
* @retval true current time within the specified time window.
* @retval false current time not within the specified time window.
*
* @xclass
*/
#define chVTIsSystemTimeWithinX(start, end) \
chTimeIsInRangeX(chVTGetSystemTimeX(), start, end)
/** /**
* @brief Adds an interval to a system time returning a system time. * @brief Adds an interval to a system time returning a system time.
* *

View File

@ -655,7 +655,7 @@ void chSchRescheduleS(void) {
* timeout specification. * timeout specification.
* @details The thread goes into a sleeping state, if it is not awakened * @details The thread goes into a sleeping state, if it is not awakened
* explicitly within the specified system time then it is forcibly * explicitly within the specified system time then it is forcibly
* awakened with a @p NIL_MSG_TMO low level message. * awakened with a @p MSG_TIMEOUT low level message.
* *
* @param[in] newstate the new thread state or a semaphore pointer * @param[in] newstate the new thread state or a semaphore pointer
* @param[in] timeout the number of ticks before the operation timeouts. * @param[in] timeout the number of ticks before the operation timeouts.
@ -663,7 +663,7 @@ void chSchRescheduleS(void) {
* - @a TIME_INFINITE no timeout. * - @a TIME_INFINITE no timeout.
* . * .
* @return The wakeup message. * @return The wakeup message.
* @retval NIL_MSG_TMO if a timeout occurred. * @retval MSG_TIMEOUT if a timeout occurred.
* *
* @sclass * @sclass
*/ */

View File

@ -45,10 +45,13 @@
*/ */
#define ALLOWED_DELAY TIME_MS2I(2) #define ALLOWED_DELAY TIME_MS2I(2)
extern THD_WORKING_AREA(wa_common, 128);
systime_t test_wait_tick(void);]]></value> systime_t test_wait_tick(void);]]></value>
</global_definitions> </global_definitions>
<global_code> <global_code>
<value><![CDATA[/* <value><![CDATA[THD_WORKING_AREA(wa_common, 128);
/*
* Delays execution until next system time tick. * Delays execution until next system time tick.
*/ */
systime_t test_wait_tick(void) { systime_t test_wait_tick(void) {
@ -449,7 +452,6 @@ static semaphore_t sem1, sem2;
/* /*
* Signaler thread. * Signaler thread.
*/ */
static THD_WORKING_AREA(wa_signaler, 128);
static THD_FUNCTION(signaler, arg) { static THD_FUNCTION(signaler, arg) {
(void)arg; (void)arg;
@ -550,8 +552,8 @@ test_assert_lock(chSemGetCounterI(&sem1) == 2, "wrong counter value");]]></value
<value><![CDATA[thread_config_t tc = { <value><![CDATA[thread_config_t tc = {
chThdGetPriorityX() - 1, chThdGetPriorityX() - 1,
"signaler", "signaler",
wa_signaler, wa_common,
THD_WORKING_AREA_END(wa_signaler), THD_WORKING_AREA_END(wa_common),
signaler, signaler,
NULL NULL
}; };
@ -680,7 +682,6 @@ static thread_reference_t tr1;
/* /*
* Resumer thread. * Resumer thread.
*/ */
static THD_WORKING_AREA(wa_resumer, 128);
static THD_FUNCTION(resumer, arg) { static THD_FUNCTION(resumer, arg) {
(void)arg; (void)arg;
@ -711,8 +712,8 @@ static THD_FUNCTION(resumer, arg) {
<value><![CDATA[thread_config_t tc = { <value><![CDATA[thread_config_t tc = {
chThdGetPriorityX() - 1, chThdGetPriorityX() - 1,
"resumer", "resumer",
wa_resumer, wa_common,
THD_WORKING_AREA_END(wa_resumer), THD_WORKING_AREA_END(wa_common),
resumer, resumer,
NULL NULL
}; };
@ -793,7 +794,6 @@ static ROMCONST evhandler_t evhndl[] = {h1, h2, h3};
/* /*
* Direct events thread. * Direct events thread.
*/ */
static THD_WORKING_AREA(wa_evtthd1, 128);
static THD_FUNCTION(evtthd1, p) { static THD_FUNCTION(evtthd1, p) {
chThdSleepMilliseconds(50); chThdSleepMilliseconds(50);
@ -803,7 +803,6 @@ static THD_FUNCTION(evtthd1, p) {
/* /*
* Broadcaster thread. * Broadcaster thread.
*/ */
static THD_WORKING_AREA(wa_evtthd2, 128);
static THD_FUNCTION(evtthd2, p) { static THD_FUNCTION(evtthd2, p) {
(void)p; (void)p;
@ -987,8 +986,8 @@ test_assert(m == 0, "stuck event");]]></value>
thread_config_t tc = { thread_config_t tc = {
chThdGetPriorityX() + 1, chThdGetPriorityX() + 1,
"event1", "event1",
wa_evtthd1, wa_common,
THD_WORKING_AREA_END(wa_evtthd1), THD_WORKING_AREA_END(wa_common),
evtthd1, evtthd1,
chThdGetSelfX() chThdGetSelfX()
}; };
@ -1076,8 +1075,8 @@ test_assert(m == 0, "stuck event");]]></value>
thread_config_t tc = { thread_config_t tc = {
chThdGetPriorityX() + 1, chThdGetPriorityX() + 1,
"event1", "event1",
wa_evtthd1, wa_common,
THD_WORKING_AREA_END(wa_evtthd1), THD_WORKING_AREA_END(wa_common),
evtthd1, evtthd1,
chThdGetSelfX() chThdGetSelfX()
}; };
@ -1176,8 +1175,8 @@ test_assert(m == 0, "stuck event");]]></value>
thread_config_t tc = { thread_config_t tc = {
chThdGetPriorityX() + 1, chThdGetPriorityX() + 1,
"event1", "event1",
wa_evtthd1, wa_common,
THD_WORKING_AREA_END(wa_evtthd1), THD_WORKING_AREA_END(wa_common),
evtthd1, evtthd1,
chThdGetSelfX() chThdGetSelfX()
}; };
@ -1311,8 +1310,8 @@ chEvtRegisterMask(&es2, &el2, 4);]]></value>
thread_config_t tc = { thread_config_t tc = {
chThdGetPriorityX() + 1, chThdGetPriorityX() + 1,
"event2", "event2",
wa_evtthd2, wa_common,
THD_WORKING_AREA_END(wa_evtthd2), THD_WORKING_AREA_END(wa_common),
evtthd2, evtthd2,
NULL NULL
}; };
@ -1371,7 +1370,6 @@ test_assert(!chEvtIsListeningI(&es2), "stuck listener");]]></value>
<value><![CDATA[/* <value><![CDATA[/*
* Messager thread. * Messager thread.
*/ */
static THD_WORKING_AREA(wa_messager, 128);
static THD_FUNCTION(messager, p) { static THD_FUNCTION(messager, p) {
chMsgSend(p, 'A'); chMsgSend(p, 'A');
@ -1416,8 +1414,8 @@ msg_t msg;]]></value>
<value><![CDATA[thread_config_t tc = { <value><![CDATA[thread_config_t tc = {
chThdGetPriorityX() - 1, chThdGetPriorityX() - 1,
"messager", "messager",
wa_messager, wa_common,
THD_WORKING_AREA_END(wa_messager), THD_WORKING_AREA_END(wa_common),
messager, messager,
chThdGetSelfX() chThdGetSelfX()
}; };
@ -1448,6 +1446,624 @@ test_assert_sequence("ABCD", "invalid sequence");]]></value>
</case> </case>
</cases> </cases>
</sequence> </sequence>
<sequence>
<type index="2">
<value>Benchmarks</value>
</type>
<brief>
<value>Benchmarks.</value>
</brief>
<description>
<value>This module implements a series of system benchmarks. The benchmarks are useful as a stress test and as a reference when comparing ChibiOS/RT with similar systems.&lt;br&gt;&#xD;
Objective of the test sequence is to provide a performance index for the most critical system subsystems. The performance numbers allow to discover performance regressions between successive ChibiOS/RT releases.</value>
</description>
<condition>
<value />
</condition>
<shared_code>
<value><![CDATA[#if CH_CFG_USE_SEMAPHORES || defined(__DOXYGEN__)
static semaphore_t sem1;
#endif
#if CH_CFG_USE_MUTEXES || defined(__DOXYGEN__)
static mutex_t mtx1;
#endif
#if CH_CFG_USE_MESSAGES
static THD_FUNCTION(bmk_thread1, p) {
thread_t *tp;
msg_t msg;
(void)p;
do {
tp = chMsgWait();
msg = chMsgGet(tp);
chMsgRelease(tp, msg);
} while (msg);
}
NOINLINE static unsigned int msg_loop_test(thread_t *tp) {
systime_t start, end;
uint32_t n = 0;
start = test_wait_tick();
end = chTimeAddX(start, TIME_MS2I(1000));
do {
(void)chMsgSend(tp, 1);
n++;
#if defined(SIMULATOR)
_sim_check_for_interrupts();
#endif
} while (chVTIsSystemTimeWithinX(start, end));
(void)chMsgSend(tp, 0);
return n;
}
#endif
static THD_FUNCTION(bmk_thread3, p) {
chThdExit((msg_t)p);
}
static THD_FUNCTION(bmk_thread4, p) {
msg_t msg;
thread_t *self = chThdGetSelfX();
(void)p;
chSysLock();
do {
chSchGoSleepS(NIL_STATE_SUSPENDED);
msg = self->u1.msg;
} while (msg == MSG_OK);
chSysUnlock();
}]]></value>
</shared_code>
<cases>
<case>
<brief>
<value>Messages performance #1.</value>
</brief>
<description>
<value>A message server thread is created with a lower priority than the client thread, the messages throughput per second is measured and the result printed on the output log.</value>
</description>
<condition>
<value>CH_CFG_USE_MESSAGES</value>
</condition>
<various_code>
<setup_code>
<value />
</setup_code>
<teardown_code>
<value />
</teardown_code>
<local_variables>
<value><![CDATA[uint32_t n;
thread_t *tp;]]></value>
</local_variables>
</various_code>
<steps>
<step>
<description>
<value>The messenger thread is started at a lower priority than the current thread.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[thread_config_t tc = {
chThdGetPriorityX() + 1,
"messenger",
wa_common,
THD_WORKING_AREA_END(wa_common),
bmk_thread1,
NULL
};
tp = chThdCreate(&tc);]]></value>
</code>
</step>
<step>
<description>
<value>The number of messages exchanged is counted in a one second time window.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[n = msg_loop_test(tp);
chThdWait(tp);]]></value>
</code>
</step>
<step>
<description>
<value>Score is printed.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[test_print("--- Score : ");
test_printn(n);
test_print(" msgs/S, ");
test_printn(n << 1);
test_println(" ctxswc/S");]]></value>
</code>
</step>
</steps>
</case>
<case>
<brief>
<value>Messages performance #2.</value>
</brief>
<description>
<value>A message server thread is created with an higher priority than the client thread, the messages throughput per second is measured and the result printed on the output log.</value>
</description>
<condition>
<value>CH_CFG_USE_MESSAGES</value>
</condition>
<various_code>
<setup_code>
<value />
</setup_code>
<teardown_code>
<value />
</teardown_code>
<local_variables>
<value><![CDATA[uint32_t n;
thread_t *tp;]]></value>
</local_variables>
</various_code>
<steps>
<step>
<description>
<value>The messenger thread is started at an higher priority than the current thread.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[thread_config_t tc = {
chThdGetPriorityX() - 1,
"messenger",
wa_common,
THD_WORKING_AREA_END(wa_common),
bmk_thread1,
NULL
};
tp = chThdCreate(&tc);]]></value>
</code>
</step>
<step>
<description>
<value>The number of messages exchanged is counted in a one second time window.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[n = msg_loop_test(tp);
chThdWait(tp);]]></value>
</code>
</step>
<step>
<description>
<value>Score is printed.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[test_print("--- Score : ");
test_printn(n);
test_print(" msgs/S, ");
test_printn(n << 1);
test_println(" ctxswc/S");]]></value>
</code>
</step>
</steps>
</case>
<case>
<brief>
<value>Context Switch performance.</value>
</brief>
<description>
<value>A thread is created that just performs a @p chSchGoSleepS() into a loop, the thread is awakened as fast is possible by the tester thread.&lt;br&gt;&#xD;
The Context Switch performance is calculated by measuring the number of iterations after a second of continuous operations.</value>
</description>
<condition>
<value />
</condition>
<various_code>
<setup_code>
<value />
</setup_code>
<teardown_code>
<value />
</teardown_code>
<local_variables>
<value><![CDATA[thread_t *tp;
uint32_t n;]]></value>
</local_variables>
</various_code>
<steps>
<step>
<description>
<value>Starting the target thread at an higher priority level.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[thread_config_t tc = {
chThdGetPriorityX() - 1,
"messenger",
wa_common,
THD_WORKING_AREA_END(wa_common),
bmk_thread4,
NULL
};
tp = chThdCreate(&tc);]]></value>
</code>
</step>
<step>
<description>
<value>Waking up the thread as fast as possible in a one second time window.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[systime_t start, end;
n = 0;
start = test_wait_tick();
end = chTimeAddX(start, TIME_MS2I(1000));
do {
chSysLock();
chSchWakeupS(tp, MSG_OK);
chSchWakeupS(tp, MSG_OK);
chSchWakeupS(tp, MSG_OK);
chSchWakeupS(tp, MSG_OK);
chSysUnlock();
n += 4;
} while (chVTIsSystemTimeWithinX(start, end));]]></value>
</code>
</step>
<step>
<description>
<value>Stopping the target thread.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[chSysLock();
chSchWakeupS(tp, MSG_TIMEOUT);
chSysUnlock();
chThdWait(tp);]]></value>
</code>
</step>
<step>
<description>
<value>Score is printed.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[test_print("--- Score : ");
test_printn(n * 2);
test_println(" ctxswc/S");]]></value>
</code>
</step>
</steps>
</case>
<case>
<brief>
<value>Threads performance, full cycle.</value>
</brief>
<description>
<value>Threads are continuously created and terminated into a loop. A full chThdCreateStatic() / @p chThdExit() / @p chThdWait() cycle is performed in each iteration.&lt;br&gt;&#xD;
The performance is calculated by measuring the number of iterations after a second of continuous operations.</value>
</description>
<condition>
<value />
</condition>
<various_code>
<setup_code>
<value />
</setup_code>
<teardown_code>
<value />
</teardown_code>
<local_variables>
<value><![CDATA[uint32_t n;]]></value>
</local_variables>
</various_code>
<steps>
<step>
<description>
<value>A thread is created at a lower priority level and its termination detected using @p chThdWait(). The operation is repeated continuously in a one-second time window.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[systime_t start, end;
thread_config_t tc = {
chThdGetPriorityX() + 1,
"messenger",
wa_common,
THD_WORKING_AREA_END(wa_common),
bmk_thread3,
NULL
};
n = 0;
start = test_wait_tick();
end = chTimeAddX(start, TIME_MS2I(1000));
do {
chThdWait(chThdCreate(&tc));
n++;
} while (chVTIsSystemTimeWithinX(start, end));]]></value>
</code>
</step>
<step>
<description>
<value>Score is printed.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[test_print("--- Score : ");
test_printn(n);
test_println(" threads/S");]]></value>
</code>
</step>
</steps>
</case>
<case>
<brief>
<value>Threads performance, create/exit only.</value>
</brief>
<description>
<value>Threads are continuously created and terminated into a loop. A partial @p chThdCreateStatic() / @p chThdExit() cycle is performed in each iteration, the @p chThdWait() is not necessary because the thread is created at an higher priority so there is no need to wait for it to terminate.&lt;br&gt; The performance is calculated by measuring the number of iterations after a second of continuous operations.</value>
</description>
<condition>
<value />
</condition>
<various_code>
<setup_code>
<value />
</setup_code>
<teardown_code>
<value />
</teardown_code>
<local_variables>
<value><![CDATA[uint32_t n;]]></value>
</local_variables>
</various_code>
<steps>
<step>
<description>
<value>A thread is created at an higher priority level and let terminate immediately. The operation is repeated continuously in a one-second time window.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[systime_t start, end;
thread_config_t tc = {
chThdGetPriorityX() - 1,
"messenger",
wa_common,
THD_WORKING_AREA_END(wa_common),
bmk_thread3,
NULL
};
n = 0;
start = test_wait_tick();
end = chTimeAddX(start, TIME_MS2I(1000));
do {
chThdWait(chThdCreate(&tc));
n++;
} while (chVTIsSystemTimeWithinX(start, end));]]></value>
</code>
</step>
<step>
<description>
<value>Score is printed.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[test_print("--- Score : ");
test_printn(n);
test_println(" threads/S");]]></value>
</code>
</step>
</steps>
</case>
<case>
<brief>
<value>Semaphores wait/signal performance</value>
</brief>
<description>
<value>A counting semaphore is taken/released into a continuous loop, no Context Switch happens because the counter is always non negative.&lt;br&gt;&#xD;
The performance is calculated by measuring the number of iterations after a second of continuous operations.</value>
</description>
<condition>
<value>CH_CFG_USE_SEMAPHORES</value>
</condition>
<various_code>
<setup_code>
<value><![CDATA[chSemObjectInit(&sem1, 1);]]></value>
</setup_code>
<teardown_code>
<value />
</teardown_code>
<local_variables>
<value><![CDATA[uint32_t n;]]></value>
</local_variables>
</various_code>
<steps>
<step>
<description>
<value>A semaphore is teken and released. The operation is repeated continuously in a one-second time window.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[systime_t start, end;
n = 0;
start = test_wait_tick();
end = chTimeAddX(start, TIME_MS2I(1000));
do {
chSemWait(&sem1);
chSemSignal(&sem1);
chSemWait(&sem1);
chSemSignal(&sem1);
chSemWait(&sem1);
chSemSignal(&sem1);
chSemWait(&sem1);
chSemSignal(&sem1);
n++;
#if defined(SIMULATOR)
_sim_check_for_interrupts();
#endif
} while (chVTIsSystemTimeWithinX(start, end));]]></value>
</code>
</step>
<step>
<description>
<value>The score is printed.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[test_print("--- Score : ");
test_printn(n * 4);
test_println(" wait+signal/S");]]></value>
</code>
</step>
</steps>
</case>
<case>
<brief>
<value>RAM Footprint.</value>
</brief>
<description>
<value>The memory size of the various kernel objects is printed.</value>
</description>
<condition>
<value />
</condition>
<various_code>
<setup_code>
<value />
</setup_code>
<teardown_code>
<value />
</teardown_code>
<local_variables>
<value />
</local_variables>
</various_code>
<steps>
<step>
<description>
<value>The size of the system area is printed.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[test_print("--- System: ");
test_printn(sizeof(nil_system_t));
test_println(" bytes");]]></value>
</code>
</step>
<step>
<description>
<value>The size of a thread structure is printed.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[test_print("--- Thread: ");
test_printn(sizeof(thread_t));
test_println(" bytes");]]></value>
</code>
</step>
<step>
<description>
<value>The size of a semaphore structure is printed.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[#if CH_CFG_USE_SEMAPHORES || defined(__DOXYGEN__)
test_print("--- Semaph: ");
test_printn(sizeof(semaphore_t));
test_println(" bytes");
#endif]]></value>
</code>
</step>
<step>
<description>
<value>The size of an event source is printed.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[#if CH_CFG_USE_EVENTS || defined(__DOXYGEN__)
test_print("--- EventS: ");
test_printn(sizeof(event_source_t));
test_println(" bytes");
#endif]]></value>
</code>
</step>
<step>
<description>
<value>The size of an event listener is printed.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[#if CH_CFG_USE_EVENTS || defined(__DOXYGEN__)
test_print("--- EventL: ");
test_printn(sizeof(event_listener_t));
test_println(" bytes");
#endif]]></value>
</code>
</step>
<step>
<description>
<value>The size of a mailbox is printed.</value>
</description>
<tags>
<value />
</tags>
<code>
<value><![CDATA[#if CH_CFG_USE_MAILBOXES || defined(__DOXYGEN__)
test_print("--- MailB.: ");
test_printn(sizeof(mailbox_t));
test_println(" bytes");
#endif]]></value>
</code>
</step>
</steps>
</case>
</cases>
</sequence>
</sequences> </sequences>
</instance> </instance>
</instances> </instances>

View File

@ -5,7 +5,8 @@ TESTSRC += ${CHIBIOS}/test/nil/source/test/nil_test_root.c \
${CHIBIOS}/test/nil/source/test/nil_test_sequence_003.c \ ${CHIBIOS}/test/nil/source/test/nil_test_sequence_003.c \
${CHIBIOS}/test/nil/source/test/nil_test_sequence_004.c \ ${CHIBIOS}/test/nil/source/test/nil_test_sequence_004.c \
${CHIBIOS}/test/nil/source/test/nil_test_sequence_005.c \ ${CHIBIOS}/test/nil/source/test/nil_test_sequence_005.c \
${CHIBIOS}/test/nil/source/test/nil_test_sequence_006.c ${CHIBIOS}/test/nil/source/test/nil_test_sequence_006.c \
${CHIBIOS}/test/nil/source/test/nil_test_sequence_007.c
# Required include directories # Required include directories
TESTINC += ${CHIBIOS}/test/nil/source/test TESTINC += ${CHIBIOS}/test/nil/source/test

View File

@ -27,6 +27,7 @@
* - @subpage nil_test_sequence_004 * - @subpage nil_test_sequence_004
* - @subpage nil_test_sequence_005 * - @subpage nil_test_sequence_005
* - @subpage nil_test_sequence_006 * - @subpage nil_test_sequence_006
* - @subpage nil_test_sequence_007
* . * .
*/ */
@ -60,6 +61,7 @@ const testsequence_t * const nil_test_suite_array[] = {
#if (CH_CFG_USE_MESSAGES) || defined(__DOXYGEN__) #if (CH_CFG_USE_MESSAGES) || defined(__DOXYGEN__)
&nil_test_sequence_006, &nil_test_sequence_006,
#endif #endif
&nil_test_sequence_007,
NULL NULL
}; };
@ -75,6 +77,8 @@ const testsuite_t nil_test_suite = {
/* Shared code. */ /* Shared code. */
/*===========================================================================*/ /*===========================================================================*/
THD_WORKING_AREA(wa_common, 128);
/* /*
* Delays execution until next system time tick. * Delays execution until next system time tick.
*/ */

View File

@ -30,6 +30,7 @@
#include "nil_test_sequence_004.h" #include "nil_test_sequence_004.h"
#include "nil_test_sequence_005.h" #include "nil_test_sequence_005.h"
#include "nil_test_sequence_006.h" #include "nil_test_sequence_006.h"
#include "nil_test_sequence_007.h"
#if !defined(__DOXYGEN__) #if !defined(__DOXYGEN__)
@ -57,6 +58,7 @@ extern "C" {
*/ */
#define ALLOWED_DELAY TIME_MS2I(2) #define ALLOWED_DELAY TIME_MS2I(2)
extern THD_WORKING_AREA(wa_common, 128);
systime_t test_wait_tick(void); systime_t test_wait_tick(void);
#endif /* !defined(__DOXYGEN__) */ #endif /* !defined(__DOXYGEN__) */

View File

@ -57,7 +57,6 @@ static semaphore_t sem1, sem2;
/* /*
* Signaler thread. * Signaler thread.
*/ */
static THD_WORKING_AREA(wa_signaler, 128);
static THD_FUNCTION(signaler, arg) { static THD_FUNCTION(signaler, arg) {
(void)arg; (void)arg;
@ -166,8 +165,8 @@ static void nil_test_003_002_setup(void) {
thread_config_t tc = { thread_config_t tc = {
chThdGetPriorityX() - 1, chThdGetPriorityX() - 1,
"signaler", "signaler",
wa_signaler, wa_common,
THD_WORKING_AREA_END(wa_signaler), THD_WORKING_AREA_END(wa_common),
signaler, signaler,
NULL NULL
}; };

View File

@ -45,7 +45,6 @@ static thread_reference_t tr1;
/* /*
* Resumer thread. * Resumer thread.
*/ */
static THD_WORKING_AREA(wa_resumer, 128);
static THD_FUNCTION(resumer, arg) { static THD_FUNCTION(resumer, arg) {
(void)arg; (void)arg;
@ -85,8 +84,8 @@ static void nil_test_004_001_setup(void) {
thread_config_t tc = { thread_config_t tc = {
chThdGetPriorityX() - 1, chThdGetPriorityX() - 1,
"resumer", "resumer",
wa_resumer, wa_common,
THD_WORKING_AREA_END(wa_resumer), THD_WORKING_AREA_END(wa_common),
resumer, resumer,
NULL NULL
}; };

View File

@ -62,7 +62,6 @@ static ROMCONST evhandler_t evhndl[] = {h1, h2, h3};
/* /*
* Direct events thread. * Direct events thread.
*/ */
static THD_WORKING_AREA(wa_evtthd1, 128);
static THD_FUNCTION(evtthd1, p) { static THD_FUNCTION(evtthd1, p) {
chThdSleepMilliseconds(50); chThdSleepMilliseconds(50);
@ -72,7 +71,6 @@ static THD_FUNCTION(evtthd1, p) {
/* /*
* Broadcaster thread. * Broadcaster thread.
*/ */
static THD_WORKING_AREA(wa_evtthd2, 128);
static THD_FUNCTION(evtthd2, p) { static THD_FUNCTION(evtthd2, p) {
(void)p; (void)p;
@ -238,8 +236,8 @@ static void nil_test_005_003_execute(void) {
thread_config_t tc = { thread_config_t tc = {
chThdGetPriorityX() + 1, chThdGetPriorityX() + 1,
"event1", "event1",
wa_evtthd1, wa_common,
THD_WORKING_AREA_END(wa_evtthd1), THD_WORKING_AREA_END(wa_common),
evtthd1, evtthd1,
chThdGetSelfX() chThdGetSelfX()
}; };
@ -320,8 +318,8 @@ static void nil_test_005_004_execute(void) {
thread_config_t tc = { thread_config_t tc = {
chThdGetPriorityX() + 1, chThdGetPriorityX() + 1,
"event1", "event1",
wa_evtthd1, wa_common,
THD_WORKING_AREA_END(wa_evtthd1), THD_WORKING_AREA_END(wa_common),
evtthd1, evtthd1,
chThdGetSelfX() chThdGetSelfX()
}; };
@ -409,8 +407,8 @@ static void nil_test_005_005_execute(void) {
thread_config_t tc = { thread_config_t tc = {
chThdGetPriorityX() + 1, chThdGetPriorityX() + 1,
"event1", "event1",
wa_evtthd1, wa_common,
THD_WORKING_AREA_END(wa_evtthd1), THD_WORKING_AREA_END(wa_common),
evtthd1, evtthd1,
chThdGetSelfX() chThdGetSelfX()
}; };
@ -542,8 +540,8 @@ static void nil_test_005_007_execute(void) {
thread_config_t tc = { thread_config_t tc = {
chThdGetPriorityX() + 1, chThdGetPriorityX() + 1,
"event2", "event2",
wa_evtthd2, wa_common,
THD_WORKING_AREA_END(wa_evtthd2), THD_WORKING_AREA_END(wa_common),
evtthd2, evtthd2,
NULL NULL
}; };

View File

@ -49,7 +49,6 @@
/* /*
* Messager thread. * Messager thread.
*/ */
static THD_WORKING_AREA(wa_messager, 128);
static THD_FUNCTION(messager, p) { static THD_FUNCTION(messager, p) {
chMsgSend(p, 'A'); chMsgSend(p, 'A');
@ -86,8 +85,8 @@ static void nil_test_006_001_execute(void) {
thread_config_t tc = { thread_config_t tc = {
chThdGetPriorityX() - 1, chThdGetPriorityX() - 1,
"messager", "messager",
wa_messager, wa_common,
THD_WORKING_AREA_END(wa_messager), THD_WORKING_AREA_END(wa_common),
messager, messager,
chThdGetSelfX() chThdGetSelfX()
}; };

View File

@ -0,0 +1,640 @@
/*
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
Licensed under the Apache License, Version 2.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://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include "hal.h"
#include "nil_test_root.h"
/**
* @file nil_test_sequence_007.c
* @brief Test Sequence 007 code.
*
* @page nil_test_sequence_007 [7] Benchmarks
*
* File: @ref nil_test_sequence_007.c
*
* <h2>Description</h2>
* This module implements a series of system benchmarks. The benchmarks
* are useful as a stress test and as a reference when comparing
* ChibiOS/RT with similar systems.<br> Objective of the test sequence
* is to provide a performance index for the most critical system
* subsystems. The performance numbers allow to discover performance
* regressions between successive ChibiOS/RT releases.
*
* <h2>Test Cases</h2>
* - @subpage nil_test_007_001
* - @subpage nil_test_007_002
* - @subpage nil_test_007_003
* - @subpage nil_test_007_004
* - @subpage nil_test_007_005
* - @subpage nil_test_007_006
* - @subpage nil_test_007_007
* .
*/
/****************************************************************************
* Shared code.
****************************************************************************/
#if CH_CFG_USE_SEMAPHORES || defined(__DOXYGEN__)
static semaphore_t sem1;
#endif
#if CH_CFG_USE_MUTEXES || defined(__DOXYGEN__)
static mutex_t mtx1;
#endif
#if CH_CFG_USE_MESSAGES
static THD_FUNCTION(bmk_thread1, p) {
thread_t *tp;
msg_t msg;
(void)p;
do {
tp = chMsgWait();
msg = chMsgGet(tp);
chMsgRelease(tp, msg);
} while (msg);
}
NOINLINE static unsigned int msg_loop_test(thread_t *tp) {
systime_t start, end;
uint32_t n = 0;
start = test_wait_tick();
end = chTimeAddX(start, TIME_MS2I(1000));
do {
(void)chMsgSend(tp, 1);
n++;
#if defined(SIMULATOR)
_sim_check_for_interrupts();
#endif
} while (chVTIsSystemTimeWithinX(start, end));
(void)chMsgSend(tp, 0);
return n;
}
#endif
static THD_FUNCTION(bmk_thread3, p) {
chThdExit((msg_t)p);
}
static THD_FUNCTION(bmk_thread4, p) {
msg_t msg;
thread_t *self = chThdGetSelfX();
(void)p;
chSysLock();
do {
chSchGoSleepS(NIL_STATE_SUSPENDED);
msg = self->u1.msg;
} while (msg == MSG_OK);
chSysUnlock();
}
/****************************************************************************
* Test cases.
****************************************************************************/
#if (CH_CFG_USE_MESSAGES) || defined(__DOXYGEN__)
/**
* @page nil_test_007_001 [7.1] Messages performance #1
*
* <h2>Description</h2>
* A message server thread is created with a lower priority than the
* client thread, the messages throughput per second is measured and
* the result printed on the output log.
*
* <h2>Conditions</h2>
* This test is only executed if the following preprocessor condition
* evaluates to true:
* - CH_CFG_USE_MESSAGES
* .
*
* <h2>Test Steps</h2>
* - [7.1.1] The messenger thread is started at a lower priority than
* the current thread.
* - [7.1.2] The number of messages exchanged is counted in a one
* second time window.
* - [7.1.3] Score is printed.
* .
*/
static void nil_test_007_001_execute(void) {
uint32_t n;
thread_t *tp;
/* [7.1.1] The messenger thread is started at a lower priority than
the current thread.*/
test_set_step(1);
{
thread_config_t tc = {
chThdGetPriorityX() + 1,
"messenger",
wa_common,
THD_WORKING_AREA_END(wa_common),
bmk_thread1,
NULL
};
tp = chThdCreate(&tc);
}
/* [7.1.2] The number of messages exchanged is counted in a one
second time window.*/
test_set_step(2);
{
n = msg_loop_test(tp);
chThdWait(tp);
}
/* [7.1.3] Score is printed.*/
test_set_step(3);
{
test_print("--- Score : ");
test_printn(n);
test_print(" msgs/S, ");
test_printn(n << 1);
test_println(" ctxswc/S");
}
}
static const testcase_t nil_test_007_001 = {
"Messages performance #1",
NULL,
NULL,
nil_test_007_001_execute
};
#endif /* CH_CFG_USE_MESSAGES */
#if (CH_CFG_USE_MESSAGES) || defined(__DOXYGEN__)
/**
* @page nil_test_007_002 [7.2] Messages performance #2
*
* <h2>Description</h2>
* A message server thread is created with an higher priority than the
* client thread, the messages throughput per second is measured and
* the result printed on the output log.
*
* <h2>Conditions</h2>
* This test is only executed if the following preprocessor condition
* evaluates to true:
* - CH_CFG_USE_MESSAGES
* .
*
* <h2>Test Steps</h2>
* - [7.2.1] The messenger thread is started at an higher priority than
* the current thread.
* - [7.2.2] The number of messages exchanged is counted in a one
* second time window.
* - [7.2.3] Score is printed.
* .
*/
static void nil_test_007_002_execute(void) {
uint32_t n;
thread_t *tp;
/* [7.2.1] The messenger thread is started at an higher priority than
the current thread.*/
test_set_step(1);
{
thread_config_t tc = {
chThdGetPriorityX() - 1,
"messenger",
wa_common,
THD_WORKING_AREA_END(wa_common),
bmk_thread1,
NULL
};
tp = chThdCreate(&tc);
}
/* [7.2.2] The number of messages exchanged is counted in a one
second time window.*/
test_set_step(2);
{
n = msg_loop_test(tp);
chThdWait(tp);
}
/* [7.2.3] Score is printed.*/
test_set_step(3);
{
test_print("--- Score : ");
test_printn(n);
test_print(" msgs/S, ");
test_printn(n << 1);
test_println(" ctxswc/S");
}
}
static const testcase_t nil_test_007_002 = {
"Messages performance #2",
NULL,
NULL,
nil_test_007_002_execute
};
#endif /* CH_CFG_USE_MESSAGES */
/**
* @page nil_test_007_003 [7.3] Context Switch performance
*
* <h2>Description</h2>
* A thread is created that just performs a @p chSchGoSleepS() into a
* loop, the thread is awakened as fast is possible by the tester
* thread.<br> The Context Switch performance is calculated by
* measuring the number of iterations after a second of continuous
* operations.
*
* <h2>Test Steps</h2>
* - [7.3.1] Starting the target thread at an higher priority level.
* - [7.3.2] Waking up the thread as fast as possible in a one second
* time window.
* - [7.3.3] Stopping the target thread.
* - [7.3.4] Score is printed.
* .
*/
static void nil_test_007_003_execute(void) {
thread_t *tp;
uint32_t n;
/* [7.3.1] Starting the target thread at an higher priority level.*/
test_set_step(1);
{
thread_config_t tc = {
chThdGetPriorityX() - 1,
"messenger",
wa_common,
THD_WORKING_AREA_END(wa_common),
bmk_thread4,
NULL
};
tp = chThdCreate(&tc);
}
/* [7.3.2] Waking up the thread as fast as possible in a one second
time window.*/
test_set_step(2);
{
systime_t start, end;
n = 0;
start = test_wait_tick();
end = chTimeAddX(start, TIME_MS2I(1000));
do {
chSysLock();
chSchWakeupS(tp, MSG_OK);
chSchWakeupS(tp, MSG_OK);
chSchWakeupS(tp, MSG_OK);
chSchWakeupS(tp, MSG_OK);
chSysUnlock();
n += 4;
} while (chVTIsSystemTimeWithinX(start, end));
}
/* [7.3.3] Stopping the target thread.*/
test_set_step(3);
{
chSysLock();
chSchWakeupS(tp, MSG_TIMEOUT);
chSysUnlock();
chThdWait(tp);
}
/* [7.3.4] Score is printed.*/
test_set_step(4);
{
test_print("--- Score : ");
test_printn(n * 2);
test_println(" ctxswc/S");
}
}
static const testcase_t nil_test_007_003 = {
"Context Switch performance",
NULL,
NULL,
nil_test_007_003_execute
};
/**
* @page nil_test_007_004 [7.4] Threads performance, full cycle
*
* <h2>Description</h2>
* Threads are continuously created and terminated into a loop. A full
* chThdCreateStatic() / @p chThdExit() / @p chThdWait() cycle is
* performed in each iteration.<br> The performance is calculated by
* measuring the number of iterations after a second of continuous
* operations.
*
* <h2>Test Steps</h2>
* - [7.4.1] A thread is created at a lower priority level and its
* termination detected using @p chThdWait(). The operation is
* repeated continuously in a one-second time window.
* - [7.4.2] Score is printed.
* .
*/
static void nil_test_007_004_execute(void) {
uint32_t n;
/* [7.4.1] A thread is created at a lower priority level and its
termination detected using @p chThdWait(). The operation is
repeated continuously in a one-second time window.*/
test_set_step(1);
{
systime_t start, end;
thread_config_t tc = {
chThdGetPriorityX() + 1,
"messenger",
wa_common,
THD_WORKING_AREA_END(wa_common),
bmk_thread3,
NULL
};
n = 0;
start = test_wait_tick();
end = chTimeAddX(start, TIME_MS2I(1000));
do {
chThdWait(chThdCreate(&tc));
n++;
} while (chVTIsSystemTimeWithinX(start, end));
}
/* [7.4.2] Score is printed.*/
test_set_step(2);
{
test_print("--- Score : ");
test_printn(n);
test_println(" threads/S");
}
}
static const testcase_t nil_test_007_004 = {
"Threads performance, full cycle",
NULL,
NULL,
nil_test_007_004_execute
};
/**
* @page nil_test_007_005 [7.5] Threads performance, create/exit only
*
* <h2>Description</h2>
* Threads are continuously created and terminated into a loop. A
* partial @p chThdCreateStatic() / @p chThdExit() cycle is performed
* in each iteration, the @p chThdWait() is not necessary because the
* thread is created at an higher priority so there is no need to wait
* for it to terminate.<br> The performance is calculated by measuring
* the number of iterations after a second of continuous operations.
*
* <h2>Test Steps</h2>
* - [7.5.1] A thread is created at an higher priority level and let
* terminate immediately. The operation is repeated continuously in a
* one-second time window.
* - [7.5.2] Score is printed.
* .
*/
static void nil_test_007_005_execute(void) {
uint32_t n;
/* [7.5.1] A thread is created at an higher priority level and let
terminate immediately. The operation is repeated continuously in a
one-second time window.*/
test_set_step(1);
{
systime_t start, end;
thread_config_t tc = {
chThdGetPriorityX() - 1,
"messenger",
wa_common,
THD_WORKING_AREA_END(wa_common),
bmk_thread3,
NULL
};
n = 0;
start = test_wait_tick();
end = chTimeAddX(start, TIME_MS2I(1000));
do {
chThdWait(chThdCreate(&tc));
n++;
} while (chVTIsSystemTimeWithinX(start, end));
}
/* [7.5.2] Score is printed.*/
test_set_step(2);
{
test_print("--- Score : ");
test_printn(n);
test_println(" threads/S");
}
}
static const testcase_t nil_test_007_005 = {
"Threads performance, create/exit only",
NULL,
NULL,
nil_test_007_005_execute
};
#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
/**
* @page nil_test_007_006 [7.6] Semaphores wait/signal performance
*
* <h2>Description</h2>
* A counting semaphore is taken/released into a continuous loop, no
* Context Switch happens because the counter is always non
* negative.<br> The performance is calculated by measuring the number
* of iterations after a second of continuous operations.
*
* <h2>Conditions</h2>
* This test is only executed if the following preprocessor condition
* evaluates to true:
* - CH_CFG_USE_SEMAPHORES
* .
*
* <h2>Test Steps</h2>
* - [7.6.1] A semaphore is teken and released. The operation is
* repeated continuously in a one-second time window.
* - [7.6.2] The score is printed.
* .
*/
static void nil_test_007_006_setup(void) {
chSemObjectInit(&sem1, 1);
}
static void nil_test_007_006_execute(void) {
uint32_t n;
/* [7.6.1] A semaphore is teken and released. The operation is
repeated continuously in a one-second time window.*/
test_set_step(1);
{
systime_t start, end;
n = 0;
start = test_wait_tick();
end = chTimeAddX(start, TIME_MS2I(1000));
do {
chSemWait(&sem1);
chSemSignal(&sem1);
chSemWait(&sem1);
chSemSignal(&sem1);
chSemWait(&sem1);
chSemSignal(&sem1);
chSemWait(&sem1);
chSemSignal(&sem1);
n++;
#if defined(SIMULATOR)
_sim_check_for_interrupts();
#endif
} while (chVTIsSystemTimeWithinX(start, end));
}
/* [7.6.2] The score is printed.*/
test_set_step(2);
{
test_print("--- Score : ");
test_printn(n * 4);
test_println(" wait+signal/S");
}
}
static const testcase_t nil_test_007_006 = {
"Semaphores wait/signal performance",
nil_test_007_006_setup,
NULL,
nil_test_007_006_execute
};
#endif /* CH_CFG_USE_SEMAPHORES */
/**
* @page nil_test_007_007 [7.7] RAM Footprint
*
* <h2>Description</h2>
* The memory size of the various kernel objects is printed.
*
* <h2>Test Steps</h2>
* - [7.7.1] The size of the system area is printed.
* - [7.7.2] The size of a thread structure is printed.
* - [7.7.3] The size of a semaphore structure is printed.
* - [7.7.4] The size of an event source is printed.
* - [7.7.5] The size of an event listener is printed.
* - [7.7.6] The size of a mailbox is printed.
* .
*/
static void nil_test_007_007_execute(void) {
/* [7.7.1] The size of the system area is printed.*/
test_set_step(1);
{
test_print("--- System: ");
test_printn(sizeof(nil_system_t));
test_println(" bytes");
}
/* [7.7.2] The size of a thread structure is printed.*/
test_set_step(2);
{
test_print("--- Thread: ");
test_printn(sizeof(thread_t));
test_println(" bytes");
}
/* [7.7.3] The size of a semaphore structure is printed.*/
test_set_step(3);
{
#if CH_CFG_USE_SEMAPHORES || defined(__DOXYGEN__)
test_print("--- Semaph: ");
test_printn(sizeof(semaphore_t));
test_println(" bytes");
#endif
}
/* [7.7.4] The size of an event source is printed.*/
test_set_step(4);
{
#if CH_CFG_USE_EVENTS || defined(__DOXYGEN__)
test_print("--- EventS: ");
test_printn(sizeof(event_source_t));
test_println(" bytes");
#endif
}
/* [7.7.5] The size of an event listener is printed.*/
test_set_step(5);
{
#if CH_CFG_USE_EVENTS || defined(__DOXYGEN__)
test_print("--- EventL: ");
test_printn(sizeof(event_listener_t));
test_println(" bytes");
#endif
}
/* [7.7.6] The size of a mailbox is printed.*/
test_set_step(6);
{
#if CH_CFG_USE_MAILBOXES || defined(__DOXYGEN__)
test_print("--- MailB.: ");
test_printn(sizeof(mailbox_t));
test_println(" bytes");
#endif
}
}
static const testcase_t nil_test_007_007 = {
"RAM Footprint",
NULL,
NULL,
nil_test_007_007_execute
};
/****************************************************************************
* Exported data.
****************************************************************************/
/**
* @brief Array of test cases.
*/
const testcase_t * const nil_test_sequence_007_array[] = {
#if (CH_CFG_USE_MESSAGES) || defined(__DOXYGEN__)
&nil_test_007_001,
#endif
#if (CH_CFG_USE_MESSAGES) || defined(__DOXYGEN__)
&nil_test_007_002,
#endif
&nil_test_007_003,
&nil_test_007_004,
&nil_test_007_005,
#if (CH_CFG_USE_SEMAPHORES) || defined(__DOXYGEN__)
&nil_test_007_006,
#endif
&nil_test_007_007,
NULL
};
/**
* @brief Benchmarks.
*/
const testsequence_t nil_test_sequence_007 = {
"Benchmarks",
nil_test_sequence_007_array
};

View File

@ -0,0 +1,27 @@
/*
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
Licensed under the Apache License, Version 2.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://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file nil_test_sequence_007.h
* @brief Test Sequence 007 header.
*/
#ifndef NIL_TEST_SEQUENCE_007_H
#define NIL_TEST_SEQUENCE_007_H
extern const testsequence_t nil_test_sequence_007;
#endif /* NIL_TEST_SEQUENCE_007_H */