Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proper Xenomai inter-process communication (IPC) #16

Closed
giuliomoro opened this issue Aug 13, 2016 · 8 comments
Closed

Proper Xenomai inter-process communication (IPC) #16

giuliomoro opened this issue Aug 13, 2016 · 8 comments

Comments

@giuliomoro
Copy link

giuliomoro commented Aug 13, 2016

The issue is that staticMAudioSync->Signal(); (which in turns calls std::condition_variable_any::notify_one ) was causing a mode switch in the audio thread.
We removed the mode switch from the audio thread by moving it to another thread:

    // this avoids Xenomai mode switches in the audio thread ...
    Bela_scheduleAuxiliaryTask(mAudioSyncSignalTask);
}

void SC_BelaDriver::staticMAudioSyncSignal(){
    // ... but mode switches are still happening here, in a lower priority thread.
    // FIXME: this triggers a mode switch in Xenomai.
    staticMAudioSync->Signal();
    rt_task_suspend(rt_task_self());
}

, still this is inelegant, non-deterministic and adds to the CPU load.

The proper way around this is to rewrite common/SC_SyncCondition.h and common/SC_lock.h so that they use Xenomai-specific IPC functions instead of condition_variable_any and std::mutex.
The discussion here shows a possible method using RT_COND, rt_cond_wait, rt_cond_signal, RT_MUTEX, rt_mutex_acquire, rt_mutex_release

@sensestage
Copy link

ok - this is pretty lowlevel stuff.
In principle it should of course be possible to do it; we'll have to look into that together then, I guess.

@sensestage
Copy link

Does it also cause problems with boost::sync::semaphore(0)?
It seems that that is where the quit message fails.
(see issue #9).

@giuliomoro
Copy link
Author

not sure. I don't see why it should.

@giuliomoro
Copy link
Author

It may be related to having heavy CPU load in the audio thread?

@sensestage
Copy link

No, the quit message sometimes even fails when there are no synths running on the server.

@sensestage
Copy link

going into detail in issue #9

@giuliomoro
Copy link
Author

giuliomoro commented Oct 8, 2016

I don't think this inherently causes any problems with boost::sync::semaphore(0).

The only problem I could see is that the last call to

staticMAudioSync->Signal();

(which originally was mAudioSync.Signal())

does not get executed because the auxiliary thread it runs in is terminated before it gets executed after the last call to SC_BelaDriver::BelaAudioCallback.

Thinking of how to reduce CPU usage for this operation, the suggestion above is not going to work because using xenomai's condition variables forces the thread to switch to primary mode, and then it would switch back to secondary mode once resumed, so:
using Xenomai's condition variables would not remove mode switches, would only move them to another thread, with no advantage for us. Similar results would be obtained using Xenomai's semaphores or queues.

The only path provided by Xenomai for communication between real-time and non-real-time threads seems to be "pipes", which uses a pseudo-device file descriptor at the non-real-time end. http://www.xenomai.org/documentation/trunk/html/api/group__pipe.html
But I have the impression that this would cause more overhead than the current implementation.

Here, for instance, we used Xenomai's pipes https://github.com/BelaPlatform/Bela/blob/2b9b0bf04fd07b8ada325fd27da7a6c1685a60b4/core/Midi.cpp

@giuliomoro
Copy link
Author

Back to the point, what mAudioSync->Signal(); does is waking up a low-priority thread, which does (in server/scsynth/SC_CoreAudio.cpp):

// send /tr messages
 trigfifo->Perform();
// send node reply messages
nodereplyfifo->Perform();
// send node status messages
nodeendfifo->Perform();
// free GraphDefs
deletegraphfifo->Perform();
// perform message
 mFromEngine.Perform();

Now, when the CPU load is low, there are occasional "dropouts", as in: the number of times this thread is actually woken up is smaller than the number of times it is signalled. This makes sense, if you think that this is a low-prio thread and should not necessarily have to wake up every time the audio callback is terminated (as we are requesting it to do by Signal()ling it at the end of each audio callback!). This is probably ok for large block sizes.
It is not clear whether the thread does not wake up because it is already awake, still busy with its tasks, or whether it is not woken up at all because Linux decides to go and do something else instead.
It seems that when CPU usage increases to about 70% for the audio thread, at least 30% of the wake ups are lost

Either way - without even looking at the internal code of all the above tasks - I think it is safe to assume that - by design - they a) are all interruptible and thread-safe, and b) they can run a reasonably small number of times per seconds, even smaller than Fs/blocksize per second (which - again - is the number of times the thread is resumed). (I say I assume that because otherwise all the SC programs would always be one step away from collapsing).

This said, in principle we should be able to simply set this task to sleep for, e.g.: 1ms so that it wakes itself up without need for synchronization with the audio callback.
BUT when I proposed a similar solution in 50e26c5, we were often getting "synthdef not found" errors, as if the synthdefs were not loaded by the server, which is why we ended up in the current situation. I guess it makes sense give it another try.

giuliomoro added a commit that referenced this issue Oct 23, 2020
giuliomoro added a commit that referenced this issue Nov 25, 2020
giuliomoro added a commit that referenced this issue Dec 1, 2020
giuliomoro added a commit that referenced this issue Dec 18, 2020
giuliomoro added a commit that referenced this issue Dec 19, 2020
Currently only used by the Bela backend, but it is not strictly Bela-specific.
Gives a good 7% save on CPU on Bela.

Closes #62
Closes #52
Closes #16
giuliomoro added a commit that referenced this issue Dec 19, 2020
It relies on the __COBALT__ macro which is defined if Xenomai is used.
Currently only used by the Bela backend, but it is not strictly Bela-specific.
Gives a good 7% save on CPU on Bela.

Closes #62
Closes #52
Closes #16
giuliomoro added a commit that referenced this issue Dec 20, 2020
It relies on the __COBALT__ macro which is defined if Xenomai is used.
Currently only used by the Bela backend, but it is not strictly Bela-specific.
Gives a good 7% save on CPU on Bela.

Closes #62
Closes #52
Closes #16
giuliomoro added a commit that referenced this issue Dec 20, 2020
It relies on the __COBALT__ macro which is defined if Xenomai is used.
Currently only used by the Bela backend, but it is not strictly Bela-specific.
Gives a good 7% save on CPU on Bela.

Closes #62
Closes #52
Closes #16
giuliomoro added a commit that referenced this issue Dec 20, 2020
It relies on the __COBALT__ macro which is defined if Xenomai is used.
Currently only used by the Bela backend, but it is not strictly Bela-specific.
Gives a good 7% save on CPU on Bela.

Closes #62
Closes #52
Closes #16
giuliomoro added a commit that referenced this issue Dec 20, 2020
It relies on the __COBALT__ macro which is defined if Xenomai is used.
Currently only used by the Bela backend, but it is not strictly Bela-specific.
Gives a good 7% save on CPU on Bela.

Closes #62
Closes #52
Closes #16
giuliomoro added a commit that referenced this issue Jan 23, 2021
It relies on the __COBALT__ macro which is defined if Xenomai is used.
Currently only used by the Bela backend, but it is not strictly Bela-specific.
Gives a good 7% save on CPU on Bela.

Closes #62
Closes #52
Closes #16
giuliomoro added a commit that referenced this issue Jan 28, 2021
It relies on the __COBALT__ macro which is defined if Xenomai is used.
Currently only used by the Bela backend, but it is not strictly Bela-specific.
Gives a good 7% save on CPU on Bela.

Closes #62
Closes #52
Closes #16
giuliomoro added a commit that referenced this issue Jan 28, 2021
It relies on the __COBALT__ macro which is defined if Xenomai is used.
Currently only used by the Bela backend, but it is not strictly Bela-specific.
Gives a good 7% save on CPU on Bela.

Closes #62
Closes #52
Closes #16
giuliomoro added a commit that referenced this issue Jan 28, 2021
It relies on the __COBALT__ macro which is defined if Xenomai is used.
Currently only used by the Bela backend, but it is not strictly Bela-specific.
Gives a good 7% save on CPU on Bela.

Closes #62
Closes #52
Closes #16
giuliomoro added a commit that referenced this issue Jan 28, 2021
It relies on the __COBALT__ macro which is defined if Xenomai is used.
Currently only used by the Bela backend, but it is not strictly Bela-specific.
Gives a good 7% save on CPU on Bela.

Closes #62
Closes #52
Closes #16
giuliomoro added a commit that referenced this issue Feb 10, 2021
It relies on the __COBALT__ macro which is defined if Xenomai is used.
Currently only used by the Bela backend, but it is not strictly Bela-specific.
Gives a good 7% save on CPU on Bela.

Closes #62
Closes #52
Closes #16
giuliomoro added a commit that referenced this issue Feb 10, 2021
It relies on the __COBALT__ macro which is defined if Xenomai is used.
Currently only used by the Bela backend, but it is not strictly Bela-specific.
Gives a good 7% save on CPU on Bela.

Closes #62
Closes #52
Closes #16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants