RTA Knowledge Base

Introduction

Scope

The goal of this application note is to demonstrate the usage of RTA-OS APIs to compute different RTA-OS runtime metrics such as task execution times, CPU load and CPU throughput calculation. There is also a section to explain the use of OS metric monitoring using the corresponding RTA-OS configuration option.

Abbreviations

AUTOSAR: Automotive Open System Architecure

BSW: Basic Software

RTE: Run Time Environment

OS: Operating System

ASW: Application Software

ISR: Interrupt Service Routine

CPU: Central Processing Unit [In this context, it refers to the core processor or individual core when multi-core, of the micro-controller unit]

Tool-chain

The RTA-OS alone is sufficient, as the context is related to the metrics of RTA-OS. RTA-OS comes as part of RTA-CAR from RTA-CAR 6.0.1.

This application note was made using:

RTA-OSv6.2.0

Prerequisites

  • It is assumed that you have the RTA-OS installed, and you must be familiar with AUTOSAR specifications, terminology and methods.
  • You already have a completely configured and a working AUTOSAR project with the ETAS RTA-OS as the operating system.
  • You are familiar with the complete general workflow regarding configuring, code generation, and compiling the AUTOSAR project, comprising BSW, RTE, and OS. (with or without RTA-CAR, according to your use case)

RTA-OS Configuration Prerequisites

The APIs that are illustrated below are either enabled / provide meaningful output when certain configuration items are set for the OS-Port. The detailed dependency is explained in the table below.

OS Configuration ItemDependent APIs

Enable Time Monitoring. Set it to TRUE

  • Os_GetExecutionTime
  • Os_GetTaskElapsedTime
  • Os_GetISRElapsedTime
  • Os_GetIdleElapsedTime
  • Os_GetElapsedTime

Enable Elapsed Time Recording. Set it to TRUE

  • Os_GetTaskElapsedTime
  • Os_GetISRElapsedTime
  • Os_GetIdleElapsedTime
  • Os_GetElapsedTime

Task & ISR Execution Time

The RTA-OS facilitates several APIs using which the execution time of a Task or an ISR can be identified.

There are two ways to implement these APIs.

  1. When you manually write the task bodies and use the RTA-OS to generate the Tasks / ISRs, you can implement the metrics computation within the task body.
  2. When you use the RTA-RTE (ETAS tool-chain) to generate the task body, these files should not be edited further. In such a case you can implement the metrics computation in an ASW, map it to a runnable, and thereby, map the runnable to the Task / ISR in context. Here, care must be taken in setting the order of the runnables within the task as per the use case. It should also be considered that adding additional function calls will have an affect on execution time.

For simplicity, all the examples below shall be shown as an implementation within the task body. (case 1)

Os_GetExecutionTime()

This API returns the net execution time consumed (i.e., excluding all preemption's) since the start of the Task or ISR. Therefore, in order to compute the complete execution time of a Task or ISR, this API needs to be placed at the end of the Task / ISR, before TerminateTask(). Refer the below example.

#include "Os.h"
TASK(OsTask_100ms)
{
	Runnable_1();
	Runnable_2();
	/*	.	*/
  	/*	.	*/
  	/*Last runnable within the task*/
	Runnable_n();    

	/*Compute the execution time of this 100ms task in ticks*/
	VAR(Os_StopwatchTickType, AUTOMATIC) UsedTimeTicks = Os_GetExecutionTime();

	/*Convert to seconds*/  
	VAR(float64, AUTOMATIC) UsedTimeSec = (float64) UsedTimeTicks / OSSWTICKSPERSECOND;

	/*End of task*/
	TerminateTask();
}

Os_GetTaskElapsedTime() or Os_GetISRElapsedTime()

This API returns the cumulative time spent running the specified task or ISR, since StartOS(), or an explicit reset of the accumulated time. As the execution time per iteration is what is desired in most use cases, the same is illustrated below in the example, in combination with the reset APIs.

#include "Os.h"
ISR(MyISR)
{
	ISRHandler_1();
	/*	.	*/
  	/*	.	*/
  	/*Last runnable within the task*/
	ISRHandler_n();    

	/*Compute the execution time of MyISR routine in ticks. Pass the corresponding ISRID as the parameter*/     
	VAR(Os_StopwatchTickType, AUTOMATIC) ExecTimeTicks = Os_GetISRElapsedTime(OsTask_1ms);   
	VAR(float64, AUTOMATIC) ExecTimeOS_MyISR = (float64) ExecTimeTicks / OSSWTICKSPERSECOND ;
	/*Reset the elapsed time*/
	Os_ResetISRElapsedTime(MyISR); 
}

TASK(OsTask_1ms)
{
	Runnable_1();
	Runnable_2();
	/*	.	*/
  	/*	.	*/
  	/*Last runnable within the task*/
	Runnable_n();    

	/*Compute the execution time of 1ms task in ticks. Pass the corresponding TaskID as the parameter*/    	
	VAR(Os_StopwatchTickType, AUTOMATIC)  ExecTimeTicks = Os_GetTaskElapsedTime(OsTask_1ms);   
	VAR(float64, AUTOMATIC)ExecTimeOS_1ms = (float64) ExecTimeTicks / OSSWTICKSPERSECOND ;
	/*Reset the elapsed time*/
	Os_ResetTaskElapsedTime(OsTask_1ms);
	
 	/*End of task*/
	TerminateTask();
}

TASK(OsTask_5ms)
{
	Runnable_1();
	Runnable_2();
	/*	.	*/
  	/*	.	*/
  	/*Last runnable within the task*/
	Runnable_n();    

	/*Compute the execution time of 5ms task in ticks. Pass the corresponding TaskID as the parameter*/     	
	VAR(Os_StopwatchTickType, AUTOMATIC) ExecTimeTicks = Os_GetTaskElapsedTime(OsTask_5ms);   
	VAR(float64, AUTOMATIC) ExecTimeOS_5ms = (float64) ExecTimeTicks / OSSWTICKSPERSECOND ;
	/*Reset the elapsed time*/
	Os_ResetTaskElapsedTime(OsTask_5ms);
	
 	/*End of task*/
	TerminateTask();
}

Os_GetTaskMaxExecutionTime() or Os_GetISRMaxExecutionTime()

This API returns the maximum observed execution time for the Task or ISR. This maximum value is over all complete invocations of the task or ISR, since the StartOS() or an explicit reset using the corresponding reset APIs. You may place this calculation in a slow task to reduce overhead on the faster tasks, as this need not be called during every iteration of the task itself.

#include "Os.h"
TASK(OsTask_100ms)
{
	Os_StopwatchTickType ExecTimeTicks;
	
	/*---------------------*/
	/*Other 100ms functions*/
	/*---------------------*/
	
	/*Compute the max execution time of 1ms task in ticks. Pass the corresponding TaskID as the parameter*/  
	ExecTimeTicks = Os_GetTaskMaxExecutionTime(OsTask_1ms);   
	VAR(float64, AUTOMATIC) MaxExecTimeOS_1ms = (float64) ExecTimeTicks / OSSWTICKSPERSECOND ;
	
	/*Compute the max execution time of MyISR in ticks. Pass the corresponding ISRID as the parameter*/  
	ExecTimeTicks = Os_GetISRMaxExecutionTime(MyISR);   
	VAR(float64, AUTOMATIC) MaxExecTimeOS_MyISR = (float64) ExecTimeTicks / OSSWTICKSPERSECOND ;
	
	/*---optional reset---*/
	Os_ResetTaskMaxExecutionTime(OsTask_1ms);
	Os_ResetISRMaxExecutionTime(MyISR);
		
 	/*End of task*/
	TerminateTask();
}

CPU Load

CPU load is not a well-defined property since it depends on what the application designer wishes to include in the measurement.  As a simple measurement, in RTA-OS you can periodically call Os_GetIdleElapsedTime (followed by Os_ResetIdleElapsedTime) for each core to know the proportion of time during that period that the CPU was in the Idle call-back. Best called from a slow periodic task to minimize overhead and increase accuracy.

Os_GetIdleElapsedTime()

This API returns the cumulative time spent "Idle" since StartOS() or an explicit reset of the accumulated time using the corresponding reset API.

Example
#include "Os.h"
TASK(OsTask_50ms)
{    
	/* Period of this task in ticks	 */
    VAR(float64, AUTOMATIC) TicksPerPeriod = 0.05f * OSSWTICKSPERSECOND; 

    /* How many ticks have been spent in idle */
    VAR(Os_StopwatchTickType, AUTOMATIC) TimeInIdle= Os_GetIdleElapsedTime(OS_CORE_CURRENT);

    /* Idle / Period */
    VAR(float64, AUTOMATIC) PercentInIdle = 100.0f * ((float64)(TimeInIdle / TicksPerPeriod));

    /* Load Percentage = 100% - Idle Percentage */
    VAR(float64, AUTOMATIC) Load = (100.0f - PercentInIdle);

    /* Reset for next call */
    Os_ResetIdleElapsedTime(OS_CORE_CURRENT);  
}

CPU Throughput

A simple definition of CPU throughput would be amount of work done per unit time. Here we can measure it as number of instructions (instruction cycles) the CPU processes per unit time. In our illustration we shall utilize the Os_GetIdleElapsedTime API again.

As the unit is per unit time (a second) you can either calculate it every second or estimate it for a second with the available task. Like before, it is recommended to calculate in a slower task for increased accuracy.

Example
#include "Os.h"
TASK(OsTask_100ms)
{    
    /* How many ticks have been spent in idle */
    VAR(Os_StopwatchTickType, AUTOMATIC) TicksInIdle= Os_GetIdleElapsedTime(OS_CORE_CURRENT);
    
	/*Calculate ticks equivalent to 100ms*/
	VAR(Os_StopwatchTickType, AUTOMATIC)TicksPerCycle = 0.1f * OSSWTICKSPERSECOND;

	/*Ticks used per cycle*/
	VAR(Os_StopwatchTickType, AUTOMATIC) TicksUsed = TicksPerCycle - TicksInIdle;

	/*Time used in seconds per cycle*/
	VAR(float64, AUTOMATIC) TimeUsed = TicksUsed / OSSWTICKSPERSECOND;

	/*Calculate throughput per second. Here x10 as 0.1s is cycle time.*/
	VAR(TickType, AUTOMATIC) ThroughputCPU0 = (TimeUsed * OSCYCLESPERSECOND) * 10;

    Os_ResetIdleElapsedTime(OS_CORE_CURRENT);  
}

OS Metrics Monitoring

RTA-OS facilitates a performance measurement option within itself. This involves enabling the "Collect OS usage metrics" option to TRUE.

With this option enabled, RTA-OS will keep a count of various significant things. This data can be used to measure overall throughput of a system, and suggest architectural changes that might reduce overheads. The list of things that get counted are:

  • No. of times each OS API gets called.
  • No. of times each OS TASK gets activated.
  • No. of times each OS TASK / OS ISR actually starts.
  • No. of times each counter gets advanced.
  • No. of times each OS Error code occurs.
  • ...... and several more.

Refer to the chapter "Performance" in the RTA-OS User Guide that comes with the product for a full list of supported things that gets counted in this feature.

How it works

The count data is recorded in a per-core data structure called Os_Metrics. The fields that are in this structure and the structure type itself is present in the file Os_Metrics.h that is generated as a result of the option. You can monitor the data using a debugger to see the number of times each element gets used.

Moreover, the count values are 32-bit, and will wrap to 0 if it exceeds the range. Therefore, you may choose to reset the data to 0 periodically to avoid overflows and confusing data. This is can be achieved by calling the Os_Metrics_Reset() API.

NOTE : It is also advised to not not enable this option for production software. Utilize this only for testing and development.

More information & Hints

All the above examples and information are intended to familiarize you with the features and APIs within RTA-OS. However, in order to get the full details of all the APIs available, refer the RTA-OS User Guide.pdf and the RTA-OS Reference Guide.pdf documents (found inside an RTA-CAR or RTA-OS installation). The reference guide has the details of all the APIs with examples.

In order to measure the execution time, load, throughput or counts, we have several options. You can either monitor them directly in a debugger during runtime. Else, you could also implement the APIs in runnables within ASW, and create measurement points or map to external communication signals.



  • No labels

4 Comments

  1. float64 MaxExecTimeOS_1ms; floa
    The other screenshots use variable macros e.g. VAR() but this one doesnt.
    1. that is because I have declared it locally. Plus, the default storage class is AUTO as well, correct?

      is this a problem?

  2. UsedTimeSec = UsedTimeTicks
    No type casting, has all the code in this example been tested on VRTA?
    1. yea missed it.. will add the float64 casting.
      I havent, because it isnt a workflow kind of AN! Should I?