Technical Articles

Profiling C Code Generated by MATLAB Coder

By Paul Peeling, MathWorks


Whether you are generating C code to accelerate MATLAB® algorithms or to deploy MATLAB algorithms to embedded targets, execution speed is an important consideration. By profiling your code and collecting timing information, you can quickly find hotspots and bottlenecks and identify opportunities to improve code performance.

This article shows how to profile C code generated by MATLAB Coder™. We’ll be using sample-based profiling, a technique that lets you find hotspots without having to modify the code. Sample-based profiling periodically samples the call stack of the running code and aggregates the data to report the relative execution time of different parts of the code. Other profiling methods rely on instrumenting the code, which changes the performance of the running code.

The workflow uses the Microsoft® Visual Studio® C++ compiler and a freely available profiling tool, AMD CodeAnalyst, but most other compilers and profiling tools work equally well.

Code Profiling Example

In this example, we will use the following MATLAB algorithm:

function z = do_intense_computations( x )
% do_intense_computations perform computationally intensive operations
%#codegen
 
% Copyright 2012-2016 MathWorks
y = fft_magnitude( x );
z = self_convolve( y );
end
 
function y = fft_magnitude(x)
coder.inline('never')
y = abs( fft ( x ) );
end
 
function y = self_convolve( x )
coder.inline('never')
y = conv( x, x );
end

We’ll use profiling to see whether the FFT or the convolution operation is more computationally intensive.

Preparing Code for Profiling

Although sample-based profiling requires no modification of the generated code, it is good practice to break up the algorithm into functions or subfunctions. Use coder.inline(‘never’) to ensure that whenever a function is used in MATLAB, the generated C code has a corresponding function call. It’s then easy to trace profiling results from the C code back to MATLAB.

Creating a Script for Profile Runs

CodeAnalyst does profiling over a set time period. The default run length is 20 seconds. Since our MATLAB algorithm might not take this long to execute, we create a script that allows us to call it multiple times:

x = randn( 256, 1 );
while ( true )
    y = do_intense_computations( x );
    pause( 0.1 ) % allow for CTRL-C operations to break execution
end

We then run the code in MATLAB to confirm that it executes without error, and press CTRL-C to stop the code running after CodeAnalyst has finished profiling.

Configuring Code Generation for MEX or SIL Verification

First, we create a MEX file from our MATLAB algorithm using MATLAB Coder, checking that the code generation settings are correct for performance. To accelerate the algorithm, we will perform profiling on the generated MEX function. For embedded target deployment, we will generate a static library (.lib) and perform profiling on the standalone C code using software-in-the-loop (SIL) with Embedded Coder®.

MEX Verification Settings

To set the MEX verification settings we do the following:

  1. In the MATLAB Coder App, select the MEX build type and More Settings.
profiling_c_code_fig1
  1. From the Debugging tab, select Disable C compiler optimizations and click Generate.
profiling_c_code_fig2
  1. Run our test script against the generated MEX file to check that the test script completes without error.

Once the script completes, we find a MEX file in the current folder and a .pdb file in the build folder. We copy the .pdb file into the current folder.

SIL Verification Settings

To set the SIL verification settings we do the following:

1.In the MATLAB Coder App, select the Static Library (.lib) build type and More Settings.

profiling_c_code_fig3
  1. From the Build Configuration options in the Toolchain tab, select Debug, close the settings dialog, and click Generate.
profiling_c_code_fig4
  1. Click Test and run our test script against the generated MEX file.

Once the script completes, we copy the .pdb file from the build folder into the current folder.

Profiling with Code Analyst

In our profiling script, we replace the call to do_intense_computations with do_intense_computations_mex or do_intense_computations_sil. A straightforward way of doing this is to use the profiling script as the test script to exercise the MEX file. We then click Verify Generated MEX.

profiling_c_code_fig5

We switch to CodeAnalyst and start profiling. The profiling run will last 20 seconds. After the run, we navigate to the profiling data collected for the functions within the MEX file.

profiling_c_code_fig6

CodeAnalyst shows a summary view of the information captured during profiling. We need to find the information for the MEX file by looking through the list of modules.

profiling_c_code_fig7

Here we find the MEX file running as part of the MATLAB process. We double-click on the entry to access the detailed profiling information.

profiling_c_code_fig8

The profiling data shows that that the convolution operation takes approximately 10 times longer than the FFT operation.

Summary

In this example we saw how to set up an environment for profiling MEX files to accelerate MATLAB code and standalone C code for embedded targets. Using AMD CodeAnalyst, we profiled the running code without having to modify existing MATLAB code. We quickly determined which functions in our MATLAB code were responsible for most of the computation and thus could be performance bottlenecks. We can now investigate the MATLAB code, look for opportunities to optimize it, and then rebuild and profile the MEX code again.

About the Author

Paul Peeling is a consultant engineer who specializes in signal processing, machine learning, and code generation for embedded hardware. He works with MATLAB and Simulink users to develop algorithms and model systems in multiple domains, and deploy the code to real-time targets. Paul holds a Ph.D. in statistical signal processing from the University of Cambridge.

Published 2017 - 93068v00

View Articles for Related Capabilities