Build and Run an Executable on NVIDIA Hardware - MATLAB & Simulink (original) (raw)

The MATLAB® Coder™ Support Package for NVIDIA® Jetson™ and NVIDIA DRIVE® Platforms uses the GPU Coder™ product to generate CUDA® code (kernels) from the MATLAB algorithm. These kernels run on a CUDA enabled GPU platform. The support package automates the deployment of the generated CUDA code on GPU hardware platforms such as NVIDIA DRIVE or Jetson.

Learning Objectives

In this tutorial, you learn how to:

Tutorial Prerequisites

Target Board Requirements

Development Host Requirements

Example: Vector Addition

This tutorial uses a simple vector addition example to demonstrate the build and deployment workflow on NVIDIA GPUs. Create a MATLAB function myAdd.m that acts as the_entry-point_ for code generation. Alternatively, you can use the files provided in the Getting Started with the MATLAB Coder Support Package for NVIDIA Jetson and NVIDIA DRIVE Platforms example. The easiest way to generate CUDA kernels for your MATLAB algorithm is to place the coder.gpu.kernelfun (GPU Coder) pragma in the entry-point function. When GPU Coder encounters kernelfun pragma, it attempts to parallelize the computation within this function and then maps it to the GPU.

function out = myAdd(inp1,inp2) %#codegen coder.gpu.kernelfun(); out = inp1 + inp2; end

Create a Live Hardware Connection Object

The support package software uses an SSH connection over TCP/IP to execute commands required for building and running the generated CUDA code on the DRIVE or Jetson platforms. Connect the target platform to the same network as the host computer. Alternatively, you can use an Ethernet crossover cable to connect the board directly to the host computer. Refer to the NVIDIA documentation on how to set up and configure your board.

To communicate with the NVIDIA hardware, you must create a live hardware connection object by using thejetson ordrive function. To create a live hardware connection object, provide the host name or IP address, user name, and password of the target board. For example to create live object for Jetson hardware:

hwobj = jetson('jetson-tx2-name','ubuntu','ubuntu');

The software performs a check of the hardware, compiler tools and libraries, IO server installation, and gathers information on the peripherals connected to the target. This information is displayed on the MATLAB Command Window.

Checking for CUDA availability on the Target... Checking for 'nvcc' in the target system path... Checking for cuDNN library availability on the Target... Checking for TensorRT library availability on the Target... Checking for prerequisite libraries is complete. Gathering hardware details... Checking for third-party library availability on the Target... Gathering hardware details is complete. Board name : NVIDIA Jetson TX2 CUDA Version : 10.0 cuDNN Version : 7.6 TensorRT Version : 6.0 GStreamer Version : 1.14.5 V4L2 Version : 1.14.2-1 SDL Version : 1.2 OpenCV Version : 4.1.1 Available Webcams : Microsoft® LifeCam Cinema(TM) Available GPUs : NVIDIA Tegra X2

Alternatively, to create live object for DRIVE hardware:

hwobj = drive('drive-px2-name','ubuntu','ubuntu');

Note

When there is a connection failure, a diagnostic error message is reported on the MATLAB Command Window. The most likely cause of a failed connection is incorrect IP address or host name.

Generate CUDA Executable Using GPU Coder

To generate a CUDA executable that can be deployed to an NVIDIA target, create a custom main wrapper file main.cu and its associated header file main.h. The main file calls the entry-point function in the generated code. The main file passes a vector containing the first 100 natural numbers to the entry-point function and writes the results to themyAdd.bin binary file.

Custom main.cu File

//main.cu
// Include Files
#include "myAdd.h"
#include "main.h"
#include "myAdd_terminate.h"
#include "myAdd_initialize.h"
#include <stdio.h>

// Function Declarations
static void argInit_1x100_real_T(real_T result[100]);
static void main_myAdd();

// Function Definitions
static void argInit_1x100_real_T(real_T result[100])
{
  int32_T idx1;

  // Initialize each element.
  for (idx1 = 0; idx1 < 100; idx1++) {
    result[idx1] = (real_T) idx1;
  }
}

void writeToFile(real_T result[100])
{
    FILE *fid = NULL;
    fid = fopen("myAdd.bin", "wb");
    fwrite(result, sizeof(real_T), 100, fid);
    fclose(fid);
}

static void main_myAdd()
{
  real_T out[100];
  real_T b[100];
  real_T c[100];

  argInit_1x100_real_T(b);
  argInit_1x100_real_T(c);
  
  myAdd(b, c, out);
  writeToFile(out);  // Write the output to a binary file
}

// Main routine
int32_T main(int32_T, const char * const [])
{
  // Initialize the application.
  myAdd_initialize();

  // Invoke the entry-point functions.
  main_myAdd();

  // Terminate the application.
  myAdd_terminate();
  return 0;
}

Custom main.h File

//main.h
#ifndef MAIN_H
#define MAIN_H

// Include Files
#include <stddef.h>
#include <stdlib.h>
#include "rtwtypes.h"
#include "myAdd_types.h"

// Function Declarations
extern int32_T main(int32_T argc, const char * const argv[]);

#endif

Create a GPU code configuration object for generating an executable. Use the coder.hardware function to create a configuration object for the DRIVE or Jetson platform and assign it to the Hardware property of the code configuration object cfg. Use the BuildDir property to specify the folder for performing remote build process on the target. If the specified build folder does not exist on the target, the software creates a folder with the given name. If no value is assigned tocfg.Hardware.BuildDir, the remote build process happens in the last specified build folder. When there is no stored build folder value, the build process takes place in the home folder.

cfg = coder.gpuConfig('exe'); cfg.Hardware = coder.hardware('NVIDIA Jetson'); cfg.Hardware.BuildDir = '~/remoteBuildDir'; cfg.CustomSource = fullfile('main.cu');

Note

The GPU code configuration object uses the default compute capability value specified in coder.gpuConfig (GPU Coder). To use the complete set of features supported by your CUDA GPU and to reduce numerical mismatches, set theComputeCapability property of the code configuration object to match your GPU specifications. You can use the GPUInfo property of the hardware connection object to get the compute capability value for the GPU on your target.

To generate CUDA code, use the codegen command and pass the GPU code configuration object along with the size of the inputs for the myAdd entry-point function. After the code generation takes place on the host, the generated files are copied over and built on the target.

codegen('-config ',cfg,'myAdd','-args',{1:100,1:100});

Run the Executable and Verify the Results

To run the executable on the target hardware, use the runApplication method of the hardware object. In the MATLAB Command Window, enter:

pid = runApplication(hwobj,'myAdd');

Launching the executable on the target...

Executable launched successfully with process ID 26432. Displaying the simple runtime log for the executable...

Copy the output bin file myAdd.bin to the MATLAB environment on the host and compare the computed results with the simulation results from MATLAB.

outputFile = [hwobj.workspaceDir '/myAdd.bin'] getFile(hwobj,outputFile);

% Simulation result from the MATLAB. simOut = myAdd(0:99,0:99);

% Read the copied result binary file from target in MATLAB. fId = fopen('myAdd.bin','r'); tOut = fread(fId,'double'); diff = simOut - tOut'; fprintf('Maximum deviation : %f\n', max(diff(:)));

Maximum deviation between MATLAB Simulation output and GPU coder output on Target is: 0.000000

See Also

Functions

Objects

Topics