Deterministic simulation in linux user-space

Hi all!

I’m working on quite a large embedded project using FreeRTOS. Somewhere around 150kloc and ~100 tasks. We are looking into setting up a “Software in the Loop” test framework for integration and regression tests. The obvious approach is to port FreeRTOS to linux and forward the micro controller specific calls to virtual devices.

I saw there is a POSIX port of FreeRTOS, however, we have a few test cases where we need sub-tick-accurate simulation of peripherals, and we have other cases where tasks strictly depend on each other’s priorities. I don’t think the POSIX port is sufficiently deterministic for what we need.

This lead me to wondering: Has anyone written a port that runs FreeRTOS purely in userspace? I.e. no pthreads, no signals for simulating tick interrupts, but an actual x86 port?

For that matter, is anyone else interested in such a port?

The problem will be that “user-space” code can’t really simulate the interrupts. What you would need is something more like QEMU to fully emulate your machine and the I/O + Interrupt system around it.

I’ve been thinking about this, and I think I have a pretty good solution.

On a real-world micro controller, xTaskIncrementTick is normally called periodically by a timer interrupt. The timer interrupt’s frequency is either directly derived from the system clock, or if it’s a separate crystal it’ll at least be some multiple of the system clock. This means the number of instruction cycles executed per tick is a fixed number.

The code-under-test could be instrumented with an “instruction callback” function. The idea is you insert calls to this function at periodic intervals. The callback can then essentially be seen as the “CPU clock”, because on average there will be X number of callbacks per Y instructions. From this you can then derive a clock frequency, and call vPortTickISR() after making the appropriate number of divisions.

Such a simulation would be 100% deterministic which I think is very desirable for building tests on top of.

Yes, you could do that, but in my opinion it isn’t a good test of robustness. In particular, you have just made certain that your interrupts are always at chosen spots in your code, while in reality, they can occur at almost any arbitrary location (limited just by critical sections).

If you are only trying to model gross timing, and not looking to try to find race conditions, then that might be good enough.

I think for our purposes at least, it would be sufficient. We’re mostly looking to test some very specific edge cases and need the determinism to reproduce the errors we’re seeing.

I can imagine, though, that you could instrument the code in a lot of ways that would also make what you’re saying possible to test. E.g. if you’re interested in finding bugs related to being interrupted mid-instruction, I can think of ways to manipulate the generated assembly to split single operations up into multiple operations. Then you can insert the callback in between.

I haven’t really found any project that is doing the stuff I’m thinking about. Everyone suggests to use the POSIX port.

As I mentioned, there have been a number of comments about using QEMU as a platform, which allows running your code on a PC while still getting full debug capabilities as if on your final platform.