Skip to content

Commit

Permalink
tests/xtimer_configuration: Testing parameter
Browse files Browse the repository at this point in the history
  • Loading branch information
Josar committed May 11, 2018
1 parent 290d0f7 commit 80d2173
Show file tree
Hide file tree
Showing 4 changed files with 357 additions and 0 deletions.
18 changes: 18 additions & 0 deletions tests/xtimer_configuration/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
include ../Makefile.tests_common

USEMODULE += xtimer

# Port and pin configuration for probing with oscilloscope
# Port number should be found in port enum e.g in cpu/include/periph_cpu.h
FEATURES_REQUIRED += periph_gpio
CFLAGS += -DSLEEP_PIN=6
CFLAGS += -DSLEEP_PORT=PORT_F

CFLAGS += -DDEBUG_TIMER_PORT=PORTF
CFLAGS += -DDEBUG_TIMER_DDR=DDRF
CFLAGS += -DDEBUG_TIMER_PIN=PORTF4

include $(RIOTBASE)/Makefile.include

test:
./tests/01-run.py
71 changes: 71 additions & 0 deletions tests/xtimer_configuration/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# xtimer_configuration test application

This test tests `_xtimer_tsleep32()` and `xtimer_periodic_wakeup` against the
timings of of the xtimer.
And agains the timings of the external host (PC).

This test can be used to adjust `XTIMER_SHOOT_OVERHEAD`, `XTIMER_OVERHEAD`,
`XTIMER_BACKOFF` and `XTIMER_ISR_BACKOFF`.
This is to ensure that the xtimer interrupt is only as long as neccessary.

## Usage
```
make BOARD=<Board Name> flash test
```

## Find right values

1. Configure parameter in board.h as follow:
`XTIMER_ISR_BACKOFF` has to be twice `XTIMER_OVERHEAD`
```
#define XTIMER_BACKOFF (100)
#define XTIMER_ISR_BACKOFF (100)
#define XTIMER_BACKOFF_OVERHEAD (1)
#define XTIMER_OVERHEAD (50)
#define XTIMER_SHOOT_OVERHEAD (0)
```

run the test.
If the output is as follows
```
xxxx-xx-xx xx:xx:xx,xxx - INFO # 240876 243436 slept for 2560 ticks (20480 us) expected 2560 ticks, diff 27 ticks
Increase value for XTIMER_SHOOT_OVERHEAD or XTIMER_OVERHEAD 27
...
xxxx-xx-xx xx:xx:xx,xxx - INFO # 266798 266845 slept for 47 ticks (376 us) expected 47 ticks, diff 14 ticks
Increase value for XTIMER_BACKOFF_OVERHEAD 14
```

Add the new value for `XTIMER_SHOOT_OVERHEAD` and `XTIMER_BACKOFF_OVERHEAD` to the board.h and set `XTIMER_OVERHEAD` to zero.

```
#define XTIMER_BACKOFF (100)
#define XTIMER_ISR_BACKOFF (100)
#define XTIMER_BACKOFF_OVERHEAD (14)
#define XTIMER_OVERHEAD (0)
#define XTIMER_SHOOT_OVERHEAD (27)
```

2. run test again

Set `XTIMER_OVERHEAD` to new value.

If the output is as follows

```
xxxx-xx-xx xx:xx:xx,xxx - INFO # 240876 243436 slept for 2560 ticks (20480 us) expected 2560 ticks, diff 33 ticks
Increase value for XTIMER_SHOOT_OVERHEAD or XTIMER_OVERHEAD 33
```
Set 33 as value for `XTIMER_OVERHEAD` and `XTIMER_BACKOFF` two times this value.
Also set `XTIMER_ISR_BACKOFF` to `XTIMER_BACKOFF_OVERHEAD`.

```
#define XTIMER_BACKOFF (66)
#define XTIMER_ISR_BACKOFF (14)
#define XTIMER_BACKOFF_OVERHEAD (14)
#define XTIMER_OVERHEAD (33)
#define XTIMER_SHOOT_OVERHEAD (27)
```

3. Run the test again and check if there are values which are far off.

now run `tests/xtimer_usleep_short` and `tests/xtimer_usleep`.
191 changes: 191 additions & 0 deletions tests/xtimer_configuration/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
/*
* Copyright (C) 2017 Inria
* 2017 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.
*/

/**
* @ingroup tests
* @{
*
* @file
* @brief xtimer_usleep test application
*
* @author Francisco Acosta <francisco.acosta@inria.fr>
* @author Martine Lenders <m.lenders@fu-berlin.de>
* @}
*/

#include <inttypes.h>
#include <stdio.h>

#include "xtimer.h"
#include "timex.h"
#include "thread.h"

#include "Board.h"

/*
* To use a pin to probe the sleep times enable the gpio module and define
* respective DSLEEP_PIN and DSLEEP_PORT.
*
* Port number should be found in port enum e.g in cpu/include/periph_cpu.h
*
* FEATURES_REQUIRED += periph_gpio
* CFLAGS += -DSLEEP_PIN=6
* CFLAGS += -DSLEEP_PORT=PORT_F
* */
#if defined(SLEEP_PORT)
#include "board.h"
#include "periph/gpio.h"
#endif

#define RUNS (3U)
#define SLEEP_TIMES_NUMOF (sizeof(sleep_times) / sizeof(sleep_times[0]))

#define CLOCK_CICLE ((1ul) << XTIMER_WIDTH)
static const uint32_t sleep_times[] = {
XTIMER_BACKOFF - 1, /* spin adjust XTIMER_BACKOFF_OVERHEAD*/
XTIMER_BACKOFF + 1, /* no backoff test */
XTIMER_PERIODIC_SPIN, /* for sure no backoff */
CLOCK_CICLE, /* shoot with interrupt adjust*/
1000,
2345,
50000,
100000,
123456,
};

uint32_t start_kept[5 * SLEEP_TIMES_NUMOF];
uint32_t test_times[5 * SLEEP_TIMES_NUMOF];
volatile uint32_t end_times[SLEEP_TIMES_NUMOF];

static char stack[THREAD_STACKSIZE_MAIN];
static void *_thread(void *arg)
{
(void)arg;
uint8_t i = 0;

puts("thread(): waiting going to sleep!");

while (1) {
thread_sleep();
end_times[i++] = _xtimer_now();
}
return NULL;
}

int main(void)
{
uint32_t start_test, testtime;

printf("Running test %u times with %u distinct sleep times\n", RUNS,
(unsigned)SLEEP_TIMES_NUMOF);
puts("Please hit any key and then ENTER to continue");
getchar();
start_test = xtimer_now_usec();

/* Testing Periodic with fixed time
* Periodic wakeup has the fastest return time as the absolute value is set
* as timestamp.
*/
uint32_t periode, periode_ticks;
xtimer_ticks32_t start_periode;

/* Testing normal usage relativ timestamp*/
periode_ticks = 5 * XTIMER_PERIODIC_RELATIVE;
periode = _xtimer_usec_from_ticks(periode_ticks);

start_periode = xtimer_now();
for (unsigned n = 0; n < SLEEP_TIMES_NUMOF; n++) {
start_kept[n] = start_periode.ticks32;
xtimer_periodic_wakeup(&start_periode, periode);
test_times[n] = _xtimer_now();
}

for (unsigned n = 0; n < SLEEP_TIMES_NUMOF; n++) {
uint32_t diff = test_times[n] - start_kept[n];
printf("%" PRIu32 " %" PRIu32 " slept for %" PRIu32 " ticks (%" PRIu32
" us) expected %" PRIu32 " ticks, diff %" PRIu32 " ticks\n",
start_kept[n], test_times[n], diff, _xtimer_usec_from_ticks(diff),
periode_ticks, diff - periode_ticks);
}

/* Testing ticks */
/* will always have some ticks delay as absolute timestamp is calculated
* after calling multiple functions.
* _xtimer_tsleep32
* _xtimer_tsleep
* _xtimer_set64
* _xtimer_set
* */
for (unsigned n = 0; n < SLEEP_TIMES_NUMOF; n++) {
uint32_t start, end, diff;

start = _xtimer_now();
_xtimer_tsleep32(sleep_times[n]);
end = _xtimer_now();

diff = end - start;
printf("%" PRIu32 " %" PRIu32 " slept for %" PRIu32 " ticks (%" PRIu32
" us) expected %" PRIu32 " ticks, diff %" PRIu32 " ticks\n",
start, end, diff, _xtimer_usec_from_ticks(diff),
sleep_times[n], diff - sleep_times[n]);
}

/* Testing XTIMER_ISR_BACKOFF */
/* When only one timer is triggered the delay is smaller as less functions
* are called untill absolute timestamp is calculated then for _xtimer_tsleep32.
* _xtimer_set_wakeup
* _xtimer_set
*/
xtimer_t xtimer[SLEEP_TIMES_NUMOF];
uint32_t start[SLEEP_TIMES_NUMOF];
uint32_t interval[SLEEP_TIMES_NUMOF];

kernel_pid_t pid_main = thread_getpid();

kernel_pid_t pid_1 = thread_create(stack,
sizeof(stack),
THREAD_PRIORITY_MAIN - 1,
THREAD_CREATE_STACKTEST,
_thread,
NULL,
"second_thread");

interval[SLEEP_TIMES_NUMOF - 2] = _xtimer_usec_from_ticks(40000 + 15 + XTIMER_ISR_BACKOFF);
start[SLEEP_TIMES_NUMOF - 2] = _xtimer_now();
xtimer_set_wakeup(&xtimer[SLEEP_TIMES_NUMOF - 2], interval[SLEEP_TIMES_NUMOF - 2], pid_main);

interval[SLEEP_TIMES_NUMOF - 1] = _xtimer_usec_from_ticks(40000 + (XTIMER_ISR_BACKOFF * SLEEP_TIMES_NUMOF * 2) + 15 * SLEEP_TIMES_NUMOF);
start[SLEEP_TIMES_NUMOF - 1] = _xtimer_now();
xtimer_set_wakeup(&xtimer[SLEEP_TIMES_NUMOF - 1], interval[SLEEP_TIMES_NUMOF - 1], pid_main);

for (unsigned n = 0; n < (SLEEP_TIMES_NUMOF - 2); n++) {
interval[n] = _xtimer_usec_from_ticks(40000 + (XTIMER_ISR_BACKOFF * n * 2));
start[n] = _xtimer_now();
xtimer_set_wakeup(&xtimer[n], interval[n], pid_1);
}

thread_sleep();
end_times[SLEEP_TIMES_NUMOF - 2] = _xtimer_now();

thread_sleep();
end_times[SLEEP_TIMES_NUMOF - 1] = _xtimer_now();

for (unsigned n = 0; n < SLEEP_TIMES_NUMOF; n++) {
uint32_t diff = end_times[n] - start[n];
printf("%" PRIu32 " %" PRIu32 " slept for %" PRIu32 " ticks (%" PRIu32
" us) expected %" PRIu32 " ticks, diff %" PRIu32 " ticks\n",
start[n], end_times[n], diff, _xtimer_usec_from_ticks(diff),
_xtimer_ticks_from_usec(interval[n]), diff - _xtimer_ticks_from_usec(interval[n]));
}

testtime = xtimer_now_usec() - start_test;
printf("Test ran for %" PRIu32 " us\n", testtime);

return 0;
}
77 changes: 77 additions & 0 deletions tests/xtimer_configuration/tests/01-run.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# vim:fenc=utf-8

# Copyright (C) 2017 Francisco Acosta <francisco.acosta@inria.fr>
# 2017 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 os
import sys
import time

US_PER_SEC = 1000000
INTERNAL_JITTER = 0.05
EXTERNAL_JITTER = 0.15


class InvalidTimeout(Exception):
pass


def testfunc(child):
child.expect(u"Running test (\\d+) times with (\\d+) distinct sleep times")
RUNS = int(child.match.group(1))
SLEEP_TIMES_NUMOF = int(child.match.group(2))
try:
child.expect_exact(u"Please hit any key and then ENTER to continue")
child.sendline(u"a")
start_test = time.time()
for m in range(RUNS):
for n in range(SLEEP_TIMES_NUMOF):
child.expect(u"(\\d+) (\\d+) slept for (\\d+) ticks.* expected" +
" (\\d+) ticks.* diff (\\d+) ticks")
start = int(child.match.group(1))
end = int(child.match.group(2))
sleep_time = int(child.match.group(3))
exp = int(child.match.group(4))
lower_bound = exp - (exp * EXTERNAL_JITTER)
upper_bound = exp + (exp * EXTERNAL_JITTER)
time.sleep(0.001)

#if end - start < exp:
# raise InvalidTimeout("To big values %d < %d, xtimer fires too early."
# % (sleep_time, exp))
#elif sleep_time - exp > exp*(1.1):
# raise InvalidTimeout("Difference too big %d, reduce XTIMER_OVERHEAD."
# % (sleep_time-exp))
if m == 0 and n == SLEEP_TIMES_NUMOF-1:
print("Increase value for XTIMER_SHOOT_OVERHEAD or "
"XTIMER_OVERHEAD %d" % (sleep_time-exp))
elif m == 1 and n == 0:
print("Increase value for XTIMER_BACKOFF_OVERHEAD %d" % (sleep_time-exp))
elif exp/10 < 0 and not (lower_bound < sleep_time < upper_bound):
raise InvalidTimeout("Invalid timeout %d, expected %d, xtimer " +
"compared to host clock has to much deviation"
% (sleep_time, exp))

testtime = (time.time() - start_test) * US_PER_SEC
child.expect(u"Test ran for (\\d+) us")
exp = int(child.match.group(1))
lower_bound = exp - (exp * EXTERNAL_JITTER)
upper_bound = exp + (exp * EXTERNAL_JITTER)
if not (lower_bound < testtime < upper_bound):
raise InvalidTimeout("Host timer measured %d us (client measured %d us)"
% (testtime, exp))
except InvalidTimeout as e:
print(e)
sys.exit(1)


if __name__ == "__main__":
sys.path.append(os.path.join(os.environ['RIOTBASE'], 'dist/tools/testrunner'))
from testrunner import run
sys.exit(run(testfunc))

0 comments on commit 80d2173

Please sign in to comment.