benchmarks: convert latency_measure to unified kernel
Change-Id: If92833d699b95f5a7e813d0577f5467b06d3a1b6 Signed-off-by: Anas Nashif <anas.nashif@intel.com>
This commit is contained in:
parent
c096453f34
commit
0505c9c881
25 changed files with 342 additions and 881 deletions
|
@ -1,4 +1,3 @@
|
|||
MDEF_FILE = prj.mdef
|
||||
BOARD ?= qemu_x86
|
||||
|
||||
small_freq_divider_frdm_k64f=y
|
41
tests/benchmarks/latency_measure/README.txt
Normal file
41
tests/benchmarks/latency_measure/README.txt
Normal 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
|
|
@ -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
|
10
tests/benchmarks/latency_measure/src/Makefile
Normal file
10
tests/benchmarks/latency_measure/src/Makefile
Normal 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
|
115
tests/benchmarks/latency_measure/src/coop_ctx_switch.c
Normal file
115
tests/benchmarks/latency_measure/src/coop_ctx_switch.c
Normal 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;
|
||||
}
|
|
@ -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");
|
||||
PRINT_FORMAT(" 1 - Measure time to switch from ISR back to"
|
||||
" 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));
|
||||
}
|
|
@ -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));
|
63
tests/benchmarks/latency_measure/src/main.c
Normal file
63
tests/benchmarks/latency_measure/src/main.c
Normal 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)
|
||||
{
|
||||
}
|
|
@ -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,16 +40,16 @@ static uint32_t timestamp;
|
|||
*
|
||||
* @return 0 on success
|
||||
*/
|
||||
int microSemaLockUnlock(void)
|
||||
int sema_lock_unlock(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
PRINT_FORMAT(" 3- Measure average time to signal a sema then test"
|
||||
PRINT_FORMAT(" 3 - Measure average time to signal a sema then test"
|
||||
" that sema");
|
||||
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",
|
|
@ -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)));
|
||||
}
|
||||
}
|
|
@ -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];
|
||||
|
|
@ -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);
|
||||
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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_ */
|
Loading…
Add table
Add a link
Reference in a new issue