I restart the design discussion around the dsp and multi-thread subject. If i try to describe the system as resulting from everything we said and wrote in the last few months, i woulds say we have a control subsystem, and a dsp sub system.
The control subsystem is composed by a thread for each event source; each thread wait for the event (input available, timing) and when ready execute the control patch or the system action associated.
The dsp subsystem is constituted by a pool of real-time threads, executing the data flow machine i discussed in a previous mail.
The interaction between the two is pretty complex; the dsp subsystem can generate events to unblock control threads, and the control threads should be able to change the status of dsp object atomically.
Well, i think the best way to describe this architecture is the french expression “une usine à gas”, a gas factory, something large, with a lot of plumbing connecting many different and heterogenous components.
So, can we make simpler ?
My idea is to take the data flow engine and use it to run everything.
Let's start with a definition: i define a “work chunk” (waiting for a better term) as a piece of computation that can be and is executed sequentially by a single thread and that synchonize with external entities only at the beginnin of the computation on availability of input data, and at the end by providing output data for other work chunks.
A work chunk is executable if its dependencies rules on input data are satisfied; these rules can be simple AND or OR rules, or more complex (within the expressivity limits of a very efficent implementation).
The dsp grap chunk described in the previous mail is an example of work chunk.
The data flow engine execute executables work chunks using a structured thread pool.
Work chunks have a class; the class of the work chunk is used by the data flow engine to select the thread that will execute the work chunk. For example, a dsp graph chunk will get a real time thread. A system work chunk (save a patch, for example) will get a low priority thread, while a work chunk executing a control patch will get a priority depending on the event source (different between UI and timers, for example).
As you can already imagine, the idea is that *all* the computation within fts should run as a work chunk.
From another point of view, we want to represent the whole system as an extended data flow graph.
In general, with the current control semantic, the execution of a control patch must be wrapped in a single work chunk. This work chunk will have as input data the data generated from the event starting the patch. if the event is external (UI for example) we will need some glue code (and thread) to get the input data and to put it on the data flow input buffer of the chunk data. If the event is internal, it will just be a connection between two work chunk. This bring a simple solution to control patches activated by the dsp computation, as any patch using timers, for example.
This also imply that control objects change the dsp objects status by providing input data. This solve the synchronisation problem, and require MAX dsp objetcs to be written as a pair of “data flow object” interacting thru the data flow engine (but this is not very different from what we have now).
In terms of implementation, a work chunk can still be implemented as a chunk of ftl code, if enough primitives are added to ftl (like invoke_control).
For sure there are a number of problems still to be solved, but this solution have a number of advantages and opportunities.
First of all, the implementation is simpler, because only a single paradigm is used for doing everything.
Second this architecture support a progressive implementation: a first version can for example use a single thread execution with the current dsp chain in a single work chunk. A second version can introduce a simple thread poll using jack. Later we can write the dsp compiler to generate multiple work chunk.
This strategy would allows us to work immediately on the data flow engine as the way to introduce scalability in jMax, instead of waiting six or nine month to start the work.
Finally, an interesting opportunity is to have in the future a data flow model (or petri net model or similar) for control.
Maurizio