tests/bench_xtimer: initial import
This commit is contained in:
parent
26a1348a9a
commit
d89debd183
76
tests/bench_xtimer/Makefile
Normal file
76
tests/bench_xtimer/Makefile
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
include ../Makefile.tests_common
|
||||||
|
|
||||||
|
USEMODULE += xtimer
|
||||||
|
|
||||||
|
# this test uses 1000 timers by default. for boards that boards don't have
|
||||||
|
# enough memory, reduce that to 100 or 20, unless NUMOF_TIMERS has been overridden.
|
||||||
|
LOW_MEMORY_BOARDS += \
|
||||||
|
airfy-beacon \
|
||||||
|
arduino-mega2560 \
|
||||||
|
b-l072z-lrwan1 \
|
||||||
|
blackpill \
|
||||||
|
blackpill-128kib \
|
||||||
|
bluepill \
|
||||||
|
bluepill-128kib \
|
||||||
|
calliope-mini \
|
||||||
|
cc1352-launchpad \
|
||||||
|
cc2650-launchpad \
|
||||||
|
cc2650stk \
|
||||||
|
chronos \
|
||||||
|
hifive1 \
|
||||||
|
hifive1b \
|
||||||
|
i-nucleo-lrwan1 \
|
||||||
|
lsn50 \
|
||||||
|
maple-mini \
|
||||||
|
microbit \
|
||||||
|
msb-430 \
|
||||||
|
msb-430h \
|
||||||
|
nrf51dongle \
|
||||||
|
nrf6310 \
|
||||||
|
nucleo-f030r8 \
|
||||||
|
nucleo-f042k6 \
|
||||||
|
nucleo-f070rb \
|
||||||
|
nucleo-f072rb \
|
||||||
|
nucleo-f103rb \
|
||||||
|
nucleo-f303k8 \
|
||||||
|
nucleo-f334r8 \
|
||||||
|
nucleo-l031k6 \
|
||||||
|
nucleo-l053r8 \
|
||||||
|
nucleo-l073rz \
|
||||||
|
opencm904 \
|
||||||
|
saml10-xpro \
|
||||||
|
saml11-xpro \
|
||||||
|
spark-core \
|
||||||
|
stm32f0discovery \
|
||||||
|
stm32l0538-disco \
|
||||||
|
telosb \
|
||||||
|
waspmote-pro \
|
||||||
|
wsn430-v1_3b \
|
||||||
|
wsn430-v1_4 \
|
||||||
|
yunjia-nrf51822 \
|
||||||
|
z1 \
|
||||||
|
#
|
||||||
|
|
||||||
|
SUPER_LOW_MEMORY_BOARDS += \
|
||||||
|
arduino-duemilanove \
|
||||||
|
arduino-leonardo \
|
||||||
|
arduino-nano \
|
||||||
|
arduino-uno \
|
||||||
|
atmega328p \
|
||||||
|
nucleo-f031k6 \
|
||||||
|
stm32f030f4-demo \
|
||||||
|
#
|
||||||
|
|
||||||
|
ifneq (, $(filter $(BOARD), $(LOW_MEMORY_BOARDS)))
|
||||||
|
NUMOF_TIMERS ?= 100
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq (, $(filter $(BOARD), $(SUPER_LOW_MEMORY_BOARDS)))
|
||||||
|
NUMOF_TIMERS ?= 20
|
||||||
|
endif
|
||||||
|
|
||||||
|
NUMOF_TIMERS ?= 1000
|
||||||
|
|
||||||
|
CFLAGS += -DNUMOF_TIMERS=$(NUMOF_TIMERS)
|
||||||
|
|
||||||
|
include $(RIOTBASE)/Makefile.include
|
||||||
77
tests/bench_xtimer/README.md
Normal file
77
tests/bench_xtimer/README.md
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
# Introduction
|
||||||
|
|
||||||
|
This test executes some benchmarks for xtimer's set() / remove() / now()
|
||||||
|
operations.
|
||||||
|
|
||||||
|
# Details
|
||||||
|
|
||||||
|
This set of benchmarks measures xtimer's list operation efficiency.
|
||||||
|
Depending on the available memory, the individual benchmarks that are using
|
||||||
|
multiple timers are run with either 1000 (the default), 100 or 20 timers.
|
||||||
|
Each benchmark is repeated REPEAT times (default 1000).
|
||||||
|
As only the operations are benchmarked, it is asserted that no timer ever
|
||||||
|
actually triggers.
|
||||||
|
|
||||||
|
### set() one
|
||||||
|
|
||||||
|
This repeatedly sets one timer in an otherwise emtpy list.
|
||||||
|
All but the first iteration will cause xtimer to implicitly remove the timer
|
||||||
|
first.
|
||||||
|
All iterations will cause the underlying periph timer to be updated.
|
||||||
|
|
||||||
|
### remove() one
|
||||||
|
|
||||||
|
This repeatedly removes one timer from the list. In all but the first iteration,
|
||||||
|
this list will be empty.
|
||||||
|
|
||||||
|
|
||||||
|
### set() + remove() one
|
||||||
|
|
||||||
|
This repeatedly first sets, then removes one timer. The list is empty
|
||||||
|
before and after each iteration.
|
||||||
|
All iterations will cause the underlying periph timer to be updated.
|
||||||
|
|
||||||
|
### set() many increasing targets
|
||||||
|
|
||||||
|
This adds NUMOF timers with increasing target times. Each iteration will add a
|
||||||
|
timer at the end of xtimer's timer list.
|
||||||
|
Only the first iteration will cause the underlying periph timer to be updated.
|
||||||
|
After this test, the list is populated with NUMOF timers.
|
||||||
|
|
||||||
|
### re-set() first
|
||||||
|
|
||||||
|
This repatedly re-sets the first timer in the list (to the same target time).
|
||||||
|
All iterations will cause the underlying periph timer to be updated.
|
||||||
|
|
||||||
|
### re-set() middle
|
||||||
|
|
||||||
|
This repatedly re-sets the timer in the middle of the list (to the same target
|
||||||
|
time).
|
||||||
|
|
||||||
|
### re-set() last
|
||||||
|
|
||||||
|
This repatedly re-sets the last timer in the list (to the same target time).
|
||||||
|
|
||||||
|
### remove() + set() first, middle, last
|
||||||
|
|
||||||
|
Same as the previous three, but does a remove() before set().
|
||||||
|
|
||||||
|
### remove() many decreasing
|
||||||
|
|
||||||
|
This removes all timers from the list, starting with the last.
|
||||||
|
|
||||||
|
### xtimer_now()
|
||||||
|
|
||||||
|
This simply calls xtimer_now() in a loop.
|
||||||
|
|
||||||
|
|
||||||
|
# How to interpret results
|
||||||
|
|
||||||
|
The aim is to measure the time spent in xtimer's list operations.
|
||||||
|
Lower values are better.
|
||||||
|
The first/middle/last tests give an idea of the best case / average case /
|
||||||
|
worst case when running the operation with NUMOF timers.
|
||||||
|
Note that every set() on an already set timer will trigger an implicit remove(),
|
||||||
|
thus the timer list has to be iterated twice.
|
||||||
|
The tests that do a remove() before set() show whether xtimer correctly
|
||||||
|
identifies an unset timer.
|
||||||
289
tests/bench_xtimer/main.c
Normal file
289
tests/bench_xtimer/main.c
Normal file
@ -0,0 +1,289 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 Kaspar Schleiser <kaspar@schleiser.de>
|
||||||
|
*
|
||||||
|
* This file is subject to the terms and conditions of the GNU Lesser
|
||||||
|
* General Public License v2.1. See the file LICENSE in the top level
|
||||||
|
* directory for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ingroup tests
|
||||||
|
* @{
|
||||||
|
*
|
||||||
|
* @file
|
||||||
|
* @brief xtimer set / remove / now benchmark application
|
||||||
|
*
|
||||||
|
* @author Kaspar Schleiser <kaspar@schleiser.de>
|
||||||
|
*
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "msg.h"
|
||||||
|
#include "thread.h"
|
||||||
|
#include "xtimer.h"
|
||||||
|
|
||||||
|
#ifndef NUMOF_TIMERS
|
||||||
|
#define NUMOF_TIMERS (1000U)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef REPEAT
|
||||||
|
#define REPEAT (1000U)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef BASE
|
||||||
|
#define BASE (100000000LU)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef SPREAD
|
||||||
|
#define SPREAD (10000LU)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static xtimer_t _timers[NUMOF_TIMERS];
|
||||||
|
|
||||||
|
/* This variable is set by any timer that actually triggers. As the test is
|
||||||
|
* only testing set/remove/now operations, timers are not supposed to trigger.
|
||||||
|
* Thus, after every test there's an 'assert(!_triggers)'
|
||||||
|
*/
|
||||||
|
static unsigned _triggers;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The test assumes that first, middle and last will always end up in at the
|
||||||
|
* same index within the timer queue. In order to compensate for the time that
|
||||||
|
* previous operations take themselves, the interval is corrected. The
|
||||||
|
* variables "start" and "_base" are used for that.
|
||||||
|
*/
|
||||||
|
uint32_t _base;
|
||||||
|
|
||||||
|
static void _callback(void *arg) {
|
||||||
|
unsigned *triggers = arg;
|
||||||
|
*triggers += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* returns the interval for timer 'n' that has to be set in order to insert it
|
||||||
|
* into position n */
|
||||||
|
static uint32_t _timer_val(unsigned n)
|
||||||
|
{
|
||||||
|
return _base + (SPREAD * n);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set timer 'n' to its intended position 'n' */
|
||||||
|
static void _timer_set(unsigned n)
|
||||||
|
{
|
||||||
|
xtimer_set(&_timers[n], _timer_val(n));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* remove timer 'n' */
|
||||||
|
static void _timer_remove(unsigned n)
|
||||||
|
{
|
||||||
|
xtimer_remove(&_timers[n]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _print_result(const char *desc, unsigned n, uint32_t total)
|
||||||
|
{
|
||||||
|
printf("%30s %8"PRIu32" / %u = %"PRIu32"\n", desc, total, n, total/n);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
puts("xtimer benchmark application.\n");
|
||||||
|
|
||||||
|
unsigned n;
|
||||||
|
uint32_t before, diff, start;
|
||||||
|
|
||||||
|
/* initializing timer structs */
|
||||||
|
for (unsigned int n = 0; n < NUMOF_TIMERS; n++) {
|
||||||
|
_timers[n].callback = _callback;
|
||||||
|
_timers[n].arg = &_triggers;
|
||||||
|
}
|
||||||
|
|
||||||
|
start = xtimer_now_usec();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* test setting one set timer REPEAT times
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
_base = BASE;
|
||||||
|
before = xtimer_now_usec();
|
||||||
|
for (n = 0; n < REPEAT; n++) {
|
||||||
|
_timer_set(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
diff = xtimer_now_usec() - before;
|
||||||
|
|
||||||
|
_print_result("set() one", REPEAT, diff);
|
||||||
|
assert(!_triggers);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* test removing one unset timer REPEAT times
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
before = xtimer_now_usec();
|
||||||
|
for (n = 0; n < REPEAT; n++) {
|
||||||
|
_timer_remove(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
diff = xtimer_now_usec() - before;
|
||||||
|
|
||||||
|
_print_result("remove() one", REPEAT, diff);
|
||||||
|
assert(!_triggers);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* test setting / removing one timer REPEAT times
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
before = xtimer_now_usec();
|
||||||
|
_base = BASE - (before - start);
|
||||||
|
for (n = 0; n < REPEAT; n++) {
|
||||||
|
_timer_set(0);
|
||||||
|
_timer_remove(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
diff = xtimer_now_usec() - before;
|
||||||
|
|
||||||
|
_print_result("set() + remove() one", REPEAT, diff);
|
||||||
|
assert(!_triggers);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* test setting NUMOF_TIMERS timers with increasing targets
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
before = xtimer_now_usec();
|
||||||
|
_base = BASE - (before - start);
|
||||||
|
for (unsigned int n = 0; n < NUMOF_TIMERS; n++) {
|
||||||
|
_timer_set(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
diff = xtimer_now_usec() - before;
|
||||||
|
|
||||||
|
_print_result("set() many increasing target", NUMOF_TIMERS, diff);
|
||||||
|
assert(!_triggers);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* test re-setting first timer REPEAT times
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
before = xtimer_now_usec();
|
||||||
|
_base = BASE - (before - start);
|
||||||
|
for (n = 0; n < REPEAT; n++) {
|
||||||
|
_timer_set(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
diff = xtimer_now_usec() - before;
|
||||||
|
|
||||||
|
_print_result("re-set() first", REPEAT, diff);
|
||||||
|
assert(!_triggers);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* test setting middle timer REPEAT times
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
before = xtimer_now_usec();
|
||||||
|
_base = BASE - (before - start);
|
||||||
|
for (n = 0; n < REPEAT; n++) {
|
||||||
|
_timer_set(NUMOF_TIMERS/2);
|
||||||
|
}
|
||||||
|
|
||||||
|
diff = xtimer_now_usec() - before;
|
||||||
|
|
||||||
|
_print_result("re-set() middle", REPEAT, diff);
|
||||||
|
assert(!_triggers);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* test setting last timer REPEAT times
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
before = xtimer_now_usec();
|
||||||
|
_base = BASE - (before - start);
|
||||||
|
for (n = 0; n < REPEAT; n++) {
|
||||||
|
_timer_set(NUMOF_TIMERS - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
diff = xtimer_now_usec() - before;
|
||||||
|
|
||||||
|
_print_result("re-set() last", REPEAT, diff);
|
||||||
|
assert(!_triggers);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* test removing / setting first timer REPEAT times
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
before = xtimer_now_usec();
|
||||||
|
_base = BASE - (before - start);
|
||||||
|
for (n = 0; n < REPEAT; n++) {
|
||||||
|
_timer_remove(0);
|
||||||
|
_timer_set(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
diff = xtimer_now_usec() - before;
|
||||||
|
|
||||||
|
_print_result("remove() + set() first", REPEAT, diff);
|
||||||
|
assert(!_triggers);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* test removing / setting middle timer REPEAT times
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
before = xtimer_now_usec();
|
||||||
|
_base = BASE - (before - start);
|
||||||
|
for (n = 0; n < REPEAT; n++) {
|
||||||
|
_timer_remove(NUMOF_TIMERS/2);
|
||||||
|
_timer_set(NUMOF_TIMERS/2);
|
||||||
|
}
|
||||||
|
|
||||||
|
diff = xtimer_now_usec() - before;
|
||||||
|
|
||||||
|
_print_result("remove() + set() middle", REPEAT, diff);
|
||||||
|
assert(!_triggers);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* test removing / setting last timer REPEAT times
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
before = xtimer_now_usec();
|
||||||
|
_base = BASE - (before - start);
|
||||||
|
for (n = 0; n < REPEAT; n++) {
|
||||||
|
_timer_remove(NUMOF_TIMERS - 1);
|
||||||
|
_timer_set(NUMOF_TIMERS - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
diff = xtimer_now_usec() - before;
|
||||||
|
|
||||||
|
_print_result("remove() + set() last", REPEAT, diff);
|
||||||
|
assert(!_triggers);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* test removing NUMOF_TIMERS timers (latest first)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
before = xtimer_now_usec();
|
||||||
|
for (n = 0; n < NUMOF_TIMERS; n++) {
|
||||||
|
_timer_remove(NUMOF_TIMERS - n - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
diff = xtimer_now_usec() - before;
|
||||||
|
|
||||||
|
_print_result("remove() many decreasing", NUMOF_TIMERS, diff);
|
||||||
|
assert(!_triggers);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* test xtimer_now()
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
before = xtimer_now_usec();
|
||||||
|
n = REPEAT;
|
||||||
|
while (n--) {
|
||||||
|
xtimer_now_usec();
|
||||||
|
}
|
||||||
|
|
||||||
|
diff = xtimer_now_usec() - before;
|
||||||
|
|
||||||
|
_print_result("xtimer_now()", REPEAT, diff);
|
||||||
|
assert(!_triggers);
|
||||||
|
|
||||||
|
puts("done.");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
22
tests/bench_xtimer/tests/01-run.py
Executable file
22
tests/bench_xtimer/tests/01-run.py
Executable file
@ -0,0 +1,22 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
# Copyright (C) 2019 Freie Universität Berlin
|
||||||
|
#
|
||||||
|
# This file is subject to the terms and conditions of the GNU Lesser
|
||||||
|
# General Public License v2.1. See the file LICENSE in the top level
|
||||||
|
# directory for more details.
|
||||||
|
|
||||||
|
import sys
|
||||||
|
from testrunner import run
|
||||||
|
|
||||||
|
|
||||||
|
def testfunc(child):
|
||||||
|
child.expect_exact("xtimer benchmark application.\r\n")
|
||||||
|
for i in range(12):
|
||||||
|
child.expect(r"\s+[\w() _\+]+\s+\d+ / \d+ = \d+\r\n")
|
||||||
|
|
||||||
|
child.expect_exact("done.\r\n")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(run(testfunc))
|
||||||
Loading…
x
Reference in New Issue
Block a user