Skip to main content
Skip table of contents

Subcanvas - Worker Threads

Worker Threads

The Subcanvas supports multithreaded IP using a new SubcanvasWorkerThread module. The Subcanvas as shown on the Designer canvas is actually a subsystem which contains multiple internal modules. It contains a SubcanvasInternal module named “SC” which holds the AWEInstance used by the Subcanvas and one SubcanvasWorkerThread module for each additional thread required by the IP. When you profile a system with a Subcanvas, you will see these internal modules as part of the profiling data. Here is an example with 1 internal Worker Thread:

The sole purpose of the SubcanvasWorkerThread modules is to call the awe_pump() function of the SubcanvasInternal module from different threads of the parent signal flow. The SubcanvasWorkerThread modules execute as part of the parent signal flow and appear within the profiling information of the parent signal flow.

Mapping of Worker Thread Clock Dividers to Parent Clock Dividers

The properties of the internal WorkerThreads are specified by the “workerThreads” argument of the Subcanvas module. In most cases, this is set to ‘awc’ and the Subcanvas will use the clockDividers of the JSON file to configure the Worker Threads A single threaded Subcanvas (without Worker Threads) will contain:

CODE
"clockDividers": [  
"1A0"  
],

The 1A0 thread of the Subcanvas always pumps as part of the parent layout where the Subcanvas module is placed. The Subcanvas inherits the clock divider from its input pin (just like all other Audio Weaver modules do). For example, suppose that the Subcanvas inherits a clock divider of 4B1, then the Subcanvas will execute in clock divider 4B1. This works as long as the sample rate and block size of 4B1 match what is supported by the Subcanvas.

Now consider a Subcanvas that has an input block size of 48 samples and uses 3 clock dividers as shown below. This Subcanvas requires 2 Worker Threads.

CODE
"clockDividers": [
"1A0",
"2A0",
"8B0"
],

Clock divider 1A0 will map to the clock divider which is inherited by the Subcanvas’ input pin. But how will the 2 Worker Threads 2A0 and 8B0 be mapped? The general guidelines are:

  1. The clock divider of the Worker Thread will be set to: (clock divider of Worker Thread in the AWC file) x (clock divider of the input pin).

  2. The layoutSubID is set to the layoutSubID specified by the Worker Thread.

  3. The instance ID of the Worker Thread will be set to the instance ID of the input pin.

A few examples will make this clear.

  • Subcanvas module placed into thread 2A0 [Clock dividers multiply]

    • Worker Thread 2A0 🡪 4A0

    • Worker Thread 8B0 🡪 16B0

  • Subcanvas module placed into thread 1B0 [layoutSubIDs are unchanged]

    • Worker Thread 2A0 🡪 2A0

    • Worker Thread 8B0 🡪 8B0

  • Subcanvas module placed into thread 4A2 [instanceIDs come from the input pin]

    • Worker Thread 2A0 🡪 8A2

    • Worker Thread 8B0 🡪 32B2

Subblock Pumping

A novel feature is to allow the Subcanvas to pump at a smaller block size than the wire connected to it. This is called “Subblock Pumping”. Let’s continue with the previous example which has an input block size of 48 samples and uses 3 clock dividers:

CODE
"clockDividers": [
"1A0",
"2A0",
"8B0"
],

Suppose that the input wire of the Subcanvas has a block size of 96 samples and a clock divider 1A0. The SubcanvasInternal module will pump once every 96 samples in clock divider 1A0. In its process function it will then pump the internal IP twice. This allows the internal IP to operate at a block size that is smaller than the Fundamental Block Size of the Parent Signal Flow. The only requirement is that the outer block size must be a multiple of the Fundamental Block Size of the Subcanvas.

The clock divider 2A0 is thus handled in the base pump call of the SubcanvasInternal module and in this case only a single Worker Thread is needed for 8B0. Since the base pump is at a block size of 96 samples, layout 8B0 will map to a clock divider of 4B0. In this example, the layouts all pump “evenly” without CPU spikes.

Consider a slightly different example with an input block size of 48 samples and 3 clock dividers:

CODE
"clockDividers": [
"1A0",
"3A0",		// This has changed
"8B0"
],

If you try and operate this Subcanvas with a block size of 96 samples it will fail because clock divider 3A0 is not divisible by the base pump rate of 2. It is impossible to configure a Worker Thread to pump with a clock divider of 1.5.

Now operate the Subcanvas with a block size of 4x48 = 192 samples. In this case, the 3A0 Worker Thread will be swallowed up by the base 48-sample pumping. The pumping rate will be irregular since sometimes 3A0 will pump once and sometimes it will pump twice. For greater flexibility, Audio Weaver allows this, but you must be careful since it can lead to CPU spikes. 8B0 will be assigned to a Worker Thread with a clock divider of 8/4 = 2B0.

The profiling information show in Designer does not break out the Worker Threads that have been swallowed by the base pumping. Instead, the profiling information for the swallowed Worker Threads will be included in the profiling information for the base pumping.

Manually Setting Worker Threads

There may be instances where you want to manually specify the exact layout in which Worker Threads execute. This typically happens on the Hexagon when you want to take advantage of hardware threads. You specify where to place Worker Threads by setting the workerThread argument of the Subcanvas module. You specify a comma separated list of Worker Thread clockDividers in Audio Weaver format. Do not specify the core ID since this always inherited from the input wire. Start by opening the AWC file in a text editor and look for the “clockDividers” field. Suppose the AWC file contains:

CODE
"clockDividers": [
"1A0",
"2A0"
],

If you want to place the Worker Threads into subLayoutID B, set workerThreads = ‘2B’. The profiling data will confirm this:

JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.