AEM in PythonΒΆ

The following example has ben generated by using the bbque-layapp command mentioned in Application structure:

#!/usr/bin/env python
import sys
import os
script_path = os.path.dirname(os.path.abspath(__file__))
barbeque_path = (script_path + "/../../lib/bbque/bindings/python" +
                str(sys.version_info[0]) + "." + str(sys.version_info[1]))
sys.path.append(barbeque_path)
import barbeque

class PySample(barbeque.BbqueEXC):

    def __init__(self, name, recipe, rtlib_services):
        super(PySample, self).__init__(name, recipe, rtlib_services)
        self.logger.Info("EXC Unique Identifier (UID): {}".format(self.GetUniqueID()))

    def onSetup(self):
        self.logger.Notice("PySample.onSetup()")

        # Initialization code...

        return barbeque.RTLIB_ExitCode.RTLIB_OK

    def onConfigure(self, awm_id):
        self.logger.Notice("PySample.onConfigure(): EXC [{}], AWM[{:02d}]"
                           .format(self.exc_name, awm_id))

        # Information about assigned resources
        res_w = barbeque.RTLIB_Resources_Amount_Wrapper()
        ret = self.GetAssignedResources(barbeque.RTLIB_ResourceType.PROC_ELEMENT, res_w)
        cpu_time = res_w.amount
        ret = self.GetAssignedResources(barbeque.RTLIB_ResourceType.PROC_NR, res_w)
        cpu_nr = res_w.amount
        ret = self.GetAssignedResources(barbeque.RTLIB_ResourceType.GPU, res_w)
        gpu_nr = res_w.amount
        ret = self.GetAssignedResources(barbeque.RTLIB_ResourceType.MEMORY, res_w)
        mem = res_w.amount

        self.logger.Notice("PySample.onConfigure(): [{}], AWM[{:02d}] => "
                           "cpu_time={:3d}, nr_cpus={:2d}, nr_gpus={:2d}, mem={:3d}"
                           .format(self.exc_name, awm_id, cpu_time, cpu_nr, gpu_nr, mem))

        # Configure the application w.r.t to the assigned resources
        # ...

        return barbeque.RTLIB_ExitCode.RTLIB_OK

    def onRun(self):
        # A computation run...
        self.logger.Notice("PySample.onRun(): EXC [{}], current cycle={:d}"
                            .format(self.exc_name, self.Cycles()))

        # ...just run 30 cycles end then exit
        if self.Cycles() == 30:
            return barbeque.RTLIB_ExitCode.RTLIB_EXC_WORKLOAD_NONE

        return barbeque.RTLIB_ExitCode.RTLIB_OK

    def onMonitor(self):
        wmp = self.WorkingModeParams()

        # Anything to check? Performance?

        self.logger.Notice("PySample.onMonitor(): EXC [{}], AWM[{:02d}] => CPS={:.2f}"
                            .format(self.exc_name, wmp.awm_id, self.GetCPS()))
        return barbeque.RTLIB_ExitCode.RTLIB_OK

    def onRelease(self):
        self.logger.Notice("PySample.onRelease(): terminating...")

        # Cleanup code...

        return barbeque.RTLIB_ExitCode.RTLIB_OK


def main():

    # Wrapper for RTLIB_Services
    services_wrapper = barbeque.RTLIB_Services_Wrapper()

    # Initialize rpc channel with the resource manager
    error_check = barbeque.RTLIB_Init("PySample", services_wrapper)
    if (error_check != barbeque.RTLIB_ExitCode.RTLIB_OK) or (not services_wrapper.services):
        print ("RTLIB initialization failed")
        return

    # Run
    exc = PySample("PySample", "PySample", services_wrapper.services)
    exc.Start()
    exc.WaitCompletion()

if __name__ == '__main__':
    main()

In the main function, we must initialize the RTLib as we do for the C++ version, by calling the barbeque.RTLIB_Init function, providing the application name and a barbeque.RTLIB_Services_Wrapper object.

Then we can instantiate an object of the class derived from barbeque.BbqueEXC (in this case PySample), by specifying the application name, the recipe file name without the .recipe extension, and reference to the .services field of the barbeque.RTLIB_Services_Wrapper previously initialized.

At this point, we are ready to launch the actual execution by calling the Start() method and leaving the main thread waiting for the termination (WaitCompletion()).

The derived class, implementing the Adaptive Execution Model, matches the same semantic already described for the C++, we the main difference represented by the Python syntax.

Finally, similarly to the C++ case, in order to properly install our application under the BOSP installation path, we need to enable the application building/installation under the Sample applications menu (Build Configuration with Kconfig) and launch the build command (make or make samples if the source code has been deployed under bosp/samples/python).

By default, the application is installed under <BOSP_PATH>/usr/bin.