Determine Why Subsystem Code Is Not Reused
Due to the limitations described in Generate Reentrant Code from Subsystems, the code generator might not reuse generated code as you expect. To determine why code generated for a subsystem is not reused:
Review the Subsystems section of the code generation report.
Compare subsystem checksum data.
Review Subsystems Section of HTML Code Generation Report
If the code generator does not generate code for a subsystem as reusable code, and you configured the subsystem as reusable, examine the Subsystems section of the code generation report (see Generate Code Generation Report). The Subsystems section contains:
A table that summarizes how nonvirtual subsystems were converted to generated code.
Diagnostic information that describes why subsystems were not generated as reusable code.
The Subsystems section also maps noninlined subsystems in the model to
functions or reused functions in the generated code. For an example, see the
model SubsystemAtomic
in Generate Subsystem Code as Separate Function and Files.
Compare Subsystem Checksum Data
You can determine why subsystem code is not reused by comparing subsystem checksum data. The code generator determines whether subsystems are identical by comparing subsystem checksums, as noted in Limitations. For subsystem reuse across referenced models, this procedure might not flag every difference.
Consider the model, GeneratedCodeFunctionReuse
.
SS1
and SS2
are instances of
the same subsystem. In both instances the subsystem block parameter
Function packaging is set to
Reusable function
.
Use the method Simulink.SubSystem.getChecksum
to get the checksum for a
subsystem. Review the results to determine why code is not reused.
Open the model
GeneratedCodeFunctionReuse
.openExample('GeneratedCodeFunctionReuse')
Associate the subsystems
SS1
andSS2
withgcb
. For each of the subsystems , in the model window, select the subsystem. While the subsystem is selected, in the Command Window, enter:SS1 = gcb;
SS2 = gcb;
Use the method
Simulink.SubSystem.getChecksum
to get the checksum for each subsystem. This method returns two output values: the checksum value and details on the input used to compute the checksum.[chksum1, chksum1_details] = ... Simulink.SubSystem.getChecksum(SS1); [chksum2, chksum2_details] = ... Simulink.SubSystem.getChecksum(SS2);
Compare the two checksum values. The values should be equal based on the subsystem configurations.
isequal(chksum1, chksum2) ans = 1
To use
Simulink.SubSystem.getChecksum
to determine why the checksums of two subsystems differ, change the data type mode of the output port of SS1 so that it differs from that of SS2.Look under the mask of
SS1
. Right-click the subsystem. In the context menu, select Mask > Look Under Mask.In the block diagram of the subsystem, double-click the Lookup Table block to open the Subsystem Parameters dialog box.
Click Data Types.
Select block parameter Saturate on integer overflow and click OK.
Get the checksum for
SS1
. Compare the checksums for the two subsystems. This time, the checksums are not equal.[chksum1, chksum1_details] = ... Simulink.SubSystem.getChecksum(SS1); isequal(chksum1, chksum2) ans = 0
After you determine that the checksums are different, find out why. The Simulink® engine uses information, such as signal data types, some block parameter values, and block connectivity information, to compute the checksums. To determine why checksums are different, compare the data that computes the checksum values. You can get this information from the second value returned by
Simulink.SubSystem.getChecksum
, which is a structure array with four fields.Look at the structure
chksum1_details
.chksum1_details chksum1_details = ContentsChecksum: [1x1 struct] InterfaceChecksum: [1x1 struct] ContentsChecksumItems: [287x1 struct] InterfaceChecksumItems: [53x1 struct]
ContentsChecksum
andInterfaceChecksum
are component checksums of the subsystem checksum. The remaining two fields,ContentsChecksumItems
andInterfaceChecksumItems
, contain the checksum details.Determine whether a difference exists in the subsystem contents, interface, or both. For example:
isequal(chksum1_details.ContentsChecksum.Value,... chksum2_details.ContentsChecksum.Value) ans = 0 isequal(chksum1_details.InterfaceChecksum.Value,... chksum2_details.InterfaceChecksum.Value) ans = 1
In this case, differences exist in the content.
Write a script like this script to find the differences.
idxForCDiffs=[]; for idx = 1:length(chksum1_details.ContentsChecksumItems) if (~strcmp(chksum1_details.ContentsChecksumItems(idx).Identifier, ... chksum2_details.ContentsChecksumItems(idx).Identifier)) disp(['Identifiers different for contents item ', num2str(idx)]); idxForCDiffs=[idxForCDiffs, idx]; end if (ischar(chksum1_details.ContentsChecksumItems(idx).Value)) if (~strcmp(chksum1_details.ContentsChecksumItems(idx).Value, ... chksum2_details.ContentsChecksumItems(idx).Value)) disp(['Character vector values different for contents item ', num2str(idx)]); idxForCDiffs=[idxForCDiffs, idx]; end end if (isnumeric(chksum1_details.ContentsChecksumItems(idx).Value)) if (chksum1_details.ContentsChecksumItems(idx).Value ~= ... chksum2_details.ContentsChecksumItems(idx).Value) disp(['Numeric values different for contents item ', num2str(idx)]); idxForCDiffs=[idxForCDiffs, idx]; end end end
Run the script. The example assumes that you named the script
check_details
.check_details Character vector values different for contents item 202
The results indicate that differences exist for index item 202 in the subsystem contents.
Use the returned index values to get the handle, identifier, and value details for each difference found.
chksum1_details.ContentsChecksumItems(202) ans = Handle: 'GeneratedCodeFunctionReuse/SS1/Lookup Table' Identifier: 'SaturateOnIntegerOverflow' Value: 'on'
The details identify the Lookup Table block parameter Saturate on integer overflow as the focus for debugging a subsystem reuse issue.