- Edited
wa3573 I actually stuck with boost for the circular_buffer, even though I had already implemented one, if it's not broken, why fix it?
A good reason would be to avoid the dependency on boost
, especially if that is the only component you are using from the whole library. Looking at the API of boost::circular_buffer
, it should be fairly easy to replicate with std::vector
and an extra index.
wa3573 cut down on CPU load
One place where I think the original TK software is pretty inefficient is in the fact that a new mapping object is created every time the key position exceeds a given threshold. I'd suggest to pre-allocate all the objects and only start calling Trigger()
when they key position exceeds a given threshold, until the key press is completed.
wa3573 Since I used the pthread library to retrofit the TouchKeys source code
How many threads do you have currently?
wa3573 Since I used the pthread library to retrofit the TouchKeys source code, I assume I could just use the Xenomai wraps as is done here
The use of plain or __wrap()
threads really depends on what each thread is doing. What I normally do, as a general rule, is:
- a thread with real-time requirements, and which is real-time-safe, should be created as a Xenomai thread (using __wrap_pthread...
functions)
- a thread that is not real-time safe (e.g.: it accesses Linux drivers, does disk or network or USB I/O) should be created as a regular thread (using pthread_...
functions).
However, I am not 100% positive that this is the best approach in all cases.
Things become more complicated when using synchronization primitives: any Xenomai thread should only use mutexes, condition variables, semaphores, message queues, that are themselves managed by Xenomai (i.e.: created, modified and accessed with the __wrap_
functions). Failing to do so would cause a "mode switch", that is the thread would temporarily turn into a Linux thread, thus losing real-time guarantees. You definitely don't want to do this for threads that have real-time requirements. On the other hand, non-Xenomai threads cannot access synchronization primitives that were created by Xenomai.
There is only one synchronization primitive, that also works as message-passing, that would allow Xenomai threads to communicate with non-Xenomai threads (even across-processes) without causing a mode switch in the Xenomai thread: XDDP (cross-domain datagram protocol). This is what we use e.g.: in the Midi
and AuxTaskNonRT
classes. Check out the Xenomai XDDP examples for some more details.
So, I think (but I didn't benchmark it) that XDDP is the fastest way of communicating between a RT and a non-RT task, where the former is a Xenomai task and the latter is not. However, it make the code less portable, by using this custom protocol.
As an alternative, if there are one real-time and one non-real-time threads that need to share resources, I sometimes use an unorthodox approach: make them both Xenomai threads. You can keep the priority of the non-real-time thread to 0
, and it this thread will switch automatically from primary ("Xenomai RT-safe") and secondary ("Linux") mode whenever needed. I.e.: a thread that does serial I/O but also shares a mutex with the audio thread would switch to primary mode when it tries to get the mutex, and would switch back to secondary mode when doing I/O. This comes with a performance penalty: every time the thread switches mode, it wastes some CPU cycles. I am not sure HOW MANY, I think you lose about 20-40 microseconds for each mode switch.
If you are planning on making all of your threads Xenomai threads, and all of the pthread_
calls Xenomai calls, then you actually ... could avoid that altogether: there are some compiler flags provided by Xenomai that will just turn all of your pthread_
(and some more) calls into the equivalent Xenomai call. See the documentation here (section: Under the hood: the --wrap flag
). The Bela Makefile
currently deliberately removes these linker flags (see the Makefile
source where it assigns DEFAULT_XENOMAI_LDFLAGS
). You will have to re-add them for your build.
To sum up, I would encourage you to implement all you need using the regular pthread_
, then compile and link your application adding the appropriate LDFLAGS
. Try to run it this way and see if it all works fine. If you have one thread that switches mode very often (you can monitor the MSW
column in the threads stats in /proc/xenomai/sched/stat
while the program is running), so much that it becomes a performance issue, then you may want to consider moving that (those) thread(s) to a regular Linux thread (calling __real_pthread_...
), and use XDDP to communicate with it from a RT thread (if needed).
Hope this helps.