Compare Checksums to Determine Why Generated Code Is Not Reused
The code generator uses checksums to determine whether to generate reusable code. If two subsystems have different checksums, the code generator generates separate functions for each subsystem even if you configure the subsystems to be reusable. In referenced model hierarchies, the code generator also compares checksums between models. This example shows how to use the Simulink.SubSystem.getChecksum method to compare subsystems for which you intend to generate reusable code and determine why the code generator considers them unequal.
Reusable code generation is an optimization feature that is not guaranteed. Even if subsystems have equal checksums, the code generator might not generate reusable code due to how the subsystems relate to other blocks in the model or model reference hierarchy, such as if a subsystem connects to a root Inport or Outport block. For information about how to troubleshoot cases where subsystems have equal checksums but do not generate a shared function, see Use Signal Conversion or Bias Blocks to Resolve Issues with Reusable Code Generation.
Inspect and Modify Model
Consider the model GeneratedCodeFunctionReuse.
model = 'GeneratedCodeFunctionReuse';
open_system(model);
The model contains two subsystems, SS1 and SS2. The subsystems are each configured to generate a reusable functiona and have the same contents, interfaces, and parameters. Run this line of code to introduce a difference between the subsystems:
create_checksum_inequality;
Generate and Inspect Code
Generate code for the model.
slbuild(model);
### Searching for referenced models in model 'GeneratedCodeFunctionReuse'. ### Total of 1 models to build. ### Starting build procedure for: GeneratedCodeFunctionReuse ### Successful completion of build procedure for: GeneratedCodeFunctionReuse Build Summary Top model targets: Model Build Reason Status Build Duration ============================================================================================================================= GeneratedCodeFunctionReuse Information cache folder or artifacts were missing. Code generated and compiled. 0h 0m 5.8561s 1 of 1 models built (0 models already up to date) Build duration: 0h 0m 6.4528s
Inspect the generated file GeneratedCodeFunctionReuse.c.
cfile = fullfile("GeneratedCodeFunctionReuse_grt_rtw", "GeneratedCodeFunctionReuse.c"); coder.example.extractLines(cfile, "/* Output and update for atomic system: '<Root>/SS1' */", "/* Model step function */")
/* Output and update for atomic system: '<Root>/SS1' */
void GeneratedCodeFunctionReuse_SS1(real_T rtu_In1, real_T rtu_In2, const real_T
rtp_y[11], const real_T rtp_x[11], B_SS1_GeneratedCodeFunctionRe_T *localB)
{
/* Lookup_n-D: '<S1>/Lookup Table' incorporates:
* Sum: '<S1>/Sum'
*/
localB->LookupTable = look1_binlx(rtu_In1 + rtu_In2, rtp_x, rtp_y, 10U);
}
/* Output and update for atomic system: '<Root>/SS2' */
void GeneratedCodeFunctionReuse_SS2(real_T rtu_In1, real_T rtu_In2, const real_T
rtp_y[11], const real_T rtp_x[11], B_SS2_GeneratedCodeFunctionRe_T *localB)
{
/* Lookup_n-D: '<S2>/Lookup Table' incorporates:
* Sum: '<S2>/Sum'
*/
localB->LookupTable = look1_binlx(rtu_In1 + rtu_In2, rtp_x, rtp_y, 10U);
}
The code generator produces two separate functions. This means that the code generator detects a difference between the subsystems. You can inspect checksums to determine whether the difference is between the contents or interfaces of the subsystems, then determine what the specific difference is and resolve it to generate a shared function.
Inspect Checksums
Associate each subsystem with a workspace variable.
ss1 = strcat(model, '/SS1'); ss2 = strcat(model, '/SS2');
Use the Simulink.SubSystem.getChecksum method to store the checksum and checksum details for each subsystem in a workspace variable.
[checksum1, checksum1_details] = Simulink.SubSystem.getChecksum(ss1); [checksum2, checksum2_details] = Simulink.SubSystem.getChecksum(ss2);
Confirm that the checksum values are not equal.
isequal(checksum1, checksum2)
ans = logical
0
Look at the contents of the checksum1_details structure.
checksum1_details
checksum1_details = struct with fields:
ContentsChecksum: [1×1 struct]
InterfaceChecksum: [1×1 struct]
ContentsChecksumItems: [332×1 struct]
InterfaceChecksumItems: [72×1 struct]
The ContentsChecksum and InterfaceChecksum fields represent component checksums of the subsystem checksum, corresponding to the contents and interface of the subsystem, respectively. Because the subsystem checksums are unequal, at least one of the component checksums must contain a different value than the corresponding component checksum for checksum2.
Compare component checksums between the subsystems to determine whether the subsystem checksums are unequal due to a difference in the interface, contents, or both.
isequal(checksum1_details.InterfaceChecksum.Value, checksum2_details.InterfaceChecksum.Value)
ans = logical
1
isequal(checksum1_details.ContentsChecksum.Value, checksum2_details.ContentsChecksum.Value)
ans = logical
0
The subsystems have the same interfaces but different contents. To determine the specific difference between the subsystem contents, iterate over each index in the ContentsChecksumItems field of the checksum details structures.
This code performs this iteration and populates arrays with indices where the subsystems have unequal identifiers, character vector values, or numeric values. If your subsystems have unequal interface checksums, replace instances in this code of ContentsChecksumItems with InterfaceChecksumItems.
identifierMismatchIndices=[]; characterVectorValueMismatchIndices=[]; numericValueMismatchIndices=[]; for idx = 1:length(checksum1_details.ContentsChecksumItems) if (~strcmp(checksum1_details.ContentsChecksumItems(idx).Identifier, ... checksum2_details.ContentsChecksumItems(idx).Identifier)) identifierMismatchIndices=[identifierMismatchIndices, idx]; end if (ischar(checksum1_details.ContentsChecksumItems(idx).Value)) if (~strcmp(checksum1_details.ContentsChecksumItems(idx).Value, ... checksum2_details.ContentsChecksumItems(idx).Value)) characterVectorValueMismatchIndices=[characterVectorValueMismatchIndices, idx]; end end if (isnumeric(checksum1_details.ContentsChecksumItems(idx).Value)) if (checksum1_details.ContentsChecksumItems(idx).Value ~= ... checksum2_details.ContentsChecksumItems(idx).Value) numericValueMismatchIndices=[numericValueMismatchIndices, idx]; end end end
Check if the script populated any of the arrays.
identifierMismatchIndices
identifierMismatchIndices =
[]
characterVectorValueMismatchIndices
characterVectorValueMismatchIndices = 229
numericValueMismatchIndices
numericValueMismatchIndices =
[]
characterVectorValueMismatchIndices contains an index, indicating that the subsystem checksums have a character vector value mismatch at that index in their ContentsChecksumItems properties. Check the mismatched values.
mismatchedIdx = characterVectorValueMismatchIndices(1); checksum1_details.ContentsChecksumItems(mismatchedIdx)
ans = struct with fields:
Handle: 'GeneratedCodeFunctionReuse/SS1/Lookup Table'
Identifier: 'SaturateOnIntegerOverflow'
Value: 'off'
checksum2_details.ContentsChecksumItems(mismatchedIdx)
ans = struct with fields:
Handle: 'GeneratedCodeFunctionReuse/SS2/Lookup Table'
Identifier: 'SaturateOnIntegerOverflow'
Value: 'on'
The Lookup Table blocks in the subsystems have different values for the SaturateOnIntegerOverflow block parameter.
Resolve Checksum Inequality and Regenerate Code
Change the SaturateOnIntegerOverflow parameter value of one Lookup Table block to match the value of the other block, then regenerate the code.
ss2LookupTableBlock = checksum2_details.ContentsChecksumItems(mismatchedIdx).Handle;
set_param(ss2LookupTableBlock,SaturateOnIntegerOverflow='off');
slbuild(model);### Searching for referenced models in model 'GeneratedCodeFunctionReuse'. ### Total of 1 models to build. ### Starting build procedure for: GeneratedCodeFunctionReuse ### Successful completion of build procedure for: GeneratedCodeFunctionReuse Build Summary Top model targets: Model Build Reason Status Build Duration ========================================================================================================= GeneratedCodeFunctionReuse Generated code was out of date. Code generated and compiled. 0h 0m 3.8285s 1 of 1 models built (0 models already up to date) Build duration: 0h 0m 4.2499s
Inspect the generated file ReusableSubsystemChecksumInequality again.
coder.example.extractLines(cfile, " &GeneratedCodeFunctionReuse_M_;", "/* Model step function */", 0)
/*
* Output and update for atomic system:
* '<Root>/SS1'
* '<Root>/SS2'
*/
void GeneratedCodeFunctionReuse_SS1(real_T rtu_In1, real_T rtu_In2, const real_T
rtp_y[11], const real_T rtp_x[11], B_SS1_GeneratedCodeFunctionRe_T *localB)
{
/* Lookup_n-D: '<S1>/Lookup Table' incorporates:
* Sum: '<S1>/Sum'
*/
localB->LookupTable = look1_binlx(rtu_In1 + rtu_In2, rtp_x, rtp_y, 10U);
}
The code contains a single reusable function instead of two separate functions.
See Also
Simulink.SubSystem.getChecksum | Simulink.BlockDiagram.getChecksum