benchmarks: convert latency_measure to unified kernel

Change-Id: If92833d699b95f5a7e813d0577f5467b06d3a1b6
Signed-off-by: Anas Nashif <anas.nashif@intel.com>
This commit is contained in:
Anas Nashif 2017-03-24 10:23:40 -04:00 committed by Anas Nashif
commit 0505c9c881
25 changed files with 342 additions and 881 deletions

View file

@ -1,4 +1,3 @@
MDEF_FILE = prj.mdef
BOARD ?= qemu_x86
small_freq_divider_frdm_k64f=y

View file

@ -0,0 +1,41 @@
Title: Latency Measurement
Description:
This benchmark measures the latency of selected capabilities
IMPORTANT: The sample output below was generated using a simulation
environment, and may not reflect the results that will be generated using other
environments (simulated or otherwise).
Sample Output:
***** BOOTING ZEPHYR OS v1.7.99 - BUILD: Mar 24 2017 22:46:05 *****
|-----------------------------------------------------------------------------|
| Latency Benchmark |
|-----------------------------------------------------------------------------|
| tcs = timer clock cycles: 1 tcs is 10 nsec |
|-----------------------------------------------------------------------------|
| 1 - Measure time to switch from ISR back to interrupted thread |
| switching time is 12591 tcs = 125910 nsec |
|-----------------------------------------------------------------------------|
| 2 - Measure time from ISR to executing a different thread (rescheduled) |
| switch time is 8344 tcs = 83440 nsec |
|-----------------------------------------------------------------------------|
| 3 - Measure average time to signal a sema then test that sema |
| Average semaphore signal time 63 tcs = 638 nsec |
| Average semaphore test time 49 tcs = 498 nsec |
|-----------------------------------------------------------------------------|
| 4- Measure average time to lock a mutex then unlock that mutex |
| Average time to lock the mutex 107 tcs = 1078 nsec |
| Average time to unlock the mutex 92 tcs = 929 nsec |
|-----------------------------------------------------------------------------|
| 5 - Measure average context switch time between threads using (k_yield) |
| Average thread context switch using yield 110 tcs = 1107 nsec |
|-----------------------------------------------------------------------------|
| 6 - Measure average context switch time between threads (coop) |
| Average context switch time is 88 tcs = 882 nsec |
|-----------------------------------------------------------------------------|
===================================================================
PROJECT EXECUTION SUCCESSFUL

View file

@ -10,3 +10,7 @@ CONFIG_LEGACY_KERNEL=y
# Reduce memory/code footprint
CONFIG_BLUETOOTH=n
#CONFIG_KERNEL_SHELL=y
#CONFIG_CONSOLE_SHELL=y
#CONFIG_OBJECT_TRACING=y
#CONFIG_THREAD_MONITOR=y

View file

@ -0,0 +1,10 @@
ccflags-y += -I$(ZEPHYR_BASE)/tests/include
ccflags-$(CONFIG_SOC_QUARK_D2000) += -DSTACKSIZE=256
obj-y = main.o \
thread_switch_yield.o \
int_to_thread.o \
int_to_thread_evt.o \
sema_lock_release.o \
coop_ctx_switch.o \
utils.o

View file

@ -0,0 +1,115 @@
/*
* Copyright (c) 2012-2014 Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file measure context switch time between cooperative threads
*
* This file contains thread (coop) context switch time measurement.
* The thread starts two cooperative thread. One thread waits on a semaphore. The other,
* after starting, releases a semaphore which enable the first thread to run.
* Each thread increases a common global counter and context switch back and
* forth by yielding the cpu. When counter reaches the maximal value, threads
* stop and the average time of context switch is displayed.
*/
#include "timestamp.h"
#include "utils.h"
#include <arch/cpu.h>
/* number of context switches */
#define NCTXSWITCH 10000
#ifndef STACKSIZE
#define STACKSIZE 512
#endif
/* stack used by the fibers */
static char __stack thread_one_stack[STACKSIZE];
static char __stack thread_two_stack[STACKSIZE];
static uint32_t timestamp;
/* context switches counter */
static volatile uint32_t ctx_switch_counter;
/* context switch balancer. Incremented by one thread, decremented by another*/
static volatile int ctx_switch_balancer;
K_SEM_DEFINE(sync_sema, 0, 1);
/**
*
* thread_onne
*
* Fiber makes all the test preparations: registers the interrupt handler,
* gets the first timestamp and invokes the software interrupt.
*
* @return N/A
*/
static void thread_one(void)
{
k_sem_take(&sync_sema, K_FOREVER);
timestamp = TIME_STAMP_DELTA_GET(0);
while (ctx_switch_counter < NCTXSWITCH) {
k_yield();
ctx_switch_counter++;
ctx_switch_balancer--;
}
timestamp = TIME_STAMP_DELTA_GET(timestamp);
}
/**
*
* @brief Check the time when it gets executed after the semaphore
*
* Fiber starts, waits on semaphore. When the interrupt handler releases
* the semaphore, thread measures the time.
*
* @return 0 on success
*/
static void thread_two(void)
{
k_sem_give(&sync_sema);
while (ctx_switch_counter < NCTXSWITCH) {
k_yield();
ctx_switch_counter++;
ctx_switch_balancer++;
}
}
/**
*
* @brief The test main function
*
* @return 0 on success
*/
int coop_ctx_switch(void)
{
PRINT_FORMAT(" 6 - Measure average context switch time between threads (coop)");
ctx_switch_counter = 0;
ctx_switch_balancer = 0;
bench_test_start();
k_thread_spawn(&thread_one_stack[0], STACKSIZE,
(k_thread_entry_t) thread_one, NULL, NULL, NULL, 6, 0, K_NO_WAIT);
k_thread_spawn(&thread_two_stack[0], STACKSIZE,
(k_thread_entry_t) thread_two, NULL, NULL, NULL, 6, 0, K_NO_WAIT);
if (ctx_switch_balancer > 3 || ctx_switch_balancer < -3) {
PRINT_FORMAT(" Balance is %d. FAILED", ctx_switch_balancer);
} else if (bench_test_end() != 0) {
error_count++;
PRINT_OVERFLOW_ERROR();
} else {
PRINT_FORMAT(" Average context switch time is %u tcs = %u"
" nsec",
timestamp / ctx_switch_counter,
SYS_CLOCK_HW_CYCLES_TO_NS_AVG(timestamp,
ctx_switch_counter));
}
return 0;
}

View file

@ -1,15 +1,15 @@
/* micro_int_to_task.c - measure time from ISR back to interrupted task */
/*
* Copyright (c) 2012-2014 Wind River Systems, Inc.
* Copyright (c) 2017 Intel Corporation.
*
* SPDX-License-Identifier: Apache-2.0
*/
/*
* DESCRIPTION
/**
* @file measure time from ISR back to interrupted thread
*
* This file contains test that measures time to switch from the interrupt
* handler back to the interrupted task in microkernel.
* handler back to the interrupted thread.
*/
#include "timestamp.h"
@ -18,7 +18,7 @@
#include <arch/cpu.h>
#include <irq_offload.h>
static volatile int flagVar;
static volatile int flag_var;
static uint32_t timestamp;
@ -30,11 +30,11 @@ static uint32_t timestamp;
*
* @return N/A
*/
static void latencyTestIsr(void *unused)
static void latency_test_isr(void *unused)
{
ARG_UNUSED(unused);
flagVar = 1;
flag_var = 1;
timestamp = TIME_STAMP_DELTA_GET(0);
}
@ -47,11 +47,11 @@ static void latencyTestIsr(void *unused)
*
* @return N/A
*/
static void makeInt(void)
static void make_int(void)
{
flagVar = 0;
irq_offload(latencyTestIsr, NULL);
if (flagVar != 1) {
flag_var = 0;
irq_offload(latency_test_isr, NULL);
if (flag_var != 1) {
PRINT_FORMAT(" Flag variable has not changed. FAILED\n");
} else {
timestamp = TIME_STAMP_DELTA_GET(timestamp);
@ -64,13 +64,13 @@ static void makeInt(void)
*
* @return 0 on success
*/
int microIntToTask(void)
int int_to_thread(void)
{
PRINT_FORMAT(" 1 - Measure time to switch from ISR back to"
" interrupted task");
" interrupted thread");
TICK_SYNCH();
makeInt();
if (flagVar == 1) {
make_int();
if (flag_var == 1) {
PRINT_FORMAT(" switching time is %u tcs = %u nsec",
timestamp, SYS_CLOCK_HW_CYCLES_TO_NS(timestamp));
}

View file

@ -1,16 +1,15 @@
/* micro_int_to_task_evt.c - measure time from ISR to a rescheduled task */
/*
* Copyright (c) 2012-2014 Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
/*
* DESCRIPTION
/**
* @file measure time from ISR to a rescheduled thread
*
* This file contains test that measures time to switch from an interrupt
* handler to executing a task after rescheduling. In other words, execution
* after interrupt handler resume in a different task than the one which got
* handler to executing a thread after rescheduling. In other words, execution
* after interrupt handler resume in a different thread than the one which got
* interrupted.
*/
@ -24,6 +23,10 @@
static uint32_t timestamp;
K_SEM_DEFINE(INTSEMA, 0, 1);
K_ALERT_DEFINE(EVENT0, NULL, 10);
/**
*
* @brief Test ISR used to measure best case interrupt latency
@ -32,44 +35,49 @@ static uint32_t timestamp;
*
* @return N/A
*/
static void latencyTestIsr(void *unused)
static void latency_test_isr(void *unused)
{
ARG_UNUSED(unused);
isr_event_send(EVENT0);
k_alert_send(&EVENT0);
timestamp = TIME_STAMP_DELTA_GET(0);
}
/**
*
* @brief Software interrupt generating task
* @brief Software interrupt generating thread
*
* Lower priority task that, when starts, waits for a semaphore. When gets
* it, released by the main task, sets up the interrupt handler and generates
* the software interrupt
* Lower priority thread that, when it starts, it waits for a semaphore. When
* it gets it, released by the main thread, sets up the interrupt handler and
* generates the software interrupt
*
* @return 0 on success
*/
void microInt(void)
void int_thread(void)
{
task_sem_take(INTSEMA, TICKS_UNLIMITED);
irq_offload(latencyTestIsr, NULL);
task_suspend(task_id_get());
k_sem_take(&INTSEMA, K_FOREVER);
irq_offload(latency_test_isr, NULL);
k_thread_suspend(k_current_get());
}
K_THREAD_DEFINE(int_thread_id, 512,
(k_thread_entry_t) int_thread, NULL, NULL, NULL,
11, 0, K_NO_WAIT);
/**
*
* @brief The test main function
*
* @return 0 on success
*/
int microIntToTaskEvt(void)
int int_to_thread_evt(void)
{
PRINT_FORMAT(" 2 - Measure time from ISR to executing a different task"
PRINT_FORMAT(" 2 - Measure time from ISR to executing a different thread"
" (rescheduled)");
TICK_SYNCH();
task_sem_give(INTSEMA);
task_event_recv(EVENT0, TICKS_UNLIMITED);
k_sem_give(&INTSEMA);
k_alert_recv(&EVENT0, K_FOREVER);
timestamp = TIME_STAMP_DELTA_GET(timestamp);
PRINT_FORMAT(" switch time is %u tcs = %u nsec",
timestamp, SYS_CLOCK_HW_CYCLES_TO_NS(timestamp));

View file

@ -0,0 +1,63 @@
/*
* Copyright (c) 2012-2015 Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
/*
* @file
* This file contains the main testing module that invokes all the tests.
*/
#include <timestamp.h>
#include "utils.h"
#include <tc_util.h>
#define STACK_SIZE 1024
uint32_t tm_off; /* time necessary to read the time */
int error_count; /* track number of errors */
extern void thread_switch_yield(void);
extern void int_to_thread(void);
extern void int_to_thread_evt(void);
extern void sema_lock_unlock(void);
extern void mutex_lock_unlock(void);
extern int coop_ctx_switch(void);
void test_thread(void *arg1, void *arg2, void *arg3)
{
PRINT_BANNER();
PRINT_TIME_BANNER();
bench_test_init();
int_to_thread();
print_dash_line();
int_to_thread_evt();
print_dash_line();
sema_lock_unlock();
print_dash_line();
mutex_lock_unlock();
print_dash_line();
thread_switch_yield();
print_dash_line();
coop_ctx_switch();
print_dash_line();
TC_END_REPORT(error_count);
}
K_THREAD_DEFINE(tt_id, STACK_SIZE,
test_thread, NULL, NULL, NULL,
10, 0, K_NO_WAIT);
void main(void)
{
}

View file

@ -1,4 +1,3 @@
/* micro_sema_lock_release.c - measure time for sema lock and release */
/*
* Copyright (c) 2012-2015 Wind River Systems, Inc.
@ -7,9 +6,10 @@
*/
/*
* DESCRIPTION
* @file measure time for sema lock and release
*
* This file contains the test that measures semaphore and mutex lock and
* release time in a microkernel. There is no contention on the sema nor the
* release time in the kernel. There is no contention on the sema nor the
* mutex being tested.
*/
@ -28,6 +28,9 @@
static uint32_t timestamp;
K_SEM_DEFINE(lock_unlock_sema, 0, N_TEST_SEMA);
K_MUTEX_DEFINE(TEST_MUTEX);
/**
*
* @brief The function tests semaphore lock/unlock time
@ -37,7 +40,7 @@ static uint32_t timestamp;
*
* @return 0 on success
*/
int microSemaLockUnlock(void)
int sema_lock_unlock(void)
{
int i;
@ -46,7 +49,7 @@ int microSemaLockUnlock(void)
bench_test_start();
timestamp = TIME_STAMP_DELTA_GET(0);
for (i = 0; i < N_TEST_SEMA; i++) {
task_sem_give(SEMA_LOCK_UNLOCK);
k_sem_give(&lock_unlock_sema);
}
timestamp = TIME_STAMP_DELTA_GET(timestamp);
if (bench_test_end() == 0) {
@ -56,14 +59,14 @@ int microSemaLockUnlock(void)
SYS_CLOCK_HW_CYCLES_TO_NS_AVG(timestamp,
N_TEST_SEMA));
} else {
errorCount++;
error_count++;
PRINT_OVERFLOW_ERROR();
}
bench_test_start();
timestamp = TIME_STAMP_DELTA_GET(0);
for (i = 0; i < N_TEST_SEMA; i++) {
task_sem_take(SEMA_LOCK_UNLOCK, TICKS_UNLIMITED);
k_sem_take(&lock_unlock_sema, K_FOREVER);
}
timestamp = TIME_STAMP_DELTA_GET(timestamp);
if (bench_test_end() == 0) {
@ -73,7 +76,7 @@ int microSemaLockUnlock(void)
SYS_CLOCK_HW_CYCLES_TO_NS_AVG(timestamp,
N_TEST_SEMA));
} else {
errorCount++;
error_count++;
PRINT_OVERFLOW_ERROR();
}
return 0;
@ -88,7 +91,7 @@ int microSemaLockUnlock(void)
*
* @return 0 on success
*/
int microMutexLockUnlock(void)
int mutex_lock_unlock(void)
{
int i;
@ -96,7 +99,7 @@ int microMutexLockUnlock(void)
" unlock that mutex");
timestamp = TIME_STAMP_DELTA_GET(0);
for (i = 0; i < N_TEST_MUTEX; i++) {
task_mutex_lock(TEST_MUTEX, TICKS_UNLIMITED);
k_mutex_lock(&TEST_MUTEX, K_FOREVER);
}
timestamp = TIME_STAMP_DELTA_GET(timestamp);
PRINT_FORMAT(" Average time to lock the mutex %u tcs = %u nsec",
@ -104,7 +107,7 @@ int microMutexLockUnlock(void)
SYS_CLOCK_HW_CYCLES_TO_NS_AVG(timestamp, N_TEST_MUTEX));
timestamp = TIME_STAMP_DELTA_GET(0);
for (i = 0; i < N_TEST_MUTEX; i++) {
task_mutex_unlock(TEST_MUTEX);
k_mutex_unlock(&TEST_MUTEX);
}
timestamp = TIME_STAMP_DELTA_GET(timestamp);
PRINT_FORMAT(" Average time to unlock the mutex %u tcs = %u nsec",

View file

@ -1,73 +1,78 @@
/* micro_task_switch_yield.c - measure task context switch time using yield */
/*
* Copyright (c) 2012-2014 Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
/*
* DESCRIPTION
/**
* @file
* This file contains the benchmark that measure the average time it takes to
* do context switches between microkernel tasks using task_yield () to force
* do context switches between threads using k_yield () to force
* context switch.
*/
#include <zephyr.h>
#include "timestamp.h" /* reading time */
#include <timestamp.h> /* reading time */
#include "utils.h" /* PRINT () and other macros */
/* <stdlib.h> is not supported */
static int abs(int i) { return (i >= 0) ? i : -i; }
static int abs(int i)
{
return (i >= 0) ? i : -i;
}
/* context switch enough time so our measurement is precise */
#define NB_OF_YIELD 1000
static uint32_t helper_task_iterations;
static uint32_t helper_thread_iterations;
#define Y_STACK_SIZE 512
#define Y_PRIORITY 10
char __noinit __stack y_stack_area[Y_STACK_SIZE];
/**
*
* @brief Helper task for measuring task switch latency using yield
*
* This task is define in .mdef as SEMYIELDTSK
* @brief Helper thread for measuring thread switeh latency using yield
*
* @return N/A
*/
void yieldingTask(void)
void yielding_thread(void *arg1, void *arg2, void *arg3)
{
while (helper_task_iterations < NB_OF_YIELD) {
task_yield();
helper_task_iterations++;
while (helper_thread_iterations < NB_OF_YIELD) {
k_yield();
helper_thread_iterations++;
}
}
/**
*
* @brief Entry point for task context switch using yield test
* @brief Entry point for thread context switch using yield test
*
* @return N/A
*/
void microTaskSwitchYield(void)
void thread_switch_yield(void)
{
uint32_t iterations = 0;
int32_t delta;
uint32_t timestamp;
PRINT_FORMAT(" 5- Measure average context switch time between tasks"
" using (task_yield)");
PRINT_FORMAT(" 5 - Measure average context switch time between threads"
" using (k_yield)");
bench_test_start();
/* launch helper task of the same priority than this routine */
task_start(YIELDTASK);
/* launch helper thread of the same priority than this routine */
k_thread_spawn(y_stack_area, Y_STACK_SIZE, yielding_thread, NULL, NULL, NULL,
Y_PRIORITY, 0, K_NO_WAIT);
/* get initial timestamp */
timestamp = TIME_STAMP_DELTA_GET(0);
/* loop until either helper or this routine reaches number of yields */
while (iterations < NB_OF_YIELD &&
helper_task_iterations < NB_OF_YIELD) {
task_yield();
helper_thread_iterations < NB_OF_YIELD) {
k_yield();
iterations++;
}
@ -81,25 +86,25 @@ void microTaskSwitchYield(void)
* iteration away from reaching NB_OF_YIELD if execute was switching
* back and forth.
*/
delta = iterations - helper_task_iterations;
delta = iterations - helper_thread_iterations;
if (bench_test_end() < 0) {
errorCount++;
error_count++;
PRINT_OVERFLOW_ERROR();
} else if (abs(delta) > 1) {
/* expecting even alternating context switch, seems one routine
* called yield without the other having chance to execute
*/
errorCount++;
error_count++;
PRINT_FORMAT(" Error, iteration:%u, helper iteration:%u",
iterations, helper_task_iterations);
iterations, helper_thread_iterations);
} else {
/* task_yield is called (iterations + helper_task_iterations)
/* thread_yield is called (iterations + helper_thread_iterations)
* times in total.
*/
PRINT_FORMAT(" Average task context switch using "
PRINT_FORMAT(" Average thread context switch using "
"yield %u tcs = %u nsec",
timestamp / (iterations + helper_task_iterations),
timestamp / (iterations + helper_thread_iterations),
SYS_CLOCK_HW_CYCLES_TO_NS_AVG(timestamp,
(iterations + helper_task_iterations)));
(iterations + helper_thread_iterations)));
}
}

View file

@ -17,5 +17,5 @@
#include "utils.h"
/* scratchpad for the string used to print on console */
char tmpString[TMP_STRING_SIZE];
char tmp_string[TMP_STRING_SIZE];

View file

@ -19,8 +19,8 @@
#include <misc/printk.h>
#include <stdio.h>
#include "timestamp.h"
extern char tmpString[];
extern int errorCount;
extern char tmp_string[];
extern int error_count;
#define TMP_STRING_SIZE 100
@ -29,8 +29,8 @@ extern int errorCount;
#define PRINT_FORMAT(fmt, ...) \
do { \
snprintf(tmpString, TMP_STRING_SIZE, fmt, ##__VA_ARGS__); \
PRINTF("|%-77s|\n", tmpString); \
snprintf(tmp_string, TMP_STRING_SIZE, fmt, ##__VA_ARGS__); \
PRINTF("|%-77s|\n", tmp_string); \
} while (0)
/**
@ -39,7 +39,7 @@ extern int errorCount;
*
* @return N/A
*/
static inline void printDashLine(void)
static inline void print_dash_line(void)
{
PRINTF("|-------------------------------------------------------"
"----------------------|\n");
@ -49,23 +49,16 @@ static inline void printDashLine(void)
do { \
PRINTF("| E N D " \
" |\n"); \
printDashLine(); \
print_dash_line(); \
} while (0)
#define PRINT_NANO_BANNER() \
do { \
printDashLine(); \
PRINTF("| Nanokernel Latency Benchmark " \
" |\n"); \
printDashLine(); \
} while (0)
#define PRINT_MICRO_BANNER() \
#define PRINT_BANNER() \
do { \
printDashLine(); \
PRINTF("| Microkernel Latency Benchmark " \
print_dash_line(); \
PRINTF("| Latency Benchmark " \
" |\n"); \
printDashLine(); \
print_dash_line(); \
} while (0)
@ -73,7 +66,7 @@ static inline void printDashLine(void)
do { \
PRINT_FORMAT(" tcs = timer clock cycles: 1 tcs is %u nsec", \
SYS_CLOCK_HW_CYCLES_TO_NS(1)); \
printDashLine(); \
print_dash_line(); \
} while (0)
#define PRINT_OVERFLOW_ERROR() \
@ -86,13 +79,6 @@ static inline void printDashLine(void)
void raiseIntFunc(void);
extern void raiseInt(uint8_t id);
/* test the interrupt latency */
int nanoIntLatency(void);
int nanoIntToFiber(void);
int nanoIntToFiberSem(void);
int nanoCtxSwitch(void);
int nanoIntLockUnlock(void);
/* pointer to the ISR */
typedef void (*ptestIsr) (void *unused);

View file

@ -1,87 +0,0 @@
Title: Latency Measurement
Description:
This benchmark measures the latency of selected capabilities of both the
nanokernel and microkernel.
IMPORTANT: The sample output below was generated using a simulation
environment, and may not reflect the results that will be generated using other
environments (simulated or otherwise).
--------------------------------------------------------------------------------
Building and Running Project:
This microkernel project outputs to the console. It can be built and executed
on QEMU as follows:
make qemu
--------------------------------------------------------------------------------
Troubleshooting:
Problems caused by out-dated project information can be addressed by
issuing one of the following commands then rebuilding the project:
make clean # discard results of previous builds
# but keep existing configuration info
or
make pristine # discard results of previous builds
# and restore pre-defined configuration info
--------------------------------------------------------------------------------
Sample Output:
|-----------------------------------------------------------------------------|
| Nanokernel Latency Benchmark |
|-----------------------------------------------------------------------------|
| tcs = timer clock cycles: 1 tcs is N nsec |
|-----------------------------------------------------------------------------|
| 1- Measure time to switch from fiber to ISR execution |
| switching time is NNNN tcs = NNNNN nsec |
|-----------------------------------------------------------------------------|
| 2- Measure time to switch from ISR back to interrupted fiber |
| switching time is NNNN tcs = NNNNN nsec |
|-----------------------------------------------------------------------------|
| 3- Measure time from ISR to executing a different fiber (rescheduled) |
| switching time is NNNN tcs = NNNNN nsec |
|-----------------------------------------------------------------------------|
| 4- Measure average context switch time between fibers |
| Average context switch time is NNNN tcs = NNNNN nsec |
|-----------------------------------------------------------------------------|
| 5- Measure average time to lock then unlock interrupts |
| 5.1- When each lock and unlock is executed as a function call |
| Average time for lock then unlock is NNNN tcs = NNNN nsec |
| |
| 5.2- When each lock and unlock is executed as inline function call |
| Average time for lock then unlock is NNN tcs = NNNN nsec |
|-----------------------------------------------------------------------------|
|-----------------------------------------------------------------------------|
| Microkernel Latency Benchmark |
|-----------------------------------------------------------------------------|
| tcs = timer clock cycles: 1 tcs is N nsec |
|-----------------------------------------------------------------------------|
| 1- Measure time to switch from ISR to back to interrupted task |
| switching time is NNNN tcs = NNNNN nsec |
|-----------------------------------------------------------------------------|
| 2- Measure time from ISR to executing a different task (rescheduled) |
| switch time is NNNNN tcs = NNNNNN nsec |
|-----------------------------------------------------------------------------|
| 3- Measure average time to signal a sema then test that sema |
| Average semaphore signal time NNNNN tcs = NNNNNN nsec |
| Average semaphore test time NNNNN tcs = NNNNNN nsec |
|-----------------------------------------------------------------------------|
| 4- Measure average time to lock a mutex then unlock that mutex |
| Average time to lock the mutex NNNNN tcs = NNNNNN nsec |
| Average time to unlock the mutex NNNNN tcs = NNNNNN nsec |
|-----------------------------------------------------------------------------|
| 5- Measure average context switch time between tasks using (task_yield) |
| Average task context switch using yield NNNNN tcs = NNNNNN nsec |
|-----------------------------------------------------------------------------|
| E N D |
|-----------------------------------------------------------------------------|
===================================================================
PROJECT EXECUTION SUCCESSFUL

View file

@ -1,21 +0,0 @@
% Application : latency_measure
% Common definitions
% TASK NAME PRIO ENTRY STACK GROUPS
% ====================================================
TASK TESTTASK 10 microMain 1024 [EXE]
TASK INTTASK 11 microInt 512 [EXE]
TASK YIELDTASK 10 yieldingTask 512 []
% SEMA NAME
% ===============
SEMA INTSEMA
SEMA SEMA_LOCK_UNLOCK
% EVENT NAME HANDLER
% ======================
EVENT EVENT0 0
% MUTEX NAME
% ================
MUTEX TEST_MUTEX

View file

@ -1,15 +0,0 @@
ccflags-y += -I$(CURDIR)/misc/generated/sysgen
ccflags-y += -I$(ZEPHYR_BASE)/tests/include
ccflags-$(CONFIG_SOC_QUARK_D2000) += -DSTACKSIZE=256
obj-y = main.o \
micro_int_to_task_evt.o \
nano_ctx_switch.o \
nano_int_to_fiber.o \
micro_sema_lock_release.o \
nano_int.o \
nano_int_to_fiber_sem.o \
micro_int_to_task.o \
micro_task_switch_yield.o \
nano_int_lock_unlock.o \
utils.o

View file

@ -1,98 +0,0 @@
/* main.c - main testing module */
/*
* Copyright (c) 2012-2015 Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
/*
* DESCRIPTION
* This file contains the main testing module that invokes all the tests.
*/
#include "timestamp.h"
#include "utils.h"
#include <tc_util.h>
#include <arch/cpu.h>
uint32_t tm_off; /* time necessary to read the time */
int errorCount; /* track number of errors */
/**
*
* @brief Test latency of nanokernel
*
* @return N/A
*/
void nanoTest(void)
{
PRINT_NANO_BANNER();
PRINT_TIME_BANNER();
nanoIntLatency();
printDashLine();
nanoIntToFiber();
printDashLine();
nanoIntToFiberSem();
printDashLine();
nanoCtxSwitch();
printDashLine();
nanoIntLockUnlock();
printDashLine();
}
int microIntToTaskEvt(void);
int microIntToTask(void);
int microSemaLockUnlock(void);
int microMutexLockUnlock(void);
void microTaskSwitchYield(void);
/**
*
* @brief Test latency of microkernel
*
* @return N/A
*/
void microTest(void)
{
PRINT_MICRO_BANNER();
PRINT_TIME_BANNER();
microIntToTask();
printDashLine();
microIntToTaskEvt();
printDashLine();
microSemaLockUnlock();
printDashLine();
microMutexLockUnlock();
printDashLine();
microTaskSwitchYield();
printDashLine();
}
/**
*
* @brief Microkernel testing entry point
*
* @return N/A
*/
void microMain(void)
{
bench_test_init();
nanoTest();
microTest();
PRINT_END_BANNER();
TC_END_REPORT(errorCount);
}

View file

@ -1,116 +0,0 @@
/* nano_ctx_switch.c - measure context switch time between fibers */
/*
* Copyright (c) 2012-2014 Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
/*
* DESCRIPTION
* This file contains fiber context switch time measurement.
* The task starts two fibers. One fiber waits on a semaphore. The other,
* after starting, releases a semaphore which enable the first fiber to run.
* Each fiber increases a common global counter and context switch back and
* forth by yielding the cpu. When counter reaches the maximal value, fibers
* stop and the average time of context switch is displayed.
*/
#include "timestamp.h"
#include "utils.h"
#include <arch/cpu.h>
/* number of context switches */
#define NCTXSWITCH 10000
#ifndef STACKSIZE
#define STACKSIZE 512
#endif
/* stack used by the fibers */
static char __stack fiberOneStack[STACKSIZE];
static char __stack fiberTwoStack[STACKSIZE];
/* semaphore used for fibers synchronization */
static struct nano_sem syncSema;
static uint32_t timestamp;
/* context switches counter */
static volatile uint32_t ctxSwitchCounter;
/* context switch balancer. Incremented by one fiber, decremented by another*/
static volatile int ctxSwitchBalancer;
/**
*
* fiberOne
*
* Fiber makes all the test preparations: registers the interrupt handler,
* gets the first timestamp and invokes the software interrupt.
*
* @return N/A
*/
static void fiberOne(void)
{
nano_fiber_sem_take(&syncSema, TICKS_UNLIMITED);
timestamp = TIME_STAMP_DELTA_GET(0);
while (ctxSwitchCounter < NCTXSWITCH) {
fiber_yield();
ctxSwitchCounter++;
ctxSwitchBalancer--;
}
timestamp = TIME_STAMP_DELTA_GET(timestamp);
}
/**
*
* @brief Check the time when it gets executed after the semaphore
*
* Fiber starts, waits on semaphore. When the interrupt handler releases
* the semaphore, fiber measures the time.
*
* @return 0 on success
*/
static void fiberTwo(void)
{
nano_fiber_sem_give(&syncSema);
while (ctxSwitchCounter < NCTXSWITCH) {
fiber_yield();
ctxSwitchCounter++;
ctxSwitchBalancer++;
}
}
/**
*
* @brief The test main function
*
* @return 0 on success
*/
int nanoCtxSwitch(void)
{
PRINT_FORMAT(" 4- Measure average context switch time between fibers");
nano_sem_init(&syncSema);
ctxSwitchCounter = 0;
ctxSwitchBalancer = 0;
bench_test_start();
task_fiber_start(&fiberOneStack[0], STACKSIZE,
(nano_fiber_entry_t) fiberOne, 0, 0, 6, 0);
task_fiber_start(&fiberTwoStack[0], STACKSIZE,
(nano_fiber_entry_t) fiberTwo, 0, 0, 6, 0);
if (ctxSwitchBalancer > 3 || ctxSwitchBalancer < -3) {
PRINT_FORMAT(" Balance is %d. FAILED", ctxSwitchBalancer);
} else if (bench_test_end() != 0) {
errorCount++;
PRINT_OVERFLOW_ERROR();
} else {
PRINT_FORMAT(" Average context switch time is %u tcs = %u"
" nsec",
timestamp / ctxSwitchCounter,
SYS_CLOCK_HW_CYCLES_TO_NS_AVG(timestamp,
ctxSwitchCounter));
}
return 0;
}

View file

@ -1,75 +0,0 @@
/* nano_int.c - measure the time from task to ISR */
/*
* Copyright (c) 2012-2014 Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
/*
* DESCRIPTION
* This file contains test that measures time to switch time from a fiber
* to the interrupt handler when an interrupt is generated.
*/
#include "timestamp.h"
#include "utils.h"
#include <arch/cpu.h>
#include <irq_offload.h>
#ifndef STACKSIZE
#define STACKSIZE 512
#endif
/* stack used by the fiber that generates the interrupt */
static char __stack fiberStack[STACKSIZE];
static uint32_t timestamp;
/**
*
* @brief Test ISR used to measure best case interrupt latency
*
* The interrupt handler gets the second timestamp.
*
* @return N/A
*/
static void latencyTestIsr(void *unused)
{
ARG_UNUSED(unused);
timestamp = TIME_STAMP_DELTA_GET(timestamp);
}
/**
*
* @brief Interrupt preparation fiber
*
* Fiber makes all the test preparations: registers the interrupt handler,
* gets the first timestamp and invokes the software interrupt.
*
* @return N/A
*/
static void fiberInt(void)
{
timestamp = TIME_STAMP_DELTA_GET(0);
irq_offload(latencyTestIsr, NULL);
}
/**
*
* @brief The test main function
*
* @return 0 on success
*/
int nanoIntLatency(void)
{
PRINT_FORMAT(" 1- Measure time to switch from fiber to ISR execution");
TICK_SYNCH();
task_fiber_start(&fiberStack[0], STACKSIZE,
(nano_fiber_entry_t) fiberInt, 0, 0, 6, 0);
PRINT_FORMAT(" switching time is %u tcs = %u nsec",
timestamp, SYS_CLOCK_HW_CYCLES_TO_NS(timestamp));
return 0;
}

View file

@ -1,57 +0,0 @@
/* nano_int_lock_unlock.c - measure time for interrupts lock and unlock */
/*
* Copyright (c) 2012-2014 Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
/*
* DESCRIPTION
* This file contains test that measures average time needed to do a call
* to lock the interrupt lock and a call to unlock the interrupts. Typically
* users calls both of these functions to ensure interrupts are lock while
* some code executes. No explicit interrupts are generated during the test
* so the interrupt handler does not run.
*/
#include "timestamp.h"
#include "utils.h"
#include <arch/cpu.h>
/* total number of interrupt lock/unlock cycles */
#define NTESTS 100000
static uint32_t timestamp;
/**
*
* @brief The test main function
*
* @return 0 on success
*/
int nanoIntLockUnlock(void)
{
int i;
unsigned int mask;
PRINT_FORMAT(" 5- Measure average time to lock then unlock interrupts");
bench_test_start();
timestamp = TIME_STAMP_DELTA_GET(0);
for (i = 0; i < NTESTS; i++) {
mask = irq_lock();
irq_unlock(mask);
}
timestamp = TIME_STAMP_DELTA_GET(timestamp);
if (bench_test_end() == 0) {
PRINT_FORMAT(" Average time for lock then unlock "
"is %u tcs = %u nsec",
timestamp / NTESTS,
SYS_CLOCK_HW_CYCLES_TO_NS_AVG(timestamp, NTESTS));
} else {
errorCount++;
PRINT_OVERFLOW_ERROR();
}
return 0;
}

View file

@ -1,86 +0,0 @@
/* nano_int_to_fiber.c - measure switching time from ISR back to fiber */
/*
* Copyright (c) 2012-2014 Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
/*
* DESCRIPTION
* This file contains test that measures the switching time from the
* interrupt handler back to the executing fiber that got interrupted.
*/
#include "timestamp.h"
#include "utils.h"
#include <arch/cpu.h>
#include <irq_offload.h>
#ifndef STACKSIZE
#define STACKSIZE 512
#endif
/* stack used by the fiber that generates the interrupt */
static char __stack fiberStack[STACKSIZE];
static volatile int flagVar;
static uint32_t timestamp;
/**
*
* @brief Test ISR used to measure best case interrupt latency
*
* The interrupt handler gets the second timestamp.
*
* @return N/A
*/
static void latencyTestIsr(void *unused)
{
ARG_UNUSED(unused);
flagVar = 1;
timestamp = TIME_STAMP_DELTA_GET(0);
}
/**
*
* @brief Interrupt preparation fiber
*
* Fiber makes all the test preparations: registers the interrupt handler,
* gets the first timestamp and invokes the software interrupt.
*
* @return N/A
*/
static void fiberInt(void)
{
flagVar = 0;
irq_offload(latencyTestIsr, NULL);
if (flagVar != 1) {
PRINT_FORMAT(" Flag variable has not changed. FAILED");
} else {
timestamp = TIME_STAMP_DELTA_GET(timestamp);
}
}
/**
*
* @brief The test main function
*
* @return 0 on success
*/
int nanoIntToFiber(void)
{
PRINT_FORMAT(" 2- Measure time to switch from ISR back to interrupted"
" fiber");
TICK_SYNCH();
task_fiber_start(&fiberStack[0], STACKSIZE,
(nano_fiber_entry_t) fiberInt, 0, 0, 6, 0);
if (flagVar == 1) {
PRINT_FORMAT(" switching time is %u tcs = %u nsec",
timestamp, SYS_CLOCK_HW_CYCLES_TO_NS(timestamp));
}
return 0;
}

View file

@ -1,110 +0,0 @@
/* nano_int_to_fiber_sem.c - measure switching time from ISR to diff fiber */
/*
* Copyright (c) 2012-2014 Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
/*
* DESCRIPTION
* This file contains a test which measure switching time from interrupt
* handler execution to executing a different fiber than the one which got
* interrupted.
* The test starts a higher priority fiber (fiberWaiter) which blocks on a
* semaphore thus can't run. Then a lower priority fiber (fiberInt) is started
* which sets up an interrupt handler and invokes the software interrupt. The
* interrupt handler releases the semaphore which enabled the high priority
* fiberWaiter to run and exit. The high priority fiber acquire the sema and
* read the time. The time delta is measured from the time
* semaphore is released in interrupt handler to the time fiberWaiter
* starts to executing.
*/
#include "timestamp.h"
#include "utils.h"
#include <arch/cpu.h>
#include <irq_offload.h>
#ifndef STACKSIZE
#define STACKSIZE 512
#endif
/* stack used by the fibers */
static char __stack waiterStack[STACKSIZE];
static char __stack intStack[STACKSIZE];
/* semaphore taken by waiting fiber ad released by the interrupt handler */
static struct nano_sem testSema;
static uint32_t timestamp;
/**
*
* @brief Test ISR used to measure best case interrupt latency
*
* The interrupt handler gets the second timestamp.
*
* @return N/A
*/
static void latencyTestIsr(void *unused)
{
ARG_UNUSED(unused);
nano_isr_sem_give(&testSema);
timestamp = TIME_STAMP_DELTA_GET(0);
}
/**
*
* @brief Interrupt preparation fiber
*
* Fiber makes all the test preparations: registers the interrupt handler,
* gets the first timestamp and invokes the software interrupt.
*
* @return N/A
*/
static void fiberInt(void)
{
irq_offload(latencyTestIsr, NULL);
fiber_yield();
}
/**
*
* @brief Check the time when it gets executed after the semaphore
*
* Fiber starts, waits on semaphore. When the interrupt handler releases
* the semaphore, fiber measures the time.
*
* @return N/A
*/
static void fiberWaiter(void)
{
nano_fiber_sem_take(&testSema, TICKS_UNLIMITED);
timestamp = TIME_STAMP_DELTA_GET(timestamp);
}
/**
*
* @brief The test main function
*
* @return 0 on success
*/
int nanoIntToFiberSem(void)
{
PRINT_FORMAT(" 3- Measure time from ISR to executing a different fiber"
" (rescheduled)");
nano_sem_init(&testSema);
TICK_SYNCH();
task_fiber_start(&waiterStack[0], STACKSIZE,
(nano_fiber_entry_t) fiberWaiter, 0, 0, 5, 0);
task_fiber_start(&intStack[0], STACKSIZE,
(nano_fiber_entry_t) fiberInt, 0, 0, 6, 0);
PRINT_FORMAT(" switching time is %u tcs = %u nsec",
timestamp, SYS_CLOCK_HW_CYCLES_TO_NS(timestamp));
return 0;
}

View file

@ -1,108 +0,0 @@
/* timestamp.h - macroses for measuring time in benchmarking tests */
/*
* Copyright (c) 2012-2015 Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
/*
* DESCRIPTION
* This file contains the macroses for taking and converting time for
* benchmarking tests.
*/
#ifndef _TIMESTAMP_H_
#define _TIMESTAMP_H_
#include <zephyr.h>
#include <limits.h>
#if defined(__GNUC__)
#include <test_asm_inline_gcc.h>
#else
#include <test_asm_inline_other.h>
#endif
typedef int64_t TICK_TYPE;
#define TICK_SYNCH() task_sleep(1)
#define TICK_GET(x) ((TICK_TYPE) sys_tick_delta(x))
#define OS_GET_TIME() sys_cycle_get_32()
/* time necessary to read the time */
extern uint32_t tm_off;
static inline uint32_t TIME_STAMP_DELTA_GET(uint32_t ts)
{
uint32_t t;
/* serialize so OS_GET_TIME() is not reordered */
timestamp_serialize();
t = OS_GET_TIME();
uint32_t res = (t >= ts) ? (t - ts) : (ULONG_MAX - ts + t);
if (ts > 0) {
res -= tm_off;
}
return res;
}
/*
* Routine initializes the benchmark timing measurement
* The function sets up the global variable tm_off
*/
static inline void bench_test_init(void)
{
uint32_t t = OS_GET_TIME();
tm_off = OS_GET_TIME() - t;
}
/* number of ticks before timer overflows */
#define BENCH_MAX_TICKS (sys_clock_ticks_per_sec - 1)
/* tickstamp used for timer counter overflow check */
static TICK_TYPE tCheck;
/*
* Routines are invoked before and after the benchmark and check
* if penchmarking code took less time than necessary for the
* high precision timer register overflow.
* Functions modify the tCheck global variable.
*/
static inline void bench_test_start(void)
{
tCheck = 0;
/* before reading time we synchronize to the start of the timer tick */
TICK_SYNCH();
tCheck = TICK_GET(&tCheck);
}
/* returns 0 if the number of ticks is valid and -1 if not */
static inline int bench_test_end(void)
{
tCheck = TICK_GET(&tCheck);
if (tCheck > BENCH_MAX_TICKS) {
return -1;
}
return 0;
}
/*
* Returns -1 if number of ticks cause high precision timer counter
* overflow and 0 otherwise
* Called after bench_test_end to see if we still can use timing
* results or is it completely invalid
*/
static inline int high_timer_overflow(void)
{
if (tCheck >= (UINT_MAX / sys_clock_hw_cycles_per_tick)) {
return -1;
}
return 0;
}
#endif /* _TIMESTAMP_H_ */