Main Content

Remove Instrumentation Overheads from Execution Time Measurements

To improve execution-time profiling of generated code that runs on deterministic hardware, you can run processor-in-the-loop (PIL) simulations that automatically filter the overheads associated with code instrumentation. You can use the target hardware to estimate the average overhead value or you can specify the value manually.

Note

By default, the software filters the execution times of AUTOSAR Runtime Environment (RTE) code and functions that run within Simulink®, for example, Function Caller blocks.

Approach for Estimating and Removing Instrumentation Overhead

When you set up target connectivity for PIL simulations, you can specify objects or functions for estimating and removing instrumentation overheads from execution-time measurements.

You can:

  • Set up a benchmark program that Simulink runs a specified number of times at the start of a PIL simulation. The benchmark program estimates the overheads for the timer API and for timer freezing and unfreezing, task, and function instrumentation code. Simulink obtains average values for the instrumentation overheads.

  • Manually specify instrumentation overhead values.

During the PIL simulation, Simulink subtracts the instrumentation overhead values from the execution-time measurements. The Simulation Data Inspector and the code execution profiling report display the corrected measurement values.

This figure shows how the uncorrected and corrected timer values correspond to invocations of code sections.

The corrected timer value excludes execution time associated with instrumentation code, RTE code, and function code that runs within Simulink.

To estimate and remove instrumentation overheads from execution-time measurements:

  • If PIL connectivity is set up by using the target namespace, use overhead classes from the target namespace.

  • If PIL connectivity is set up by using the rtw.connectivity.Config class, use functions from the class.

Remove Instrumentation Overheads by Using target Namespace

To provide the software with instrumentation overhead values, use one of these methods:

  • Set up the benchmark program that estimates overhead values.

  • Using overhead classes, manually specify overhead values.

Set Up Benchmark Program

When you set up target connectivity, implement these steps:

  1. Retrieve the target.Processor and target.Timer objects.

    processor = target.get('Processor', myProcessorObjectId);
    timer = target.get('Timer', myTimerObjectId);

  2. Create a target.ProfilingTaskOverhead object.

    taskOverhead = target.create('ProfilingTaskOverhead', ...
                                 'Name', 'Timer Task Overhead');
    taskOverhead.Counter = timer;
    taskOverhead.MinimumBenchmarkIterations = 150;

  3. Associate the overhead values with the processor.

    processor.Overheads = taskOverhead;

Specify Overhead Values

When you set up target connectivity, create overhead class objects and use the Value property to specify your value for the corresponding instrumentation overhead.

  1. Retrieve the target.Processor and target.Timer objects.

    processor = target.get('Processor', myProcessorObjectId);
    timer = target.get('Timer', myTimerObjectId);

  2. Create a target.ProfilingTaskOverhead object.

    taskOverhead = target.create('ProfilingTaskOverhead',...
                                 'Name', 'Timer Task Overhead');
    taskOverhead.Value = 10;
    taskOverhead.Counter = timer;

  3. Create a target.ProfilingFunctionOverhead object.

    functionOverhead = target.create('ProfilingFunctionOverhead',...
                                'Name', 'Timer Function Overhead');
    functionOverhead.Value = 20;
    functionOverhead.Counter = timer;

  4. Create a target.ProfilingFreezingOverhead object.

    freezingOverhead = target.create('ProfilingFreezingOverhead',...
                                     'Name', 'Timer Freezing Overhead');
    freezingOverhead.Value = 30;
    freezingOverhead.Counter = timer;

  5. Associate the overhead values with the processor.

    processor.Overheads = ...
     [taskOverhead, functionOverhead, freezingOverhead];

Remove Instrumentation Overheads by Using Functions from rtw.connectivity.Config

The rtw.connectivity.Config class provides these functions for the removal of instrumentation overheads.

FunctionDescription

activateOverheadFiltering

obj.activateOverheadFiltering (value); activates filtering of instrumentation overheads if value is true. Deactivates overhead filtering if value is false.

isOverheadFilteringActive

obj.isOverheadFilteringActive returns true if instrumentation overhead filtering is activated. Otherwise, returns false.

runOverheadBenchmark

obj.runOverheadBenchmark(value); runs a benchmark program if value is true. Does not run the benchmark program if value is false.

isOverheadBenchmarkExecuted

obj.isOverheadBenchmarkExecuted; returns true if execution of benchmark program is complete. Otherwise, returns false.

setOverheadBenchmarkSteps

obj.setOverheadBenchmarkSteps(steps); specifies number of steps for benchmark program.

getOverheadBenchmarkSteps

steps = obj.getOverheadBenchmarkSteps returns the number of specified steps for the benchmark program.

setOverheads

obj.setOverheads(taskInstrumentationOverhead, functionInstrumentationOverhead, freezingInstrumentation); specifies the overhead values for task, function, and freezing instrumentation respectively.

getOverheads

[taskInstrumentationOverhead, functionInstrumentationOverhead, freezingInstrumentation] = obj.getOverheads; returns overhead values for task, function, and freezing instrumentation respectively.

When you set up target connectivity for PIL simulations, configure the removal of the instrumentation overheads through an rtw.connectivity.Config subclass. For example, this code shows how you can run the benchmark program.

classdef overheadConnectivityConfig < rtw.connectivity.Config
  methods
    function this = customConnectivityConfig(componentArgs)
            
      % Create builder
      targetApplicationFramework = ...
        mypil.TargetApplicationFramework(componentArgs);
      builder = rtw.connectivity.MakefileBuilder(componentArgs, ...
        targetApplicationFramework, '');
            
      % Create launcher
      launcher = mypil.Launcher(componentArgs, builder);
            
      % Set up communication       
      hostCommunicator = rtw.connectivity.RtIOStreamHostCommunicator(...
                         componentArgs, ...
                         launcher, ...
                         rtiostreamLibTCPIP);     

      % Call super class constructor to register components
        this@rtw.connectivity.Config(componentArgs,...
                                     builder,...
                                     launcher,...
                                     hostCommunicator);
            
      % Register hardware-specific timer, which enables
      % code execution profiling. This example uses a 
      % timer for the host platform.
      timer = coder.profile.crlHostTimer();
      this.setTimer(timer);

      % Specify removal of profiling instrumentation overheads
      this.activateOverheadFiltering(true);
      this.runOverheadBenchmark(true);
      this.setOverheadBenchmarkSteps(50);

    end
  end
end

Instead of running the benchmark program, you can use setOverheads to provide your values for instrumentation overheads.

    ...

    % Remove instrumentation overhead using manually specified values
    this.activateOverheadFiltering(true);
    this.setOverheads (taskInstrumentationOverhead, ...
      functionInstrumentationOverhead, freezingInstrumentation);

    ...

Retrieve Benchmark Results

When a PIL simulation is complete, you can retrieve benchmark results from the variable that you specify in the Code Generation > Verification > Workspace variable field (CodeExecutionProfileVariable), for example, myExecutionProfile.

benchmarkResults = myExecutionProfile.getOverheadBenchmarkData();

benchmarkResults is a structure that contains code instrumentation overhead values.

>> benchmarkResults
 ans = 
 struct with fields:
 TimestampOverhead: [1×1 struct]
 TaskOverhead: [1×1 struct]
 FunctionOverhead: [1×1 struct]
 FreezingOverhead: [1×1 struct]

>> benchmarkResults.TaskOverhead
 ans = 
 struct with fields:
 Data: [1×100 uint64]
 NumSamples: 100
 Average: 45.2800

See Also

| | | |

Related Topics