主要内容

本页采用了机器翻译。点击此处可查看英文原文。

以编程方式分析 Simulink 模型的代码覆盖率

本示例展示了如何以编程方式分析 Embedded Coder®生成的代码的代码覆盖率。

加载模型并配置覆盖率设置

模型 slcoverage_mcdc_logic_cascade 包含一系列 Logical Operator 模块,实现了足够复杂的逻辑,可以有多个修改后的条件决策覆盖率 (MCDC) 目标。

modelName = "slcoverage_mcdc_logic_cascade";
load_system(modelName)

使用 Simulink.SimulationInput 对象启用覆盖率分析,告诉 Simulink®Coverage™ 将覆盖率数据包含在 Simulink.SimulationOutput 对象中,并将 结构覆盖率等级 参数设置为 MCDC

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

要减少代码生成器在命令行窗口中提供的输出量,请禁用 详尽编译 (Simulink Coder) 参数。

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

默认情况下,该模型使用普通仿真模式。要分析代码覆盖率而不是模型覆盖率,请将仿真模式设置为软件在环 (SIL)。

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

准备模型以进行代码生成

SIL 模式代码覆盖率分析从模型生成代码,然后分析生成的代码。在生成代码之前,请先准备好用于代码生成的模型。有关详细信息,请参阅Prepare a Model for Code Generation (Embedded Coder)

要允许 Simulink Coverage 分析生成代码的代码覆盖率,您必须设置一些额外的配置参数。有关详细信息,请参阅软件在环 (SIL) 模式和处理器在环 (PIL) 模式下模型的代码覆盖率

系统目标文件 (Simulink Coder) 参数设置为 ert.tlc

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

创建 CodeCoverageSettings 对象并将 TopModelCoverage 设置为 on

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

您还必须为您的环境设置硬件实现参数。在本示例中,将设备类型设置为通用,并将 启用可移植字长 (Embedded Coder) 参数设置为 on

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

您必须将模型配置为使用离散求解器,因为代码生成目标 ert.tlc 不支持可变步长求解器。

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

分析代码覆盖率

为了分析代码覆盖率,使用 simIn 作为 sim 函数的输入参量来仿真模型。然后,从 Simulink.SimulationOutput 对象的 covdata 属性中获取覆盖率数据。

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 5.9737s

1 of 1 models built (0 models already up to date)
Build duration: 0h 0m 6.5574s
### 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;

查看覆盖率结果

默认情况下,生成的代码中的顶级文件名是被分析模型的名称,后跟生成代码所用语言的文件扩展名。在这个示例中,您生成的是 C 代码,所以文件名是模型名称加上 .c 扩展名。但是,当您使用测试框架时,必须使用在测系统的名称,而不是框架型号的名称。有关代码生成创建的文件和函数的更多信息,请参阅 Generated Functions in a Model Reference Hierarchy (Simulink Coder)

generatedFileName = modelName + ".c";

要获取 MATLAB 中的代码覆盖率结果,请使用 cvdata 函数。例如,使用 decisioninfo 函数获取决策覆盖率结果,或使用 conditioninfo 函数获取条件覆盖率结果。对于每个度量函数,输出参量的第一个元素是已满足的目标数量,输出参量的第二个元素是目标总数。要计算覆盖率目标的完成百分比,将这些数字相除,然后乘以 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

创建并运行第二个代码覆盖率仿真

在模型的第一次仿真中,您没有向多个 Inport 模块提供任何数据,因此所有信号的值为零。对于第二个仿真,使用 createInputDataset 函数创建信号值。

dataSet = createInputDataset(modelName);

Inport 块 abcdataSet 数组中的前三个元素,它们都是第一个 And 模块的输入。创建能够改变该模块结果的值。

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])');

接下来,加载模型中 Inport 块的 dataSet 值。然后,再次仿真该模型,以再次分析覆盖率。

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 1.4195s

1 of 1 models built (0 models already up to date)
Build duration: 0h 0m 1.6986s
### 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;

聚合代码覆盖率结果

汇总代码覆盖率结果,然后查询覆盖率结果。

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

由于输入信号的改变,代码覆盖率结果得到了改善。

查看语句覆盖率结果

分析代码覆盖率时,默认情况下,executioninfo 函数会将语句覆盖率和函数覆盖率合并为一个数字。要区分这些指标,并获得函数调用覆盖率的结果,请使用 executioninfo 返回的第二个输出参量。

[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]

executioninfo 函数返回已满足的覆盖率结果和总覆盖率结果。因为这些数字相同,所以报表覆盖率为 100%。但是,生成的代码包含九条可执行语句,而不是十二条。使用结构的 executableStatement 字段检查每个代码语句的执行次数,使用 function 字段检查每个函数的执行次数。

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'}

其他 cvdata 函数也可以返回一个结构,其中包含每个覆盖率结果的附加信息。

要获取覆盖率结果的 HTML 报告,请使用 cvhtml 函数。

cvhtml("silCoverageReport",covSILAggregated);

另请参阅

| | | | | | |

主题