Skip to content

Run applications on simulator and target

This page describes how you can run your application on the Hexagon simulator and on target by using the command line interface (CLI). This page also describes the run_main_on_hexagon utility to run dynamic tests on the Hexagon simulator as well as offload a simple computational algorithm to the DSP.

Run applications on simulator

Framework for unit testing

The Hexagon SDK provides a framework that enables building dynamic tests and standalone tests and executing them on the Hexagon simulator as part of the build process. hexagon-lldb also allows to debug the unit test on the simulator.

Each of the provided Hexagon SDK example contains its own unit test.

A unit test is specified as follows in hexagon.min:

BUILD_QEXES += mylib_test               # Specify the name of the library (mylib_test.so) or executable (mylib_test) unit test
mylib_test_C_SRCS += src_app/mylib_test # List source file(s) to build mylib_test.so.  Sources must include a main(), which is the test entry point
mylib_test_DLLS+= rpcmem                # Specify test dependencies

In this example:

  • As explained in the description of the build targets, the use of QEXES instead of EXES indicates that the test binary should be run automatically on the Hexagon simulator after being built
  • The unit test is named mylib_test or mylib_test.so depending on whether we are building a dynamic test or standalone test
  • The test source file only includes one file, src_app/mylib_test.c
  • The test links the rpcmem support library and the test module

QuRT-based dynamic tests

By default, all unit tests defined using the unit testing framework described above are built and run as dynamic tests, which rely on a utility called run_main_on_hexagon to be executed. This approach is the recommended approach to run simulator tests as it provides a simulation environment that closely matches the target environment in which the dynamic library is used.

Simulator tests relying on run_main_on_hexagon are referred as dynamic tests because they involve shared objects instead of executables. For example, the calculator C++ example generates a dynamic test calculator_q.so, which is to be passed as an argument to run_main_on_hexagon for execution on the Hexagon simulator hexagon-sim.

run_main_on_hexagon calls dlopen() of the simulator test, obtains the address of main() using dlsym() on a shared object handle, and calls the main() function defined in the compiled shared library with argc and argv if provided.

All QuRT and test libraries are built into run_main_on_hexagon and QuRT header files are included by default by the build system for simulator tests using run_main_on_hexagon. This means that you should not link rtld, test_util and atomic libraries to your dynamic tests.

When a QuRT-based test is run using run_main_on_hexagon, the user shared library is loaded in a separate thread whose stack size can be configured by passing the argument stack_size=<byte size in decimal or hexadecimal format> to run_main_on_hexagon_sim binary. For QuRT-based tests, the heap used by QuRT kernel during bootstrapping time can be configured by adjusting the global variable heapSize. The default heap value is set to 1024 MB in test_util library. To change the heap size in user code, simply re-define the global variable and set its value to the desired heap value. For example, to set the heap size to 2048 MB, use:

unsigned int heapSize = 0x80000000;

Standalone tests

Standalone tests are simulator test executables that do not use QuRT. These tests are executed directly by the Hexagon simulator and do not run on target.

Simulator tests with a QuRT dependency should be using run_main_on_hexagon.

The calculator example is an example that generates a standalone test calculator_q. This binary is executed by being passed to the Hexagon simulator.

A standalone test is defined the same way as a dynamic test with the exception that hexagon.min must set the NO_QURT_INC variable to 1:

This results in skipping the inclusion of QuRT libraries and headers when building the test:

NO_QURT_INC = 1                         # Do not include QuRT dependencies and generate a standalone test instead of a dynamic test

Since standalone tests do not run with run_main_on_hexagon, any test library dependency such as rtld, test_util or atomic needs to be listed in <unit_test_name>_LIBS. For example, to modify the calculator example to use a dynamic test instead of a standalone test, simply remove the NO_QURT_INC = 1 line in hexagon.min and remove rtld test_util atomic from the list of dependencies specified in calculator_q_LIBS.

Note: It is not possible to test a dynamic library with a standalone test as a dynamic library can not be linked to a static standalone executable.

Note: You can handle C/C++ library dependencies in your standalone code as follows:

#include <dlfcn.h>
...
DL_vtbl vtbl;
char *builtin[] = { (char*)"libc.so", (char*)"libgcc.so"};
// Note: you may specify additional dependencies such as (char*)"libgcc.so" if need be
memset(&vtbl, 0, sizeof(DL_vtbl));
vtbl.size = sizeof(DL_vtbl);
vtbl.msg = HAP_debug_v2;
(void)dlinitex(2, builtin, &vtbl);

The code sample above tells the loader that libc and libgcc.so symbols are built-in and therefore, that the shared objects libc and libgcc.so should not be loaded even if specified as dependent libraries in the Makefile. This approach is not needed for dynamic tests and for libraries running on target as run_main_on_hexagon and fastrpc_shell, the FastRPC user PD ELF on target, execute similar instructions.

The default values of stack and heap memory available to standalone-tests are 1MB and 64 MB, respectively. However, the stack and heap memory values are configurable with the help of the parameters STACK_SIZE and HEAP_SIZE via command-line. Please refer to Hexagon Standalone Application User Guide (80 N2040-22) for more information about simulator command-line options.

Test library support

The Hexagon SDK provides unit test support libraries. For detailed information see the header and source files contained in the $HEXAGON_SDK_ROOT/utils directory.

test_util

This library provides support for the unit test environment. It includes simulator versions of features otherwise present on the target DSP image, such as memory allocation, debug message support, VTCM manager, L2 cache locking manager, and performance measurement.

Test execution

The build framework builds and executes unit tests automatically. In the case of standalone tests, the unit test is built into a Hexagon simulator executable, which is then run by the Hexagon simulator. In the case of a dynamic tests, the simulator executes run_main_on_hexagon, which calls the main() defined in the dynamic library to execute the unit test.

In the event of a test failure, the build will fail and display the output of the failing test.

To enable more detailed information for the make process, including the output of a successful test run, set VERBOSE=1 on the make command.

For example:

make hexagon DSP_ARCH=v68 BUILD=Debug VERBOSE=1

Run applications on target

Connect to the device

To install USB drivers on Windows/Linux and establish a connection between the device and host PC, see USB drivers setup and ADB driver setup.

Compile the binaries

Before you push the required executables and shared objects to the device, make sure you have compiled the HLOS and DSP binaries. For instructions on compiling, see build.

File locations of binaries

Once the binaries are compiled, push them to the appropriate location on the device.

  • On Linux Android (LA), the recommended location on target for the application executable is /vendor/bin, and /vendor/lib64 for their libraries.

  • On Linux Environment (LE), the recommended location for the application executable is /usr/bin, and /usr/lib64 for their libraries.

  • For recommended locations on where to push DSP binaries, see the discussion on the remote file systen.

Run the examples

To run an example on target, see the calculator example.

run_main_on_hexagon

run_main_on_hexagon is a utility to run dynamic tests on the simulator as well as offload an algorithm compiled as a shared object to the DSP. On both the Hexagon simulator and on the device, run_main_on_hexagon calls dlopen() on the dynamic shared object, obtains the address of main() using dlsym() on the shared object handle, and calls the main() function defined in the compiled shared object with argc and argv if provided. The main() is called in a new thread spawned with a stack whose size may be configured with the optional argument stack_size.

run_main_on_hexagon allows to invoke the main() of a DSP shared library without the need for providing an IDL file and the source for a CPU executable. This approach is illustrated in the QHL example and the QHL HVX example.

As explained above, run_main_on_hexagon is also used for dynamic simulator tests where it provides a simulation environment that closely matches the target environment in which the dynamic library will be used. This is achieved with the help of QuRT-provided root program called runelf.pbn.

runelf.pbn is a boot loader that loads the dynamic executable on top of hexagon-sim. It has a main thread that loads the user program and an exception thread that waits to process any exceptions that are then routed back to root. Exceptions in the user program are displayed in the console and can be debugged further using this approach.

Using run_main_on_hexagon also allows to abstract the linking of the simulator test with QuRT libraries and other common libraries.

NOTE:* For more details on how run_main_on_hexagon is implemented, see the $HEXAGON_SDK_ROOT/libs/run_main_on_hexagon/src directory.

On-target usage

Usage:

    adb shell /vendor/bin/run_main_on_hexagon <domain> <path> [stack_size=<size>] [args]

OPTIONS:
    domain: Specify the DSP domain on which to offload the program, expressed as numeric domain id
            supported domains: 0 (ADSP), 1 (MDSP), 2 (SDSP), 3 (CDSP)
    path: File path of the shared object that includes the definition of `main()`
    stack_size= : Optional argument to configure the stack size of new `ribbon` thread that runs main()
                  default stack size is 256kb and stack size less than 256kb is not supported
    args: Optional string arguments to pass to main()

Note: The stack size of the thread where the main() is called is configurable to allow users to offload complex computations to the DSP conveniently.

Here is a command-line example invoking run_main_on_hexagon on target.

    adb shell /vendor/bin/run_main_on_hexagon 0 test_main.so stack_size=0x400000 1 foo2 2 bar

With this command line, run_main_on_hexagon calls main() defined in test_main.so in a thread of stack size 0x400000 with arguments 1 foo2 2 bar, on domain 0, i.e. on the ADSP.

Simulator usage

run_main_on_hexagon can also be invoked from the Hexagon simulator. Here is a command-line example that calls the main function in test_main.so on the hexagon simulator (assuming the desired Hexagon architecture version is v68):

    hexagon-sim -mv68 --simulated_returnval --usefs hexagon_ReleaseG_toolv88_v68 --pmu_statsfile hexagon_ReleaseG_toolv88_v68/pmu_stats.txt --cosim_file hexagon_ReleaseG_toolv88_v68/q6ss.cfg --l2tcm_base 0xd800 --rtos hexagon_ReleaseG_toolv88_v68/osam.cfg $HEXAGON_SDK_ROOT/rtos/qurt/computev68/sdksim_bin/runelf.pbn -- hexagon_ReleaseG_toolv88_v68/run_main_on_hexagon_sim stack_size=0x400000 -- test_main.so 1 foo 2 bar

With this command line, run_main_on_hexagon_sim calls main() defined in test_main.so in a thread of stack size 0x400000 with arguments 1 foo2 2 bar on the simulator.

Note: In simulator tests, the argument stack_size is to be passed before --. Any argument passed after -- is considered as an argument to the main implemented in the shared object.

QEMU support for Hexagon

QEMU is a popular open source machine emulator and virtualizer. It can operate in user mode, system mode & virtualizer mode.

QEMU needs to run in system mode in order to execute the Hexagon SDK examples. QEMU is currently supported in linux OS only. The advantage with QEMU is, it is 5x faster than the Hexagon simulator. However, the Hexagon simulator is more feature-complete. For a full list of features supported by the Hexagon simulator and QEMU, refer to the feature matrix. Please refer to Qualcomm Hexagon QEMU User Guide for installation instructions on windows host and more information about QEMU.

Running SDK Examples on QEMU

  • A text file containing the QEMU command, qemu_cmd_line.txt is automatically generated inside the Hexagon build output directory when the application is built using the make.d and CMake build systems.

  • Please copy the command from the text file and run it from the Hexagon build output directory path. This will start running the application using qemu-system-hexagon.

    For example, if we built for ReleaseG variant and v68 architecture then do cd hexagon_ReleaseG_tooltoolv88_v68 and then run the QEMU command in this directory.

Note: Please make sure to copy all the required dependencies and input files into the Hexagon build output directory before running the QEMU command.

The detailed steps to run QEMU for calculator_c++ example are given below. Please follow the same steps for remaining examples also.

  • Build the calculator_c++ example for the required variant and required architecture using make.d build system as below

    make hexagon DSP_ARCH=v68
    
  • Alternatively, below command will build and run the example on QEMU uing CMake build system

    build_cmake hexagonqemu
    
  • If there are any dependencies for the example to run, copy them into Hexagon build output directory. For this case, copy calculator.input into hexagon_ReleaseG_tooltoolv88_v68

  • Change the directory to hexagon_ReleaseG_tooltoolv88_v68 using the command

    cd hexagon_ReleaseG_tooltoolv88_v68
    
  • The QEMU command present in the qemu_cmd_line.txt file is

    $(DEFAULT_HEXAGON_TOOLS_ROOT)/Tools/bin//qemu-system-hexagon -kernel $(HEXAGON_SDK_ROOT)/rtos/qurt//computev68`/sdksim_bin/runelf.pbn -append '$(HEXAGON_SDK_ROOT)/libs/run_main_on_hexagon/ship/hexagon_tooltoolv88_v68/run_main_on_hexagon_sim -- calculator_q.so'
    
  • Copy this QEMU command from the text file and run it in the current directory. This gives the same output as that of running the Hexagon simulator command.