Main Content

Programmatically Analyze Code Coverage for a Simulink Model

This example shows how to programmatically analyze code coverage for code generated by Embedded Coder®.

Load Model and Configure Coverage Settings

The model slcoverage_mcdc_logic_cascade contains a series of Logical Operator blocks that implements logic complex enough to have multiple modified condition decision coverage (MCDC) objectives.

modelName = "slcoverage_mcdc_logic_cascade";
load_system(modelName)

Use a Simulink.SimulationInput object to enable coverage analysis, tell Simulink® Coverage™ to include the coverage data in the Simulink.SimulationOutput object, and set the Structural coverage level parameter to MCDC.

simIn = Simulink.SimulationInput(modelName);
simIn = setModelParameter(simIn,"CovEnable","on");
simIn = setModelParameter(simIn,"CovSaveSingleToWorkspaceVar","on");
simIn = setModelParameter(simIn,"CovMetricStructuralLevel","MCDC");

To reduce the amount of output that the code generator provides in the command window, disable the Verbose build (Simulink Coder) parameter.

simIn = setModelParameter(simIn,"RTWVerbose","off");

By default, the model uses normal simulation mode. To analyze code coverage instead of model coverage, set the simulation mode to software-in-the-loop (SIL).

simIn = setModelParameter(simIn,"SimulationMode","software-in-the-loop");

Prepare Model for Code Generation

SIL mode code coverage analysis generates code from the model and then analyzes the generated code. Before you generate code, prepare the model for code generation. For more information, see Prepare a Model for Code Generation (Embedded Coder).

To allow Simulink Coverage to analyze code coverage for the generated code, you must set some additional configuration parameters. For more information, see Code Coverage for Models in Software-in-the-Loop (SIL) Mode and Processor-in-the-Loop (PIL) Mode.

Set the System target file (Simulink Coder) parameter to ert.tlc.

simIn = setModelParameter(simIn,"SystemTargetFile","ert.tlc");

Create a CodeCoverageSettings object and set TopModelCoverage to on.

covSettings = get_param(modelName,"CodeCoverageSettings");
covSettings.TopModelCoverage = "on";
simIn = setModelParameter(simIn,"CodeCoverageSettings",covSettings);

You must also set the hardware implementation parameters for your environment. For this example, set the device type to generic, and set the Enable portable word sizes (Embedded Coder) parameter to on.

simIn = setModelParameter(simIn,"ProdHWDeviceType",...
    "Generic->Unspecified (assume 32-bit Generic)");
simIn = setModelParameter(simIn,"PortableWordSizes","on");

You must configure the model to use a discrete solver because the code generation target ert.tlc does not support variable-step solvers.

simIn = setModelParameter(simIn,"SolverType","Fixed-step");
simIn = setModelParameter(simIn,"SolverName","FixedStepDiscrete");

Analyze Code Coverage

To analyze code coverage, simulate the model by using simIn as the input argument to the sim function. Then, get the coverage data from the covdata property of the Simulink.SimulationOutput object.

simOut = sim(simIn);
### Searching for referenced models in model 'slcoverage_mcdc_logic_cascade'.
### Total of 1 models to build.
### Starting build procedure for: slcoverage_mcdc_logic_cascade
### Successful completion of build procedure for: slcoverage_mcdc_logic_cascade

Build Summary

Top model targets:

Model                          Build Reason                                         Status                        Build Duration
================================================================================================================================
slcoverage_mcdc_logic_cascade  Information cache folder or artifacts were missing.  Code generated and compiled.  0h 0m 25.511s

1 of 1 models built (0 models already up to date)
Build duration: 0h 0m 29.16s
### Preparing to start SIL simulation ...
Building with 'gcc'.
MEX completed successfully.
### Starting SIL simulation for component: slcoverage_mcdc_logic_cascade
### Application stopped
### Stopping SIL simulation for component: slcoverage_mcdc_logic_cascade
### Completed code coverage analysis
covSIL = simOut.covdata;

View Coverage Results

By default, the top-level file name in the generated code is the name of the analyzed model, followed by the file extension for the language for which you generate code. In this example, you generate C code, so the file name is the model name with the .c extension. However, when you use a test harness, you must use the name of the system under test, not the name of the harness model. For more information about the files and functions that code generation creates, see Generated Functions in a Model Reference Hierarchy (Simulink Coder).

generatedFileName = modelName + ".c";

To get the code coverage results in MATLAB, use the cvdata functions. For example, use the decisioninfo function to get decision coverage results, or the conditioninfo function to get condition coverage results. For each metric function, the first element of the output argument is the number of satisfied objectives and the second element of the output argument is the number of total objectives. To get the percentage of coverage objectives satisfied, divide the numbers and multiply by 100.

decisionCovResults = decisioninfo(covSIL,generatedFileName)
decisionCovResults = 1×2

     5    10

decisionCovPercent = decisionCovResults(1)/decisionCovResults(2) * 100
decisionCovPercent = 
50
conditionCovResults = conditioninfo(covSIL,generatedFileName)
conditionCovResults = 1×2

    10    32

conditionCovPercent = conditionCovResults(1)/conditionCovResults(2) * 100
conditionCovPercent = 
31.2500
mcdcResults = mcdcinfo(covSIL,generatedFileName)
mcdcResults = 1×2

     0    12

mcdcCovPercent = mcdcResults(1)/mcdcResults(2) * 100
mcdcCovPercent = 
0

Create and Run a Second Code Coverage Simulation

In the first simulation of the model, you did not provide any data to the multiple Inport blocks, so all of the signals have zero values. For a second simulation, create values for the signals by using the createInputDataset function.

dataSet = createInputDataset(modelName);

The Inport blocks a, b, and c, which are the first three elements in the dataSet array, are all inputs to the first And block. Create values that change the outcome of that block.

dataSet{1} = dataSet{1}.addsample('time',[1 3 5 8]','data',boolean([0 1 1 0])');
dataSet{2} = dataSet{2}.addsample('time',[1 3 5 8]','data',boolean([0 1 0 1])');
dataSet{3} = dataSet{3}.addsample('time',[1 3 5 8]','data',boolean([0 1 1 1])');

Next, load the dataSet values for the Inport blocks in the model. Then, simulate the model a second time to analyze coverage again.

simIn = setModelParameter(simIn,"LoadExternalInput","on");
simIn = setModelParameter(simIn,"ExternalInput","dataSet");
simOut2 = sim(simIn);
### Searching for referenced models in model 'slcoverage_mcdc_logic_cascade'.
### Total of 1 models to build.
### Starting build procedure for: slcoverage_mcdc_logic_cascade
### Generated code for 'slcoverage_mcdc_logic_cascade' is up to date because no structural, parameter or code replacement library changes were found.
### Successful completion of build procedure for: slcoverage_mcdc_logic_cascade

Build Summary

Top model targets:

Model                          Build Reason                             Status          Build Duration
======================================================================================================
slcoverage_mcdc_logic_cascade  Compilation artifacts were out of date.  Code compiled.  0h 0m 3.0322s

1 of 1 models built (0 models already up to date)
Build duration: 0h 0m 3.8829s
### Preparing to start SIL simulation ...
### Starting SIL simulation for component: slcoverage_mcdc_logic_cascade
### Application stopped
### Stopping SIL simulation for component: slcoverage_mcdc_logic_cascade
### Completed code coverage analysis
covSIL2 = simOut2.covdata;

Aggregate Code Coverage Results

Aggregate the code coverage results and then query the coverage results.

covSILAggregated = covSIL + covSIL2;
decisionCovResults2 = decisioninfo(covSILAggregated,generatedFileName);
decisionCovPercent2 = decisionCovResults2(1)/decisionCovResults2(2) * 100
decisionCovPercent2 = 
70
conditionCovResults2 = conditioninfo(covSILAggregated,generatedFileName);
conditionCovPercent2 = conditionCovResults2(1)/conditionCovResults2(2) * 100
conditionCovPercent2 = 
59.3750
mcdcResults2 = mcdcinfo(covSILAggregated,generatedFileName);
mcdcCovPercent2 = mcdcResults2(1)/mcdcResults2(2) * 100
mcdcCovPercent2 = 
25

The code coverage results improved due to the changes to the input signals.

View Statement Coverage Results

When you analyze code coverage, by default, the executioninfo function groups together statement coverage and function coverage into one number. To differentiate these metrics, and to get the results for function call coverage, use the second output argument that executioninfo returns.

[execResults,execStruct] = executioninfo(covSILAggregated,generatedFileName)
execResults = 1×2

    12    12

execStruct = struct with fields:
             isFiltered: 0
      justifiedCoverage: 0
            isJustified: 0
        filterRationale: ''
               function: [1×3 struct]
           functionCall: [1×0 struct]
    executableStatement: [1×9 struct]
               decision: [1×12 struct]

The executioninfo function returns the satisfied coverage outcomes and the total coverage outcomes. Because these numbers are the same, statement coverage is 100%. However, the generated code contains nine executable statements, not twelve. Examine the execution count for each code statement by using the executableStatement field of the structure and the number of times each function executes by using the function field.

execStruct.executableStatement(1)
ans = struct with fields:
           isFiltered: 0
    justifiedCoverage: 0
          isJustified: 0
      filterRationale: ''
                 text: 'Statement executed'
       executionCount: 22
             fileName: 'slcoverage_mcdc_logic_cascade.c'
         functionName: 'slcoverage_mcdc_logic_cascade_step'
       sourceLocation: [1×1 struct]
                 kind: 'decl'
        modelElements: {'slcoverage_mcdc_logic_cascade'}

execStruct.function(1)
ans = struct with fields:
           isFiltered: 0
    justifiedCoverage: 0
          isJustified: 0
      filterRationale: ''
                 text: 'Function entry'
       executionCount: 22
             fileName: 'slcoverage_mcdc_logic_cascade.c'
         functionName: 'slcoverage_mcdc_logic_cascade_step'
       sourceLocation: [1×1 struct]
        modelElements: {'slcoverage_mcdc_logic_cascade'}

The other cvdata functions can also return a structure with additional information for each coverage outcome.

To get an HTML report of coverage results, use the cvhtml function.

cvhtml("silCoverageReport",covSILAggregated);

See Also

| | | | | | |

Topics