以编程方式分析 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 块 a、b 和 c 是 dataSet 数组中的前三个元素,它们都是第一个 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);另请参阅
sim | Simulink.SimulationInput | cvdata | decisioninfo | conditioninfo | mcdcinfo | executioninfo | cvhtml