Create Stack Usage Profile for Generated Code
To determine the size of stack memory that is required to run generated code, you can run a software-in-the-loop (SIL) or processor-in-the-loop (PIL) simulation that generates a stack usage profile. The SIL or PIL simulation instruments the generated code and uses the instrumentation to calculate stack usage. The profiles that you generate enable you to observe the effect of compiler optimization and data input on stack usage.
You can generate stack usage profiles by using the top-model or Model block SIL/PIL workflows. Subsystem block SIL/PIL workflows do not support stack usage profiling.
Benefits of Dynamic Stack Usage Profiling
Static stack usage analysis has some limitations. For example, it does not consider:
Memory optimization performed by a compiler. For example, variables that are optimized away or stored in registers.
Additional memory that the compiler uses in a function call. Compilers store the address to which the execution returns after the function call.
Memory alignment that the compiler applies.
The dynamic stack usage profiling provided by a SIL or PIL simulation does not have the listed limitations because the simulation calculates the actual memory usage of the compiled code.
Configure Stack Usage Profiling
To run a SIL or PIL simulation that generates stack usage metrics:
In the Simulink® Editor, open your model.
On the Apps tab, click SIL/PIL Manager.
In the Mode section, select SIL/PIL Simulation Only.
In the Prepare section, specify System Under Test and, if required, SIL/PIL Mode. A PIL simulation requires a driver implementation that obtains stack usage data from the target hardware. See Obtain Stack Usage Data From Target Hardware..
To enable stack usage profiling, in the Prepare section:
Open the Settings gallery.
Under Time Profiling, click the Task Profiling button and Functions button off.
Under Coverage, click the Coverage Collection button off.
Under Stack Profiling, click the Stack Profiling button on. This action selects the Measure task stack usage configuration parameter, which provides stack usage measurements for each generated task. The top model setting for the parameter overrides the corresponding setting in referenced models.
Click , which opens the Configuration Parameters dialog box. On the Data Import/Export pane, clear the Single simulation output check box.
To view streamed stack usage during the simulation, open the Simulation Data Inspector. In the Results section, click .
In the Run section, click Run SIL/PIL.
In the MATLAB® base workspace, the simulation generates a variable with the default name,
stackProfile
, which stores the stack usage data. You can specify an
alternative name through the Stack workspace variable configuration
parameter.
Implement Driver to Obtain Stack Usage Data During PIL Simulation
A PIL simulation requires a driver implementation that obtains stack usage data from the target hardware. The driver must return the value of the stack register.
Note
If you do not specify a driver for your target hardware, the PIL simulation tries to use a default generic driver.
When you set up PIL target connectivity, specify the driver through an
subclass. This
code provides an example.rtw.connectivity.Config
classdef overheadConnectivityConfig < rtw.connectivity.Config methods function this = customConnectivityConfig(componentArgs) % Create builder targetApplicationFramework = ... mypil.TargetApplicationFramework(componentArgs); builder = rtw.connectivity.MakefileBuilder(componentArgs, ... targetApplicationFramework, ''); % Create launcher launcher = mypil.Launcher(componentArgs, builder); % Set up communication hostCommunicator = rtw.connectivity.RtIOStreamHostCommunicator(... componentArgs, ... launcher, ... rtiostreamLibTCPIP); % Call super class constructor to register components this@rtw.connectivity.Config(componentArgs,... builder,... launcher,... hostCommunicator); % Specify driver implementation that obtains stack usage % data from the target hardware stackUsageDriver = coder.profile.StackDriver(); stackUsageDriver.PtrDataType = 'uint64'; stackUsageDriver.HeaderFile = 'myHeaderFile.h'; stackUsageDriver.SourceFile = 'mySourceFile.c'; stackUsageDriver.IncludePaths = {'path/To/myFolder1', ... 'path/To/myFolder2', ... 'path/To/myFolder3'}; stackUsageDriver.DriverFunction = 'myDriverFunction'; this.setStackDriver(stackUsageDriver); end end end
For more information about setting up PIL target connectivity, see:
Limitations
Stack Usage Instrumentation Prevents Use of Red Zone Optimization
Under certain conditions, compilers can generate functions that do not allocate stack
memory when called but use the red zone in the function stack frame for local variables.
As a result of this optimization, the compiled code for the functions does not need to
adjust the stack pointer and uses the red zone directly. For a x86-64
processor, the GNU® GCC compiler assumes the red zone is 128 bytes.
Code instrumentation that is required to calculate the stack usage of functions prevents compilers from applying red zone optimization. Profiled functions that contain code instrumentation explicitly allocate stack memory for all local data. With non-instrumented code, some functions might not modify the stack register and use the red zone.