This example shows how to integrate GPU Coder™ into Simulink®. GPU Coder is not supported for Simulink blocks, but you can still leverage GPUs in Simulink by generating a dynamic linked library (dll) using GPU Coder, and then integrating it into a Simulink block by using coder.ExternalDependency
APIs. Sobel edge detection is used as an example to demonstrate this concept.
CUDA enabled NVIDIA® GPU with compute capability 3.2 or higher.
NVIDIA CUDA toolkit and driver.
Simulink to create the model in Simulink.
Computer Vision Toolbox™ to use the video reader and viewer used in the example.
Environment variables for the compilers and libraries. For information on the supported versions of the compilers and libraries, see Third-party Products. For setting up the environment variables, see Setting Up the Prerequisite Products.
To verify that the compilers and libraries necessary for running this example are set up correctly, use the coder.checkGpuInstall
function.
envCfg = coder.gpuEnvConfig('host');
envCfg.BasicCodegen = 1;
envCfg.Quiet = 1;
coder.checkGpuInstall(envCfg);
The sobelEdge.m function takes an image (represented as a single matrix) and returns an image with the edges detected.
type sobelEdge
function [ magnitude ] = sobelEdge( Image ) %#codegen % Copyright 2017-2019 The MathWorks, Inc. maskX = single([-1 0 1 ; -2 0 2; -1 0 1]); maskY = single([-1 -2 -1 ; 0 0 0 ; 1 2 1]); coder.gpu.kernelfun(); resX = conv2(Image, maskX, 'same'); resY = conv2(Image, maskY, 'same'); magnitude = sqrt(resX.^2 + resY.^2); thresh = magnitude < 0.4; magnitude(thresh) = 0; end
To run this function on the GPU from Simulink, generate a shared library by using GPU Coder. Call the generated code (library) from Simulink by using coder.ExternalDependency
APIs. Copy the generated library to top level folder.
Isize = single(zeros(240, 320)); cfg = coder.gpuConfig('dll'); codegen -args {Isize} -config cfg sobelEdge if ispc copyfile(fullfile(pwd, 'codegen','dll', 'sobelEdge','sobelEdge.dll'), pwd); else copyfile(fullfile(pwd, 'codegen','dll', 'sobelEdge','sobelEdge.so'), pwd); end
Before generating CUDA code, first test the MEX function in MATLAB® to ensure that it is functionally equivalent to the original MATLAB code and that no run-time errors occur.
The SobelAPI.m is a class that defines the API to invoke the generated dynamic library. Most of this function is a standard template. The method of interest is SobelAPI.sobelEdge, which is called to execute the dynamic library. This function invokes the sobelEdge dynamic library through a coder.ceval
call.
type SobelAPI
% Copyright 2017-2019 The MathWorks, Inc. classdef SobelAPI < coder.ExternalDependency %#codegen methods (Static) function bName = getDescriptiveName(~) bName = 'SobelAPI'; end function tf = isSupportedContext(ctx) if ctx.isMatlabHostTarget() tf = true; else error('Sobel library not available for this target'); end end function updateBuildInfo(buildInfo, ctx) [~, linkLibExt, execLibExt, ~] = ctx.getStdLibInfo(); % Header files. hdrFilePath = fullfile(pwd, 'codegen', 'dll', 'sobelEdge'); buildInfo.addIncludePaths(hdrFilePath); % Link files. linkFiles = strcat('sobelEdge', linkLibExt); linkPath = hdrFilePath; linkPriority = ''; linkPrecompiled = true; linkLinkOnly = true; group = ''; buildInfo.addLinkObjects(linkFiles, linkPath, ... linkPriority, linkPrecompiled, linkLinkOnly, group); % Non-build files. nbFiles = 'sobelEdge'; nbFiles = strcat(nbFiles, execLibExt); buildInfo.addNonBuildFiles(nbFiles,'',''); end %API for library function 'sobelEdge'. function c = sobelEdge(I) % Running in generated code, call library function. coder.cinclude('sobelEdge.h'); c = coder.nullcopy(I); coder.ceval('sobelEdge', coder.rref(I), coder.wref(c)); end end end
In Simulink, create a MATLAB function block that calls SobelAPI.sobelEdge. This step is equivalent to executing the GPU Coder generated DLL code. When the MATLAB function block executes, this dynamic library runs on your host machine's GPU. And similarly for code-generation from Simulink, the CUDA code is invoked. The Simulink model uses a video reader and a video display to show the effect of the algorithm.
open_system('gpucoder_sobelEdge'); set_param('gpucoder_sobelEdge', 'SimulationCommand', 'update');
Run simulation to see the effect of the Sobel algorithm.
sim('gpucoder_sobelEdge', 'timeout', 30);