Main Content

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 matlabroot/toolbox/simulink/simdemos/simfeatures (open). This model inlines the sdotproduct S-function in TLC. The TLC file that implements the S-function is located in the folder matlabroot/toolbox/simulink/sfuntemplates/tlc_c (open). The .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.

Related Topics