TLC Coverage
Using the TLC Coverage Option
The example in Using the TLC Debugger used the debugger to detect a problem in one section of the TLC file. Because a test model may not cover all possible cases, there is a technique that traces the untested cases, the TLC coverage option.
The TLC coverage option provides an easier way to ascertain that the different code parts (not paths) in your code are exercised. To specify TLC coverage tracking, on the Configuration Parameters dialog box, select Start TLC coverage when generating code.
When you initiate TLC coverage, the Target Language Compiler produces a
.log
file for every target file (*.tlc
) used. These
.log
files are placed in project folder created for the model. Each
.log
file contains usage (count) information regarding how many times it
encounters each line during execution. Each line begins with the number of times it is
encountered, followed by a colon, followed by the code.
Example .log File
Here is a log file that results from generating code for the example model
sfcndemo_sdotproduct
, located in the folder
(open). This model inlines the matlabroot
/toolbox/simulink/simdemos/simfeaturessdotproduct
S-function in TLC. The
TLC file that implements the S-function is located in the folder
(open). The matlabroot
/toolbox/simulink/sfuntemplates/tlc_c.log
file for sdotproduct.tlc
is
sdotproduct.log
, which is placed in your build folder. The contents of
sdotproduct.log
are similar to:
Source: E:\matlab\toolbox\simulink\sfuntemplates\tlc_c\sdotproduct.tlc 0: %% 0: %% File : sdotproduct.tlc generated from sdotproduct.ttlc revision 1.6 0: %% 0: %% Abstract: 0: %% Dot product block target file. 1: 1: %implements sdotproduct "C" 1: 0: %% Function: FcnThriftedComplexMultiply ======================================== 0: %% Abstract: 0: %% This function multiplies two numbers in the complex plane. If any of 0: %% the input arguments is only real, then the complex part is passed in 0: %% as "". 0: %% 1: %function FcnThriftedComplexConjMultiply(ar,ai,br,bi,cr,ci,op) void 2: %openfile buffer 0: %% 0: %% Compute Cr = Ar * Br + Ai * Bi 0: %% 2: %assign rhsStr = "%<ar> * %<br>" 2: %if !LibIsEqual(ai, "") && !LibIsEqual(bi, "") 0: %assign rhsStr = rhsStr + " + %<ai> * %<bi>" 0: %endif 2: %<cr> %<op> %<rhsStr>; 0: %% 0: %% Compute Ci = Ar * Bi - Ai * Br 0: %% 2: %if !LibIsEqual(ci, "") 0: %assign rhsStr = "0.0" 0: %if !LibIsEqual(bi, "") 0: %assign rhsStr = "%<ar> * %<bi>" 0: %endif 0: %if !LibIsEqual(ai, "") 0: %assign rhsStr = rhsStr + " - %<ai> * %<br>" 0: %endif 0: %<ci> %<op> %<rhsStr>; 0: %endif 0: %% 2: %closefile buffer 2: %return buffer 0: %endfunction %% FcnThriftedComplexMultiply 1: 1: 0: %% Function: Outputs =========================================================== 0: %% Abstract: 0: %% Y = U0' * U1, where U0' is the complex conjugate transpose of U0 0: %% 1: %function Outputs(block, system) Output 1: %assign sfcnName = ParamSettings.FunctionName 1: /* %<Type> Block (%<sfcnName>): %<LibParentMaskBlockName(block)> */ 0: %% 1: %assign u0re = LibBlockInputSignal(0, "", "", "%<tRealPart>0") 1: %assign u0im = LibBlockInputSignal(0, "", "", "%<tImagPart>0") 1: %assign u1re = LibBlockInputSignal(1, "", "", "%<tRealPart>0") 1: %assign u1im = LibBlockInputSignal(1, "", "", "%<tImagPart>0") 0: %% 1: %assign yre = LibBlockOutputSignal(0, "", "", "%<tRealPart>0") 1: %assign yim = LibBlockOutputSignal(0, "", "", "%<tImagPart>0") 0: %% 0: %% Need to declare a temporary variable for u1re when the output is 0: %% being overwritten and u0im is nonzero 1: %assign outputOverWritesInput = ... 0: ((LibBlockInputSignalBufferDstPort(0) == 0) || ... 0: (LibBlockInputSignalBufferDstPort(1) == 0)) && ... 0: (LibBlockInputSignalIsComplex(0) && LibBlockInputSignalIsComplex(1)) 0: %% 1: %if outputOverWritesInput 0: { 0: %assign dtName = LibBlockOutputSignalDataTypeName(0, tRealPart) 0: %<dtName> tmpVar; 0: \ 0: %assign tmpVar = "tmpVar" 0: %else 1: %assign tmpVar = yre 0: %endif 0: %% 1: %<FcnThriftedComplexConjMultiply(u0re, u0im, u1re, u1im, tmpVar, yim, "=")>\ 0: %% 1: %assign rollVars = ["U", "Y"] 1: %assign rollRegion = LibGetRollRegions1(RollRegions) 0: %% 1: %if LibIsEqual(rollRegion, []) 0: %if outputOverWritesInput 0: %<yre> = tmpVar; 0: %endif 0: %else 0: %% Continue with dot product for nonscalar case 1: %roll idx = rollRegion, lcv = RollThreshold, block, "Roller", rollVars 1: %assign u0re = LibBlockInputSignal(0,"",lcv,"%<tRealPart>%<idx>") 1: %assign u0im = LibBlockInputSignal(0,"",lcv,"%<tImagPart>%<idx>") 1: %assign u1re = LibBlockInputSignal(1,"",lcv,"%<tRealPart>%<idx>") 1: %assign u1im = LibBlockInputSignal(1,"",lcv,"%<tImagPart>%<idx>") 0: %% 1: %assign yre = LibBlockOutputSignal(0,"",lcv,"%<tRealPart>%<idx>") 1: %assign yim = LibBlockOutputSignal(0,"",lcv,"%<tImagPart>%<idx>") 0: %% 1: %<FcnThriftedComplexConjMultiply(u0re, u0im, u1re, u1im, yre, yim, "+=")>\ 0: %endroll 0: %endif 1: %if outputOverWritesInput 0: } 0: %endif 1: 0: %endfunction 1: 0: %% [EOF] sdotproduct.tlc
Analyzing the Results
This structure makes it easy to identify branches not taken and to develop new tests that can exercise unused portions of the target files.
Looking at the sdotproduct.log
file, you can see that the code has not
been used to assign default values to parameters (e.g., the first part of the code for function
FcnThriftedComplexConjMultiply
). Using this log as a reference and
creating models that exercise unexecuted lines, you can make sure that your code is more
robust.