-
Notifications
You must be signed in to change notification settings - Fork 2
AudYoFlo: Tutorial I: Step V: Adding ORC to Speedup Processing
In the latest release of AudYoFlo, we added support for ORC optimization toolchain as known from GStreamer. In AudYoFlo, we need to download and install the ORC tools within the cmake configuration phase.
The option to use the ORC in AudYoFlo that needs to be specified in cmake is
JVX_USE_ORC
which we may add to the compile script compiled.bat, e.g.,

When activating this option, we can observe the ORCC installation with the optimization options displayed on the console,

Regarding our starter project, the ORC processing will become part of the ayfStarterLib located in folder
AudYoFlo/sources/sub-projects/ayfstarter/sources/Libraries/ayfstarterlib
Here, we need to add an ORC definition file, run the code generation, involve the generated code in the C library and add the underlying ORC library to our project.
The definition of the ORC processing code is provided in file volume.orc,

The code defined here shall speedup the multiplication of the input signals with a volume level. Therefore, the problem needs to be stripped down to a vector multiplication in which each element of the vector is multiplied with a floating point value. The code is defined as follows:

Four versions of the code are defined,
-
volume_orc_double_ip: Multiplication of values with parametervolumeindoubleformat - in-place processing, that is, the data is taken from a buffer and stored it back to the buffer afterwards. -
volume_orc_float_ip: Multiplication of values with parametervolumeinfloatformat - in-place processing, that is, the data is taken from a buffer and stored it back to the buffer afterwards. -
volume_orc_double: Multiplication of values with parametervolumeindoubleformat - out-of-place processing, that is, the data is taken from one buffer and stored in another buffer afterwards. -
volume_orc_float: Multiplication of values with parametervolumeinfloatformat - out-of-place processing, that is, the data is taken from one buffer and stored in another buffer afterwards.
More information on the purpose of the ORC code is available here.
The newly created file volume.orc needs to be involved to run the code generation in our ayfStarterLib library. To do so, we need to add the orc file in the local CMakeLists.txt file,

At (1), we add the ORC definition file, at (2), the ORC library and header search path is added.
Once the cmake build process was completed, the ORC code can be found in files volume.orc.c and volume.orc.h which are directly added to the solution,

Four functions are available in the header file corresponding to the definition in the file volume.orc,

These files expect one or two pointer arguments - one for in-place operation and two for out-of-place processing.
In order to involve the generated code, the core processing function is adapted. At first, in order to allow optimized and non-optimized code to be chosen during runtime, we add a property that can be modified in file ayfstarterlib.h,

In the c-code, we allow two signal processing paths, depending on the new property,

The generated code of the ORC code generator involves functions taken from the ORC library. This library was added to the CMakeLists.txt file as shown previously. We can check the linked library in the properties of the project ayfAuNStarter - the audio node compiled for runtime load,

The library is specified in the CMakeLists.txt file in the project ayfstarterlib and is propagated to the executables and dynamic library projects by cmake within the build process.
When running code with ORC, we may use environment variables to control the behavior:
- Option
ORC_DEBUG=<value>: Set the debug output level, from 0 to something. - Option
ORC_BACKEND=<str>: Specify used backend with as the name. The default seems to be a good option, e.g., usingMMXdid not work as an error was reported when running with debug options:

The ORC tool generates code for optimized execution of the core processing task. However, if the micro compile fails, there is always a backup function to realize the desired code without optimization.
Commit ID #215db80b5a991c66c35f52692c284a61635d2c5c
The ORC compiler and library functions are initialized whenever using them for the first time. That may yield a call to the ORC allocation functions in the real-time processing loop - which is not a good choice.
In the latest version of this tutorial, a pre-run of the ORC code is executed in the algorithm prepare function right before processing is started in file,

As soon as frames arrive, the ORC code environment is fully setup, any real-time glitches do not occur. Note that the ORC code can only be initialized once during the lifetime of the process since the ORC private data is stored in a static variable in the generated functions.
The mechanism to provide runtime configurations via environment variable can be extended to allow for runtime specifications for ORC.
Therefore, the following properties are defined in file ayfstarterlib.pcgf,
-
runorc: Bool property to activate ORC processing, -
orcBackendIp: String property to specify the ORC backend for in-place processing, -
orcBackendOp: String property to specify the ORC backend for out-of-place processing, -
orcDebugLevel: String propert to declare ORC debug level.

In the code, the string tokens are simply used to modify the environment variables prior to actually starting the ORC code. Note that the backend engine can only be set once right before starting processing for the first time as the ORC compilation is involved always at the beginning of processing.