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
|
BOARD ?= qemu_x86
|
||||||
|
|
||||||
small_freq_divider_frdm_k64f=y
|
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
|
# Reduce memory/code footprint
|
||||||
CONFIG_BLUETOOTH=n
|
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) 2012-2014 Wind River Systems, Inc.
|
||||||
|
* Copyright (c) 2017 Intel Corporation.
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* 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
|
* 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"
|
#include "timestamp.h"
|
||||||
|
@ -18,7 +18,7 @@
|
||||||
#include <arch/cpu.h>
|
#include <arch/cpu.h>
|
||||||
#include <irq_offload.h>
|
#include <irq_offload.h>
|
||||||
|
|
||||||
static volatile int flagVar;
|
static volatile int flag_var;
|
||||||
|
|
||||||
static uint32_t timestamp;
|
static uint32_t timestamp;
|
||||||
|
|
||||||
|
@ -30,11 +30,11 @@ static uint32_t timestamp;
|
||||||
*
|
*
|
||||||
* @return N/A
|
* @return N/A
|
||||||
*/
|
*/
|
||||||
static void latencyTestIsr(void *unused)
|
static void latency_test_isr(void *unused)
|
||||||
{
|
{
|
||||||
ARG_UNUSED(unused);
|
ARG_UNUSED(unused);
|
||||||
|
|
||||||
flagVar = 1;
|
flag_var = 1;
|
||||||
timestamp = TIME_STAMP_DELTA_GET(0);
|
timestamp = TIME_STAMP_DELTA_GET(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,11 +47,11 @@ static void latencyTestIsr(void *unused)
|
||||||
*
|
*
|
||||||
* @return N/A
|
* @return N/A
|
||||||
*/
|
*/
|
||||||
static void makeInt(void)
|
static void make_int(void)
|
||||||
{
|
{
|
||||||
flagVar = 0;
|
flag_var = 0;
|
||||||
irq_offload(latencyTestIsr, NULL);
|
irq_offload(latency_test_isr, NULL);
|
||||||
if (flagVar != 1) {
|
if (flag_var != 1) {
|
||||||
PRINT_FORMAT(" Flag variable has not changed. FAILED\n");
|
PRINT_FORMAT(" Flag variable has not changed. FAILED\n");
|
||||||
} else {
|
} else {
|
||||||
timestamp = TIME_STAMP_DELTA_GET(timestamp);
|
timestamp = TIME_STAMP_DELTA_GET(timestamp);
|
||||||
|
@ -64,13 +64,13 @@ static void makeInt(void)
|
||||||
*
|
*
|
||||||
* @return 0 on success
|
* @return 0 on success
|
||||||
*/
|
*/
|
||||||
int microIntToTask(void)
|
int int_to_thread(void)
|
||||||
{
|
{
|
||||||
PRINT_FORMAT(" 1- Measure time to switch from ISR back to"
|
PRINT_FORMAT(" 1 - Measure time to switch from ISR back to"
|
||||||
" interrupted task");
|
" interrupted thread");
|
||||||
TICK_SYNCH();
|
TICK_SYNCH();
|
||||||
makeInt();
|
make_int();
|
||||||
if (flagVar == 1) {
|
if (flag_var == 1) {
|
||||||
PRINT_FORMAT(" switching time is %u tcs = %u nsec",
|
PRINT_FORMAT(" switching time is %u tcs = %u nsec",
|
||||||
timestamp, SYS_CLOCK_HW_CYCLES_TO_NS(timestamp));
|
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.
|
* Copyright (c) 2012-2014 Wind River Systems, Inc.
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* 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
|
* This file contains test that measures time to switch from an interrupt
|
||||||
* handler to executing a task after rescheduling. In other words, execution
|
* handler to executing a thread after rescheduling. In other words, execution
|
||||||
* after interrupt handler resume in a different task than the one which got
|
* after interrupt handler resume in a different thread than the one which got
|
||||||
* interrupted.
|
* interrupted.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -24,6 +23,10 @@
|
||||||
|
|
||||||
static uint32_t timestamp;
|
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
|
* @brief Test ISR used to measure best case interrupt latency
|
||||||
|
@ -32,44 +35,49 @@ static uint32_t timestamp;
|
||||||
*
|
*
|
||||||
* @return N/A
|
* @return N/A
|
||||||
*/
|
*/
|
||||||
static void latencyTestIsr(void *unused)
|
static void latency_test_isr(void *unused)
|
||||||
{
|
{
|
||||||
ARG_UNUSED(unused);
|
ARG_UNUSED(unused);
|
||||||
|
|
||||||
isr_event_send(EVENT0);
|
k_alert_send(&EVENT0);
|
||||||
timestamp = TIME_STAMP_DELTA_GET(0);
|
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
|
* Lower priority thread that, when it starts, it waits for a semaphore. When
|
||||||
* it, released by the main task, sets up the interrupt handler and generates
|
* it gets it, released by the main thread, sets up the interrupt handler and
|
||||||
* the software interrupt
|
* generates the software interrupt
|
||||||
*
|
*
|
||||||
* @return 0 on success
|
* @return 0 on success
|
||||||
*/
|
*/
|
||||||
void microInt(void)
|
void int_thread(void)
|
||||||
{
|
{
|
||||||
task_sem_take(INTSEMA, TICKS_UNLIMITED);
|
k_sem_take(&INTSEMA, K_FOREVER);
|
||||||
irq_offload(latencyTestIsr, NULL);
|
irq_offload(latency_test_isr, NULL);
|
||||||
task_suspend(task_id_get());
|
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
|
* @brief The test main function
|
||||||
*
|
*
|
||||||
* @return 0 on success
|
* @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)");
|
" (rescheduled)");
|
||||||
TICK_SYNCH();
|
TICK_SYNCH();
|
||||||
task_sem_give(INTSEMA);
|
k_sem_give(&INTSEMA);
|
||||||
task_event_recv(EVENT0, TICKS_UNLIMITED);
|
k_alert_recv(&EVENT0, K_FOREVER);
|
||||||
timestamp = TIME_STAMP_DELTA_GET(timestamp);
|
timestamp = TIME_STAMP_DELTA_GET(timestamp);
|
||||||
PRINT_FORMAT(" switch time is %u tcs = %u nsec",
|
PRINT_FORMAT(" switch time is %u tcs = %u nsec",
|
||||||
timestamp, SYS_CLOCK_HW_CYCLES_TO_NS(timestamp));
|
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.
|
* 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
|
* 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.
|
* mutex being tested.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -28,6 +28,9 @@
|
||||||
|
|
||||||
static uint32_t timestamp;
|
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
|
* @brief The function tests semaphore lock/unlock time
|
||||||
|
@ -37,16 +40,16 @@ static uint32_t timestamp;
|
||||||
*
|
*
|
||||||
* @return 0 on success
|
* @return 0 on success
|
||||||
*/
|
*/
|
||||||
int microSemaLockUnlock(void)
|
int sema_lock_unlock(void)
|
||||||
{
|
{
|
||||||
int i;
|
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");
|
" that sema");
|
||||||
bench_test_start();
|
bench_test_start();
|
||||||
timestamp = TIME_STAMP_DELTA_GET(0);
|
timestamp = TIME_STAMP_DELTA_GET(0);
|
||||||
for (i = 0; i < N_TEST_SEMA; i++) {
|
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);
|
timestamp = TIME_STAMP_DELTA_GET(timestamp);
|
||||||
if (bench_test_end() == 0) {
|
if (bench_test_end() == 0) {
|
||||||
|
@ -56,14 +59,14 @@ int microSemaLockUnlock(void)
|
||||||
SYS_CLOCK_HW_CYCLES_TO_NS_AVG(timestamp,
|
SYS_CLOCK_HW_CYCLES_TO_NS_AVG(timestamp,
|
||||||
N_TEST_SEMA));
|
N_TEST_SEMA));
|
||||||
} else {
|
} else {
|
||||||
errorCount++;
|
error_count++;
|
||||||
PRINT_OVERFLOW_ERROR();
|
PRINT_OVERFLOW_ERROR();
|
||||||
}
|
}
|
||||||
|
|
||||||
bench_test_start();
|
bench_test_start();
|
||||||
timestamp = TIME_STAMP_DELTA_GET(0);
|
timestamp = TIME_STAMP_DELTA_GET(0);
|
||||||
for (i = 0; i < N_TEST_SEMA; i++) {
|
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);
|
timestamp = TIME_STAMP_DELTA_GET(timestamp);
|
||||||
if (bench_test_end() == 0) {
|
if (bench_test_end() == 0) {
|
||||||
|
@ -73,7 +76,7 @@ int microSemaLockUnlock(void)
|
||||||
SYS_CLOCK_HW_CYCLES_TO_NS_AVG(timestamp,
|
SYS_CLOCK_HW_CYCLES_TO_NS_AVG(timestamp,
|
||||||
N_TEST_SEMA));
|
N_TEST_SEMA));
|
||||||
} else {
|
} else {
|
||||||
errorCount++;
|
error_count++;
|
||||||
PRINT_OVERFLOW_ERROR();
|
PRINT_OVERFLOW_ERROR();
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -88,7 +91,7 @@ int microSemaLockUnlock(void)
|
||||||
*
|
*
|
||||||
* @return 0 on success
|
* @return 0 on success
|
||||||
*/
|
*/
|
||||||
int microMutexLockUnlock(void)
|
int mutex_lock_unlock(void)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
@ -96,7 +99,7 @@ int microMutexLockUnlock(void)
|
||||||
" unlock that mutex");
|
" unlock that mutex");
|
||||||
timestamp = TIME_STAMP_DELTA_GET(0);
|
timestamp = TIME_STAMP_DELTA_GET(0);
|
||||||
for (i = 0; i < N_TEST_MUTEX; i++) {
|
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);
|
timestamp = TIME_STAMP_DELTA_GET(timestamp);
|
||||||
PRINT_FORMAT(" Average time to lock the mutex %u tcs = %u nsec",
|
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));
|
SYS_CLOCK_HW_CYCLES_TO_NS_AVG(timestamp, N_TEST_MUTEX));
|
||||||
timestamp = TIME_STAMP_DELTA_GET(0);
|
timestamp = TIME_STAMP_DELTA_GET(0);
|
||||||
for (i = 0; i < N_TEST_MUTEX; i++) {
|
for (i = 0; i < N_TEST_MUTEX; i++) {
|
||||||
task_mutex_unlock(TEST_MUTEX);
|
k_mutex_unlock(&TEST_MUTEX);
|
||||||
}
|
}
|
||||||
timestamp = TIME_STAMP_DELTA_GET(timestamp);
|
timestamp = TIME_STAMP_DELTA_GET(timestamp);
|
||||||
PRINT_FORMAT(" Average time to unlock the mutex %u tcs = %u nsec",
|
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.
|
* Copyright (c) 2012-2014 Wind River Systems, Inc.
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* DESCRIPTION
|
* @file
|
||||||
* This file contains the benchmark that measure the average time it takes to
|
* 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.
|
* context switch.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <zephyr.h>
|
#include <zephyr.h>
|
||||||
#include "timestamp.h" /* reading time */
|
#include <timestamp.h> /* reading time */
|
||||||
#include "utils.h" /* PRINT () and other macros */
|
#include "utils.h" /* PRINT () and other macros */
|
||||||
|
|
||||||
/* <stdlib.h> is not supported */
|
/* <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 */
|
/* context switch enough time so our measurement is precise */
|
||||||
#define NB_OF_YIELD 1000
|
#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
|
* @brief Helper thread for measuring thread switeh latency using yield
|
||||||
*
|
|
||||||
* This task is define in .mdef as SEMYIELDTSK
|
|
||||||
*
|
*
|
||||||
* @return N/A
|
* @return N/A
|
||||||
*/
|
*/
|
||||||
void yieldingTask(void)
|
void yielding_thread(void *arg1, void *arg2, void *arg3)
|
||||||
{
|
{
|
||||||
while (helper_task_iterations < NB_OF_YIELD) {
|
while (helper_thread_iterations < NB_OF_YIELD) {
|
||||||
task_yield();
|
k_yield();
|
||||||
helper_task_iterations++;
|
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
|
* @return N/A
|
||||||
*/
|
*/
|
||||||
void microTaskSwitchYield(void)
|
void thread_switch_yield(void)
|
||||||
{
|
{
|
||||||
uint32_t iterations = 0;
|
uint32_t iterations = 0;
|
||||||
int32_t delta;
|
int32_t delta;
|
||||||
uint32_t timestamp;
|
uint32_t timestamp;
|
||||||
|
|
||||||
PRINT_FORMAT(" 5- Measure average context switch time between tasks"
|
PRINT_FORMAT(" 5 - Measure average context switch time between threads"
|
||||||
" using (task_yield)");
|
" using (k_yield)");
|
||||||
|
|
||||||
bench_test_start();
|
bench_test_start();
|
||||||
|
|
||||||
/* launch helper task of the same priority than this routine */
|
/* launch helper thread of the same priority than this routine */
|
||||||
task_start(YIELDTASK);
|
k_thread_spawn(y_stack_area, Y_STACK_SIZE, yielding_thread, NULL, NULL, NULL,
|
||||||
|
Y_PRIORITY, 0, K_NO_WAIT);
|
||||||
|
|
||||||
/* get initial timestamp */
|
/* get initial timestamp */
|
||||||
timestamp = TIME_STAMP_DELTA_GET(0);
|
timestamp = TIME_STAMP_DELTA_GET(0);
|
||||||
|
|
||||||
/* loop until either helper or this routine reaches number of yields */
|
/* loop until either helper or this routine reaches number of yields */
|
||||||
while (iterations < NB_OF_YIELD &&
|
while (iterations < NB_OF_YIELD &&
|
||||||
helper_task_iterations < NB_OF_YIELD) {
|
helper_thread_iterations < NB_OF_YIELD) {
|
||||||
task_yield();
|
k_yield();
|
||||||
iterations++;
|
iterations++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,25 +86,25 @@ void microTaskSwitchYield(void)
|
||||||
* iteration away from reaching NB_OF_YIELD if execute was switching
|
* iteration away from reaching NB_OF_YIELD if execute was switching
|
||||||
* back and forth.
|
* back and forth.
|
||||||
*/
|
*/
|
||||||
delta = iterations - helper_task_iterations;
|
delta = iterations - helper_thread_iterations;
|
||||||
if (bench_test_end() < 0) {
|
if (bench_test_end() < 0) {
|
||||||
errorCount++;
|
error_count++;
|
||||||
PRINT_OVERFLOW_ERROR();
|
PRINT_OVERFLOW_ERROR();
|
||||||
} else if (abs(delta) > 1) {
|
} else if (abs(delta) > 1) {
|
||||||
/* expecting even alternating context switch, seems one routine
|
/* expecting even alternating context switch, seems one routine
|
||||||
* called yield without the other having chance to execute
|
* called yield without the other having chance to execute
|
||||||
*/
|
*/
|
||||||
errorCount++;
|
error_count++;
|
||||||
PRINT_FORMAT(" Error, iteration:%u, helper iteration:%u",
|
PRINT_FORMAT(" Error, iteration:%u, helper iteration:%u",
|
||||||
iterations, helper_task_iterations);
|
iterations, helper_thread_iterations);
|
||||||
} else {
|
} else {
|
||||||
/* task_yield is called (iterations + helper_task_iterations)
|
/* thread_yield is called (iterations + helper_thread_iterations)
|
||||||
* times in total.
|
* times in total.
|
||||||
*/
|
*/
|
||||||
PRINT_FORMAT(" Average task context switch using "
|
PRINT_FORMAT(" Average thread context switch using "
|
||||||
"yield %u tcs = %u nsec",
|
"yield %u tcs = %u nsec",
|
||||||
timestamp / (iterations + helper_task_iterations),
|
timestamp / (iterations + helper_thread_iterations),
|
||||||
SYS_CLOCK_HW_CYCLES_TO_NS_AVG(timestamp,
|
SYS_CLOCK_HW_CYCLES_TO_NS_AVG(timestamp,
|
||||||
(iterations + helper_task_iterations)));
|
(iterations + helper_thread_iterations)));
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -17,5 +17,5 @@
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
/* scratchpad for the string used to print on console */
|
/* 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 <misc/printk.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "timestamp.h"
|
#include "timestamp.h"
|
||||||
extern char tmpString[];
|
extern char tmp_string[];
|
||||||
extern int errorCount;
|
extern int error_count;
|
||||||
|
|
||||||
#define TMP_STRING_SIZE 100
|
#define TMP_STRING_SIZE 100
|
||||||
|
|
||||||
|
@ -29,8 +29,8 @@ extern int errorCount;
|
||||||
|
|
||||||
#define PRINT_FORMAT(fmt, ...) \
|
#define PRINT_FORMAT(fmt, ...) \
|
||||||
do { \
|
do { \
|
||||||
snprintf(tmpString, TMP_STRING_SIZE, fmt, ##__VA_ARGS__); \
|
snprintf(tmp_string, TMP_STRING_SIZE, fmt, ##__VA_ARGS__); \
|
||||||
PRINTF("|%-77s|\n", tmpString); \
|
PRINTF("|%-77s|\n", tmp_string); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -39,7 +39,7 @@ extern int errorCount;
|
||||||
*
|
*
|
||||||
* @return N/A
|
* @return N/A
|
||||||
*/
|
*/
|
||||||
static inline void printDashLine(void)
|
static inline void print_dash_line(void)
|
||||||
{
|
{
|
||||||
PRINTF("|-------------------------------------------------------"
|
PRINTF("|-------------------------------------------------------"
|
||||||
"----------------------|\n");
|
"----------------------|\n");
|
||||||
|
@ -49,23 +49,16 @@ static inline void printDashLine(void)
|
||||||
do { \
|
do { \
|
||||||
PRINTF("| E N D " \
|
PRINTF("| E N D " \
|
||||||
" |\n"); \
|
" |\n"); \
|
||||||
printDashLine(); \
|
print_dash_line(); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define PRINT_NANO_BANNER() \
|
|
||||||
do { \
|
|
||||||
printDashLine(); \
|
|
||||||
PRINTF("| Nanokernel Latency Benchmark " \
|
|
||||||
" |\n"); \
|
|
||||||
printDashLine(); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define PRINT_MICRO_BANNER() \
|
#define PRINT_BANNER() \
|
||||||
do { \
|
do { \
|
||||||
printDashLine(); \
|
print_dash_line(); \
|
||||||
PRINTF("| Microkernel Latency Benchmark " \
|
PRINTF("| Latency Benchmark " \
|
||||||
" |\n"); \
|
" |\n"); \
|
||||||
printDashLine(); \
|
print_dash_line(); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
|
||||||
|
@ -73,7 +66,7 @@ static inline void printDashLine(void)
|
||||||
do { \
|
do { \
|
||||||
PRINT_FORMAT(" tcs = timer clock cycles: 1 tcs is %u nsec", \
|
PRINT_FORMAT(" tcs = timer clock cycles: 1 tcs is %u nsec", \
|
||||||
SYS_CLOCK_HW_CYCLES_TO_NS(1)); \
|
SYS_CLOCK_HW_CYCLES_TO_NS(1)); \
|
||||||
printDashLine(); \
|
print_dash_line(); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define PRINT_OVERFLOW_ERROR() \
|
#define PRINT_OVERFLOW_ERROR() \
|
||||||
|
@ -86,13 +79,6 @@ static inline void printDashLine(void)
|
||||||
void raiseIntFunc(void);
|
void raiseIntFunc(void);
|
||||||
extern void raiseInt(uint8_t id);
|
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 */
|
/* pointer to the ISR */
|
||||||
typedef void (*ptestIsr) (void *unused);
|
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