On Fri, 19 Jan 2024 16:17:15 +0100 ichthyo <[email protected]> wrote:
Thus I'm leaning towards KISS, i.e. write a mutex based implementation
first and then see if we can find *any* performance impact. Moreover this
will allow us to push ahead and start integrating it in the actual code
base. And by doing so, we'll get a clearer picture as to where and when
this locking will matter (will it even have an impact on the synth
thread?)

On 22.01.24 00:01, Will Godfrey wrote:
Won't a mutex result in us having a hard link between the GUI and the core?

Hi Will,

This is a simple and very valid question;
unfortunately it touches a complicated topic;
sorry for the lengthy response...


Short version: It depends on what we understand as a "hard link".


Right now we have a single Yoshimi process. Even in the LV2 case.
All exchange between the threads happens through *shared memory*

Whenever there are two concurrent threads, which exchange data through
shared memory, there *must* be some form of "synchronisation".
This is an absolute, total, hard rule without any exception and workaround.

If we fail to do synchronisation, either data will be corrupted randomly,
or the other side will not see changes or stale or inconsistent data, or
(especially on x86 hardware) the hardware will do the synchronisation
behind the scenes and cause a slowdown.

To qualify the term "synchronisation": in fact this means that the
/visibility of changes/ must be synchronised. Simply put, each CPU core
has its own cache, and without synchronisation of visibility there is
no guarantee that one CPU core sees the data the other core processes.


Conclusion: as long as we have a single process and exchange data
through shared memory, we need to "synchronise" and this creates
some kind of /link/ or /interdependencies/ between GUI and core.

However, we have different means of synchronisation at our disposal,
and these differ in the /impact/ of this interdependency they create.


A *mutex* is simple and easy to get correct in code.
There is a single, well documented way to handle a mutex,
and if you violate this, the program breaks obviously, either
by exception or deadlock.
Moreover, a mutex has well known, fixed cost:
- acquiring the mutex costs ~250 - 500ns on average
- /as long/ as one thread is in the critical section, all other
  attempts to enter that section send that other thread to sleep,
  which incurs an additional wake-up delay of 1µs on average.

On the other end of the scale lies the *atomic*
Atomics are very hard to grasp and understand, and quite abstract.
They can be used in a lot of creative ways, and even for advanced
well trained users it is sometimes almost impossible to decide or
even prove that the Atomics were really handled correctly.
Code involving atomics tend to be "alchemist magic"
On top of this comes, that the performance impact of Atomics
is hard to quantify and highly dependent on the circumstances.
- writing or reading an atomic costs only ~10ns
- *BUT* if two threads accidentally happen to /contend/ on the
  same atomic (i.e. try to write and read it in the same time frame),
  then this time can /balooon/ up to 200µs. And what is even
  worse, this slowdown can also impact other unrelated threads in
  ways that are hard to understand and often impossible to reproduce.

The *future* lies in the middle between the two cases. It is
much easier to understand than an atomic, but still more complex
than a mutex. Using a future requires a kernel call, and thus
has the same fixed cost as acquiring a mutex, but then there
is no additional sleep state. But the downside of a future is
that it covers only a very limited use case (which does not
apply in the case at hand here, i.e. we can not use a future).


Now, to apply these general insights to our actual case:
- if we use a mutex, the core could suffer a 2µs blocking
  in case it just happens to publish a value at the same time
  as the GUI wants to retrieve the previous value
- if we use atomics instead, in the same situation the
  the core could be delayed up to 200µs, but in a very
  unpredictable way and (if done right) also less likely.

To put these timing values in context: Yoshimi typically requires
1-5 milliseconds to process a single very simple short note.

(Sidenote: our ring buffers use atomics, so the behaviour mentioned
for atomics applies also to the ringbuffers: the core can suffer a
significant delay any time another thread happens to read/write
concurrently to the ringbuffer. But this is rather unlikely, and
the core is never blocked, but only slowed down)


So bottom line: it depends on the actual scenario and the architecture.
Given the right circumstances, you can do really stunning things with
atomics, and thus they are a "must" for high-performance computing
which has to care for every nanosecond.


My argument is: at the moment, we do not have a clear picture yet
how this new system is used. Thus at least *I* am unable to see if
we could even benefit from atomics; I can not even decide the question
yet if we can use them, and how. I have spent some time thinking that
over, and there might be a somewhat tricky procedure to make that
happen -- but then there is a general rule in programming that we
should not spend much time on an advanced solution
before having tried out the simple solution.


And a very important final note: Our goal is to work towards some
kind of communication channel. This would allow us to run the GUI
in a separate process. Especially for LV2, this is actually what
was intended by the protocol. If we go that route, we would then
at some point /replace/ our ringbuffers and the new data buffer
by a communication protocol like sockets, TCP or whatever.
Only this radical step would break the hard link between core
and GUI, but at the same time, this would introduce a latency
and possible a new link to the special twists of that protocol:
any kind of IO can *block* (and thus is rather comparable to
a mutex). Unless you're using the so called "asynchronous IO".
But that would definitively mean to go down the rabbit's hole.

-- Hermann



_______________________________________________
Yoshimi-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/yoshimi-devel

Reply via email to