\chapter{Mapping} \label{chapter:mapping} % {{{ Mapping Intro Systems are analyzable on different levels of abstraction as shown in \autoref{fig:trace_event_levels}. Depending on the use case, one or another level is more sufficient to perform the required analysis. For example, a hardware designer does not care about task states while a system engineer is usually not interested in voltage levels of transistors in memory. For the timing analysis of an embedded system a trace on system level is required because timing requirements are usually specified for system entities such as tasks or signals. Hence, system level traces contain the information necessary to validate an application with respect to its timing behavior. A trace long enough, so that all relevant entities appear with sufficient frequency for the timing analysis, is required. For example, at least two task instances must be activated in one trace to calculate the activate-to-activate time. Additionally, it is important not to influence the timing of an application by trace measurement. Consequently, the only sufficient trace technique for the timing analysis of embedded systems is hardware tracing according to \autoref{tab:trace_tool_overview}. \begin{figure}[] \centering \centerline{\includegraphics[width=\textwidth]{./media/mapping/concept_measurement_btf.pdf}} \caption[Hardware to \gls{btf} trace basic idea]{Hardware tracing records events on hardware level. This is not sufficient for the timing analysis of an embedded system. Thus, it is necessary to transform the hardware events to system events. This requires two steps. In the first step hardware events are transformed to software events. This step is done by the trace software and requires the application binary. The next transformation step produces a trace on system level, e.g.\ in the \gls{btf} format. An \gls{orti} file as well as additional information that can for example, come from a timing model file (\gls{rte}) are required for this step.} \label{fig:mapping_concept} \end{figure} Hardware tracing records events on hardware level. As stated above this level is not sufficient for the timing analysis of an embedded system. Thus, it is necessary to transform hardware events to system events as shown in \autoref{fig:mapping_concept}. Two steps are required for this transformation. Hardware level events must be transformed into software level events which are then further processed into system level events. The first step is done by the trace software. It is capable of analyzing and interpreting the hardware events that are recorded from the processor. Via the application binary files it is possible to map the raw memory addresses contained in the hardware events to the corresponding symbols of the real application as depicted in \autoref{fig:hardware_software_idea}. \begin{figure}[] \centering \centerline{\includegraphics[width=\textwidth]{./media/mapping/hardware_software_idea.pdf}} \caption[Hardware event to software event idea]{The trace software is capable of transforming a hardware level event to a software level event. This involves for example, changing memory addresses with the actual symbol names based on the application binary (\gls{elf} file). Further actions may be required depending on the trace device. Note that the displayed hardware event is just a generalization, the actual structure can be different depending on the trace device vendor.} \label{fig:hardware_software_idea} \end{figure} Depending of the trace device further steps may be required. For example, some trace devices produce timestamps, relative to the previous event which must then be transformed into absolute timestamps. Another example are program flow traces. Hardware level program flow events are usually only recorded for instructions that change the flow of an application as described in \autoref{subsection:hardware_tracing}. Only with the application binary it is possible for the software to reconstruct a complete program flow trace. Based on the software level trace, a system level trace can be generated in the next step. A suitable system level trace format is \gls{btf} which is described in \autoref{chapter:btf}. It is capable of representing the behavior of an application in a way that is eligible for its timing analysis. Different additional information, e.g.\ the \gls{orti} file is required to execute the transformation from software to system level trace. % }}} % {{{ Mapping Proceeding \section{Mapping Proceedings} Transformation from hardware to software level is done by the trace software. Corresponding to the composition of an on-chip trace device it creates two types of traces on software level: a data trace and a function trace. Let $i$ be an index in $\mathbb{N}_{0}$ denoting an individual event occurrence. Then a data event can be defined as an octuple \begin{equation} \label{eq:data_event} d_{i} = (t_i, \pi_i, a_i, v_i, c_i) \end{equation} where $t_i \in \mathbb{N}_{0}$ is the timestamp in nanoseconds, $\pi_i$ is the name of the accessed variable, $a_i \in \{R, W\}$ is the way in which the variable is accessed either $R$ for read or $W$ for write, $v_i \in \mathbb{N}$ is the value that was read or written and $c_i$ is the core name on which the access has occurred. Consequently, a data trace can be defined as a sequence of data events where $n \in \mathbb{N}_{0}$ is the number of events in the trace. \begin{equation} \label{eq:data_trace} D = (d_1, d_2, \dots, d_n) \end{equation} Let $j$ be an index in $\mathbb{N}_{0}$ denoting an individual event occurrence. Then a function event can be defined as a quadruple \begin{equation} \label{eq:function_event} f_j = (t_j, \pi_j, \theta_j, c_j) \end{equation} where $t_j \in \mathbb{N}_{0}$ is the timestamp in nanoseconds, $\pi_j$ is the name of the accessed function, $\theta_j \in \{A, \Omega\}$ indicates whether the function has started ($A$) or terminated ($\Omega$), and $c_j$ is the core name on which the function event has occurred. After that a function trace can be defined as a sequence of function events where $m \in \mathbb{N}_{0}$ is the numbers of events in the trace. \begin{equation} \label{eq:function_trace} F = (f_1, f_2, \dots, f_m) \end{equation} Based on \autoref{eq:btf_trace}, \autoref{eq:data_trace}, and \autoref{eq:function_trace} the goal is to describe a function $g$ so that \begin{equation} g: (D,\, F) \rightarrow B, \end{equation} where the timestamps $t$ of the events in $D$, $F$, and $B$ are relative to the same point in time. However, $D$ and $F$ alone are not sufficient for the transformation from software to hardware level because of three reasons. Firstly, the events on software level do not provide enough information to decide which variable maps to a certain entity on system level. For example, the state of each task is stored in a certain variable. Whenever the state changes, this variable changes too and a data event is generated. However, the transformation function does not know that the variable maps to the state of a task. Because of that the \gls{orti} file described in \autoref{subsection:osek_oil_and_orti} is required. Via this file it is possible to relate variables to the corresponding system objects. Secondly, not all entity types specified by \gls{btf} for example, runnables and signals are included in the \gls{orti} file. The former are included in the function trace, the latter in the data trace. But if the transformation function is not able to distinguish regular functions from runnables and regular variables from signals this information cannot be used. Thus, it is necessary to provide a list of those entities to the transformation function. Finally, it is necessary to keep track of the internal state of an application. If the \gls{orti} file is available it can be detected that a certain task has changed its state. Consequently, a \gls{btf} event must be generated. Without the knowledge about the previous task state however, it is not possible to decide which task action has occurred. If the task changes into the running state, this could mean that the task has started for the first time resumed from ready state or continued to run after polling a resource. Because of this reasons the function $g$ must be redefined as \begin{equation} g': (D,\, F,\, o,\, l,\, S) \rightarrow (B,\, S') \end{equation} where $o$ is the \gls{orti} file of the traced application, $l = (l_r,\, l_s)$ is a tuple that contains a list of runnables $l_r$ and a list of signal names $l_s$, and $S$ and $S'$ are the system states before and after the transformation. The information must be part of the system state $S$ is discussed in the next sections. % }}} % {{{ ORTI Mapping \section{ORTI Mappings} \textbf{Task} entities are capable of executing twelve actions according to \autoref{fig:process_state_chart} plus the additional notification event if the \gls{mta} limit is exceeded. The lifecycle of a task entity starts with its activation. An \textbf{activation} can be detected via the \gls{orti} \emph{task status} attribute. If no other task instance of the same task entity is active in the system, a task whose state changes to ready is activated. However, this does not work if a task instance of the same task is already active in the system. This can happen if multiple task activations are allowed by the \glsdesc{osekcc}. In case of a \gls{mta} the corresponding \gls{osek} \emph{task status} attribute already indicates an active state (any state that is not suspended) and will not change to ready again. Consequently, another way to detect task activations is required. Via the \gls{orti} \emph{currentactivations} attribute, the number of open activations for each task can be detected. Whenever this attribute is incremented, a new task activation \gls{btf} event must be created. Therefore, it is necessary to keep track of the number of activations for each task entity in the system. Only if the previous number of activations for a task is known, it is possible to decide whether the value is incremented or decremented when a new data write event occurs. Thus, the number of current activations for each process is a relevant information and must be part of the system state $s$. Since tasks have a lifecycle it is necessary to keep track of the instances for each task entity. Whenever a new task is activated the instance counter must be incremented and the counter value is assigned to the task. The same procedure is necessary for all other entities that have a lifecycle. The latest instance counter value for each entity must be available in the system state $s$ to create correct \gls{btf} events. Additionally, it is necessary to add newly created tasks to a list of task instances active in the system. When a task's lifecycle ends, i.e., the task terminates, it is removed from this list. A \textbf{stimulus} is required to activate a task. Stimuli can be \textbf{triggered} by process and by simulation entities. A stimulus triggered by another process represents an \glsdesc{ipa} (\gls{ipa}). An \gls{ipa} is implemented via the \lstinline{ActivateTask} service routine. The \gls{orti} \emph{servicetrace} attribute can be used to detect when this routine is executed. Whenever the \lstinline{ActivateTask} routine is entered and a task is running on the same core a stimulus event is created with the task as the source entity. Alarms are the second way to activate tasks. The \emph{alarmtime} attribute indicates how many ticks are left until an alarm expires. The \gls{orti} file also contains the action that is executed by an alarm. Thus, a stimulus can be triggered whenever an alarm that activates a task reaches an \emph{alarmtime} value of zero. \begin{table}[] \centering \begin{tabular}{r|l l} Action & ORTI attribute & System state \\ \hline trigger (ipa) & servicetrace (ActivateTask) & running task \\ trigger (alarm) & alarmtime & - \\ \end{tabular} \caption[Stimulus event mapping]{In \gls{btf}, a stimulus must be triggered so that it can activate a task. On target a task can be triggered via an \gls{ipa} or by an alarm. The first can be detected via the \emph{servicetrace} attribute, while the latter is indicated if the \emph{alarmtime} attribute reaches the value zero.} \label{tab:stimulus_mapping} \end{table} A triggered stimulus must be added to the system state. Later, when the actual task activation is executed by the \gls{os} the latest stimulus is removed from the system state and used to create a correct \gls{btf} event. \autoref{tab:stimulus_mapping} summarizes how stimulus events are detected. A \textbf{task} \textbf{start} event occurs if a task which was previously active changes to running. There are two cases for which preempt and resume actions must be created. The first case is a normal state change that can be detected via the \emph{task status} attribute. A task is \textbf{preempted} if the state changes from running to ready and \textbf{resumed} if the state changes from ready to running. However, the task state is not updated by the \gls{os} when a task is preempted by an \gls{isr}. Consequently, a task preempt event must also be created, if the \emph{runningisr2} attribute indicates that a new \gls{isr} is running on the core and a resume event must follow once the \gls{isr} terminates execution. A task \textbf{terminate} event occurs if a running task changes into the suspended state. The previous state must not be known because a task can only be terminated from the running state. However, there is a special case for task terminate events. As mentioned in \autoref{subsection:osek_architecture}, a task with pending activations switches directly into the ready state, after the current instance terminates. To work around this problem it is necessary to detect when a certain task instance executes the \lstinline{TerminateTask} service routine via the \emph{servicetrace} attribute. If this happens a flag in the system state must be set to indicate that the respective task instance has been terminated. Whenever a task changes from running to ready this flag must be checked to decide whether the corresponding event is a preemption or a termination. A \textbf{wait} event occurs if a running task waits for an event that is not set. In this case the \gls{os} will change the task state to waiting and the task is removed from the core. A \textbf{release} event occurs once the event is set and the \gls{os} changes the task state to ready. \begin{code} \begin{lstlisting}[caption={[Resource polling] The \gls{btf} polling state indicates that a process is actively waiting for a resource. This listing shows how this might be impolemented in C.}, label={listing:resource_polling}] TASK(EngineManager) { /* Wait actively until EngineResource becomes available. */ while(GetResource(EngineResource) != E_OK); engineRPM = calculateEngineRPM(); ReleaseResource(EngineResource); TerminateTask(); } \end{lstlisting} \end{code} \textbf{Poll} actions are more difficult to detect, since they are not directly related to a concept specified by \gls{osekos}. The idea of the \gls{btf} polling state is to indicate that a task is actively waiting for a resource. In code this can be implemented via a loop in which a resource is requested repeatedly until it becomes available as shown in \autoref{listing:resource_polling}. Via \emph{servicetrace} and \emph{lasterror} it can be detected that a process has requested a locked resource: the \emph{servicetrace} attribute indicates when the \lstinline{GetResource} service routine is called and \lstinline{E_OS_RESOURCE} is written to the \emph{lasterror} attributed in case the resource is locked. However, a single request does not necessarily mean that a change into the polling state is happening. Instead a task might just execute one code segment, if the resource is available and a different one, if it is not. Therefore, it is necessary to set a \emph{previous request} flag for a task instance that has requested a locked resource once. If another request follows in the same running interval a poll event is generated. Once there are no more requests, the last request must have been successful and a run event is created to indicated the state change from polling to running. Then the previous request flag must be cleared. A \textbf{park} action must be created if a task that is in polling state is changed into the ready state. Next, it is necessary to detect resource state changes of the resource which the parking task has been polling. If the respective resource changes into an unlocked state, a \textbf{release\_parking} event is created. On the other hand, if the resource stays locked and the task changes back into running state, a \textbf{poll\_parking} event is required. The \textbf{mtalimitexceeded} notification event is the last task event that must be detected. This event is created, if a task activation gets triggered, but no actual task instance is added to the system. An \gls{osek} compliant \gls{os} writes an \lstinline{E_OS_LIMIT} error into the \emph{lasterror} attribute, if a task activation is triggered, but the maximal \gls{mta} value is already reached. To create a valid \gls{btf} event it is necessary to know for which task entity the error is created. Since \gls{orti} does not provide this information the creation of \emph{mtalimitexceeded} events is not feasible. \autoref{tab:task_mapping} gives an overview of the task mapping. \begin{table}[] \centering \begin{tabular}{r|l l} Action & ORTI attribute & System state \\ \hline activate & currentactivations & currentactivations, last stimulus \\ start & state (running) & state (active) \\ resume & state (running) & state (ready) \\ resume & runningisr2 & running task \\ preempt & state (ready) & task not terminated \\ preempt & runningisr2 & running task \\ terminate & state (suspended) & active tasks \\ terminate & state (ready) & task terminated \\ wait & state (waiting) & - \\ release & state (ready) & state (waiting) \\ poll & lasterror & servicetrace, previous request \\ run & servicetrace & state (polling) \\ park & state (ready) & state (polling) \\ poll\_parking & state (running) & state (parking) \\ release\_parking & resource state & state (parking) \\ mtalimitexceeded & lasterror & entity cannot be detected \\ \end{tabular} \caption[Task event mapping]{Different pieces of information are required to detect all possible task actions. The states in the \gls{orti} attributes column are \gls{osek} task states while the states in the system information column are \gls{btf} process states. The previous state is necessary to create correct events. For example, a task state change to running could mean a \gls{btf} start, resume or run event. For some actions, it is necessary to use multiple approaches to detect them. For example, a task terminate event happens if the \gls{osek} state of changes to suspended. However, if another entity of the same task is already activated, a change to suspended does not occur. To catch this case it is necessary to set a \emph{task terminated} attribute for a task instance when it calls the \lstinline{TerminateTask} service routine.} \label{tab:task_mapping} \end{table} \begin{table}[] \centering \begin{tabular}{r|l l} Action & ORTI attribute & System state \\ \hline activate & - & - \\ start & runningisr2 & \gls{isr} stack \\ resume & runningisr2 & \gls{isr} stack \\ preempt & runningisr2 & \gls{isr} stack \\ terminate & runningisr2 & \gls{isr} stack \\ \end{tabular} \caption[\gls{isr} event mapping]{The \emph{runningisr2} attribute is used to detect basic \gls{isr} actions. Because \glspl{isr} are not allowed to wait for events, waiting state related actions must not be created. All other actions can be detected in the same way as for task instances as shown in \autoref{tab:task_mapping}.} \label{tab:isr_mapping} \end{table} \textbf{\glspl{isr}} and tasks share the same \gls{btf} state model. However, \gls{osek} does not specify a detailed state model for \glspl{isr} as it does for tasks. Consequently, the basic process actions activate, start, resume, preempt, and terminate are detected differently compared to task actions as shown in \autoref{tab:isr_mapping}. \glspl{isr} are not allowed to wait for events. Therefore, waiting related process state transitions must not be considered. The detection of semaphore polling events works equally to task events and is therefore not discussed again. An \glsdesc{isr} is triggered by a hardware interrupt. This means if the hardware detects a certain condition, e.g., an \gls{io} pin state changes from high to low, the program flow is interrupted and a certain code section that is mapped to this interrupt is executed. Depending on the trace device, it may or may not be feasible to detect the activation of an interrupt via the corresponding \gls{isr} control register. In the former case, it is possible to create a stimulus and the resulting activate event by detecting when the interrupt activate bit is set in the corresponding control register. Otherwise, the \textbf{activate} event must be created when the \gls{isr} changes into the running state for the first time. In this case trigger, activate, and start event are all created with the same timestamp. \begin{figure}[] \centering \centerline{\includegraphics[width=\textwidth]{./media/mapping/isr_stacking.pdf}} \caption[Running \gls{isr} stacking]{A stack can be used to track the active \glspl{isr} in a system. This is necessary to create appropriate \gls{btf} events. For example, the event when \emph{isr\_foo} is set as the running \gls{isr}, is different, depending on the current state of the stack. If the \gls{isr} is already on the stack, a resume event must be created, otherwise a start event.} \label{fig:isr_stacking} \end{figure} The currently running category two \gls{isr} is indicated by the \emph{runninngisr2} \gls{orti} attribute. Each \gls{isr} has an unique \gls{id} that is written into the variable, if the respective entity is running. Otherwise runningisr2 is zero which indicates that no \gls{isr} is active. Mapping from \gls{id} to name is included in the \gls{orti} file. If \emph{runningisr2} changes to the \gls{id} of a certain \gls{isr}, it is not possible to decide whether this instance runs for the first time or whether it is resumed, after it has been preempted by an \gls{isr} with higher priority as shown in \autoref{fig:isr_stacking}. Therefore, it is necessary to keep track of the active \gls{isr} instances in the system, e.g.\ via a stack. Whenever the value of \emph{runningisr2} changes it is checked whether the corresponding \gls{id} is already on the stack. If so, the \gls{isr} was already running and has been \textbf{preempted}. Consequently, the \gls{isr} that caused the preemption has terminated and must be popped off the stack. The \gls{isr} that has been preempted must be \textbf{resumed}. The other case is that the new \gls{isr} has not been running yet, i.e.\ is not on the stack. This means that the \gls{isr} on top of the stack, if there is one gets \textbf{preempted} and the new \gls{isr} is \textbf{started} and pushed on the stack. If \emph{runningisr2} becomes zero the last \gls{isr} is popped of the stack and \textbf{terminated}. As the name indicates, \emph{runningisr2} is only written for category two interrupt routines. Regular \glspl{isr} are not managed by the \gls{os} and therefore not detectable via \gls{orti} attributes. Instead function trace must be utilized to detect when a category one \gls{isr} is started or terminated. To map the function names to actual \gls{isr} entities, a list of category one \glspl{isr} is required. If such a list is available, the proceeding is the same as described above. \begin{table}[] \centering \begin{tabular}{r|l l} Action & ORTI attribute & System state \\ \hline start & - & running process \\ terminate & - & running process \\ suspend & task state & running process, process runnables \\ resume & task state & running process, process runnables \\ \end{tabular} \caption[Runnable event mapping]{Runnable start and stop events can be detected via function tracing. The source entity for a runnable event is the process in whose context the runnable is executed. A runnable is suspended when the corresponding process is preempted. If the process resumes, the runnable is resumed, too. One runnable can be called in the context of another runnable. This means multiple runnables can be running within the same process context at the same point in time. If this is the case, all running runnables must be suspended and resumed.} \label{tab:runnable_mapping} \end{table} \textbf{Runnable} actions are detectable via function events. Start and terminate events must be created for function entry and function exit events. A program flow trace contains the information about all functions in the system. A list of runnable entity names is thus required to check whether a function is a runnable or not. Suspend events must be created, if the process context in which a runnable is running is preempted and a resume event is required if the corresponding process resumes. This means that whenever a process is deallocated, a potentially active runnable must be suspended. Once the process is reallocated the runnable also resumes. Additionally, runnables can be nested, i.e.\ one runnable can be executed by another runnable. If this happens it is important to suspend and resume all running runnables, if the corresponding process is preempted and resumed. \begin{table}[] \centering \begin{tabular}{r|l l} Action & ORTI attribute & System state \\ \hline write & - & running process \\ read & - & running process \\ \end{tabular} \caption[Signal event mapping]{Signals can be read or written. To create valid \gls{btf} signal events, it is necessary to know which process is currently running on the core, i.e., which process executed the read or write.} \label{tab:signal_mapping} \end{table} \textbf{Signal} events are detectable via data events. To decide which data event corresponds to a signal event a list of signal names must be available. With this list it can be decided if a certain data event results in a signal event or not. The source entity for signal read events is the currently running process as shown in \autoref{tab:signal_mapping}. If no process is running an entity of type simulation can be used to set the value of the signal. \textbf{Event} actions are easily detectable via the \emph{servicetrace} attribute. Via this attribute it is possible to create set, wait, and clear event actions. However, in order to create valid event actions, it is also necessary to know the event entity that relates to the respective action. \gls{orti} does not specify event related attributes. Because \gls{orti} does not specify OS event related attributes, it is not possible to create valid actions for this entity type. \begin{table}[] \centering \begin{tabular}{r|l l} Action & ORTI attribute & System state \\ \hline ready & resource object & - \\ lock & resource locker & - \\ unlock & resource locker & - \\ full & resource locked, servicetrace & - \\ overfull & resource locked, servicetrace & - \\ \end{tabular} \caption[Resource event mapping]{\gls{osek} resources can only be locked or unlocked which means they do not support all semaphore actions. Lock and unlock actions can be detected via the \gls{orti} locker attribute. Full and overfull events are created if an already locked resource is requested again. This is detectable via the \emph{servicetrace} attribute. The resource for which the \emph{resource locked} attributed was read the last time is the resource for which the error has occurred.} \label{tab:resource_mapping} \end{table} \begin{table}[] \centering \begin{tabular}{r l l} Action & ORTI attribute & System state \\ \hline requestsemaphore & resource locker & - \\ assigned & resource locker & - \\ waiting & resource locked & - \\ released & resource locker & previous locker \\ \end{tabular} \caption[Semaphore process event mapping]{Via the resource locker attribute it is possible to detect if a resource has successfully requested a semaphore. The \emph{resource locker} attribute changes to the no task \gls{id} if the resource is no longer locked. For this case it is necessary to know the task that has previously locked the resource in order to create the correct release event. Waiting actions can be created by detecting data read events to the \emph{resource locked} attribute.} \label{tab:semaphore_process_mapping} \end{table} \textbf{Resource} entities must be initialized via the ready action before they can be used in a \gls{btf} trace. This can be done at the beginning of a trace with the timestamp zero. The \gls{orti} file contains a list of all resource objects that are part of the application. Since resources can only be locked or unlocked, they cannot change into the semaphore used state. Consequently, only the state transition actions shown in \autoref{tab:resource_mapping} can occur for resource events. Additionally, only a subset of the process semaphore actions are required to represent the behavior of resources. Via the \gls{orti} \emph{resource locker} attribute it is possible to detect by which task entity a resource is locked. This means a lock event can be generated whenever the \gls{id} of a certain task is written to this attribute. On the other hand, an unlock event is created when \emph{resource locker} indicates that the respective entity is currently not locked by any task. Moreover, it is necessary to assign a process to the locked resource once it is locked by the task and to release it when the resource is released as shown in \autoref{tab:semaphore_process_mapping}. Full and overfull actions are created when a locked resource is polled by a process. The semaphore waiting action is used to indicated the identity of the polling process. As shown above, it is possible to detect whether a process is polling a resource via the \emph{servicetrace} and \emph{lasterror} \gls{orti} attributes. \emph{Lasterror} is set to \lstinline{E_OS_ACCESS} in case a resource is already locked. The resource for which the polling occurs is detectable via the \emph{resource locked} attribute. Whenever a certain resource is requested the \gls{os} will read this attribute to decide whether a request is allowed or not. % }}} % {{{ OS Specific Mapping \section{OS Specific Mappings} It is not feasible to create all \gls{btf} events relying solely on the \gls{orti} file. For example, it is necessary to have a list of runnable and signal names in order to create valid events for those entity types. But even for entities that are supported by the \gls{orti} interface not all events can be generated. It is possible to detect if the activation limit of a task is exceeded however, it is not possible to determine for which task entity this happens. Nevertheless, even though not all events are detectable via \gls{orti} alone, an \gls{osekos} stores the information of interest internally. During a task activation the \gls{os} must decide whether the \gls{mta} limit is reached or not. To do so it is necessary to compare the current amount of pending activations to the value of maximal allowed activations. Consequently, the \gls{os} has to read certain information from memory which results in data trace events. Based on this argument all other events can be reconstructed, if the corresponding \gls{os} specific operations are known. On the downside, it is no longer possible to rely on a standardized interface like \gls{orti}. This means the algorithm that does the transformation must be customized depending on the \gls{os}. In this section the adaptations required to create a \gls{btf} trace for the \gls{osek} compliant Erika Enterprise (\gls{ee}) \glsdesc{os} \cite{erika} are shown. In \autoref{section:evaluation_test_bench} the reasons for choosing \gls{ee} are discussed. \textbf{Task} \emph{mtalimitexceeded} events cannot be created based on \gls{orti} alone because the task entity for which the event occurs is not detectable. One way to get this information is to remember which task's \emph{currentactivations} attribute was read the last time. The \gls{os} has to decide whether a task instance can be created once an activation is triggered. To do so it compares the maximum allowed activations with the current number of activations of a task. In other words, the \gls{os} reads the \emph{currentactivations} attribute for the task that should be activated. If the \gls{mta} limit is exceeded an error code is written. \begin{figure}[] \centering \centerline{\includegraphics[width=\textwidth]{./media/mapping/mtalimitexceeded.pdf}} \caption[Call stack for inter-core process activation]{A \emph{mtalimitexceeded} event must be created if the \lstinline{E_OS_LIMIT} error is set via the \emph{lasterror} \gls{orti} attribute. However, this is not correct for Erika Enterprise multi-core applications. For a failing inter-core inter-process activation the error code is written two times, once on the source and once on the target core. Therefore, special care must be taken, so that the \gls{btf} event is created only once.} \label{fig:mtalimitexceeded} \end{figure} \begin{code} \begin{lstlisting}[caption={[Task activations limit exceeded] Erika Enterprise keeps track of the remaining activations that are allowed for a task entity. If the value is zero and another activation occurs an \lstinline{E_OS_LIMIT} error is set.}, label={listing:mtalimitexceeded}] if ( EE_th_rnact[TaskID] == 0U ) { ev = E_OS_LIMIT; } else { /* Do activation. Code removed for clarity. */ ev = E_OK; } if (ev != E_OK ) { EE_ORTI_set_lasterror(ev); EE_oo_notify_error_ActivateTask(TaskID, ev); } \end{lstlisting} \end{code} As it turns out this approach is not sufficient for multi-core systems. Activation of a task entity by a task on another core via \lstinline{ActivateTask} is implemented by a \glsdesc{rpc} (\gls{rpc}) as shown in \autoref{fig:mtalimitexceeded}. The \gls{rpc} triggers an \gls{isr} on the other core which performs the required action. In case of an inter-process activation the \lstinline{ActivateTask} routine is executed again, but this time on the core the target task is allocated to. If the \gls{mta} limit of the task is exceeded an \lstinline{E_OS_LIMIT} error event is written and a \lstinline{mtalimitexceed} event is created. However, the remote procedure call is notified by the remote \gls{isr} once the service routine has finished. The corresponding error code is also returned back to the initial core and written to the \emph{lasterror} attribute. The resulting problem is that the transformation algorithm would create another \emph{mtalimitexceeded} event based on the last read from the pending activations variable on the initial core which is not correct. A way to work around this problem can be derived by looking at a part of the source code of the \lstinline{ActivateTask} implementation shown in \autoref{listing:mtalimitexceeded}. It shows that \gls{ee} keeps track of the remaining activations of each task in an array called \lstinline{EE_th_rnact}. If the field for a specific task becomes zero, an \lstinline{E_OS_LIMIT} error is written. This means if a task should be activated on one core and this activation fails due to too many pending activations this will become clear by a data read event to \lstinline{EE_th_rnact} directly followed by a write event to the \emph{lasterror} attribute. For a remote activation there are multiple other data events between the error and the previous read to \lstinline{EE_th_rnact}. Therefore, no incorrect \emph{mtalimitexceeded} event is created. \begin{figure}[] \centering \centerline{\includegraphics[width=\textwidth]{./media/mapping/deltaqueue.pdf}} \caption[Alarm delta queue implementation]{\gls{ee} implements alarms via a delta queue. There is one queue, containing of the corresponding alarms, for each counter. Each alarm has a delta value that indicates after how many ticks in relation to the previous alarm it must be executed. Only the delta of the first alarm in the queue must be decremented for each counter tick. If an alarm expires it is removed from the queue, and inserted again in case it is cyclic. In this example Alarm 2 expires after three ticks. Since Alarm 5 has a delta of zero it expires at the same counter cycle. Alarm 4 expires after six cycles, i.e.\ the sum of its own and all previous deltas. } \label{fig:deltaqueue} \end{figure} \begin{table}[] \centering \begin{tabular}{r|l l} Action & Variable & Additional Information \\ \hline mtalimitexceeded & lasterror & previous data read event \\ trigger (alarm) & alarm action type & \gls{orti} \\ \end{tabular} \caption[OS task and stimulus event mapping]{Via \gls{orti} it is not possible to detect for which task an \lstinline{E_OS_LIMIT} event has been created. However, the data read event before this error can be used to get this information. Additionally, alarm trigger events cannot be created via the \emph{alarmtime} attribute in Erika Enterprise, because it is not implemented in an \gls{osek} compliant way. Instead, read events to the \lstinline{ActionType} attribute of an alarm can be used to detect when a stimulus event must be created.} \label{tab:task_mapping_os} \end{table} \textbf{Stimulus} events must be created for inter-process and alarm activations as shown in \autoref{tab:stimulus_mapping}. An alarm activation stimulus is created if the \gls{orti} \emph{alarmtime} attribute becomes zero. However, \gls{ee} \gls{os} does not update this attribute in compliance with the \gls{osek} specification \cite{erikaaltick}. Hence, another technique is required to detect alarm events. \gls{ee} keeps track of all active alarms in a delta queue as shown in \autoref{fig:deltaqueue}. There is one queue for each counter. Whenever a counter is incremented the delta of the first element in the queue is decremented. If the delta of the first alarm in the queue becomes zero this alarm and all following alarms with a delta of zero expire and the corresponding actions are executed. For an expiring alarm the \gls{os} is required to execute the corresponding action. As shown in \autoref{tab:task_mapping_os} each alarm has an \lstinline{ActionType} attribute. Via this attribute the \gls{os} determines the correct action for an alarm. In other words, if an alarm expires this attribute must be read and a data read event is generated. Consequently, a \gls{btf} stimulus event is created whenever the action type attribute of an alarm is read. The exact action executed by an alarm, e.g.\ which task is activated for a process activation is read from the \gls{orti} file. \textbf{Event} actions must include the information about the affected event. For example, if a task sets an event it is necessary to know the target task and event for this action. \gls{orti} allows it to detect when an event related service routine is executed however, no information about the event itself is made available. \begin{code} \begin{lstlisting}[caption={[Set event] Erika Enterprise uses the \lstinline{EE_th_event_active} array to keep track of the events set for each task. If a new event is set the mask is updated by connecting the previous events and the new event via bitwise or. It is not possible to set an event for a suspended task.}, label={listing:set_event}] if ( EE_th_status[TaskID] == SUSPENDED ) { ev = E_OS_STATE; } else { /* Set the event mask only if the task is not suspended */ EE_th_event_active[TaskID] |= Mask; /* Check if the TASK was waiting for an event we just set */ if ((EE_th_event_waitmask[TaskID] & Mask) != 0U) { /* Activate task here */ } } \end{lstlisting} \end{code} \begin{table}[] \centering \begin{tabular}{r|l l} Action & Variable & Additional Information \\ \hline wait\_event & \lstinline!EE_th_event_waitmask! & previous wait mask\\ clear\_event & \lstinline!EE_th_event_active! & previous active mask\\ set\_event & \lstinline!EE_th_event_active! & previous active mask\\ all actions & - & event bit from eecfg.h \\ \end{tabular} \caption[OS specific event mapping]{Erika Enterprise uses two arrays to keep track of the event states for each task entity. Via write events to these arrays and the previous event state for a task instance correct \gls{btf} events can be generated.} \label{tab:os_event_mapping} \end{table} Erika Enterprise uses two arrays to keep track of the event related state of a task: In \lstinline{EE_th_event_active} the events currently set for a specific task instance are stored and \lstinline{EE_th_event_waitmask} includes the information about which events a task entity is waiting for. Each field in the array corresponds to one task and each bit of a field is related to a certain event. Whenever a task is terminated both event masks are cleared. Using these arrays it is possible to create correct events as shown in \autoref{tab:os_event_mapping}. Whenever an \gls{os} event related service routine is executed the corresponding event mask is updated. For example, if an event is set for a specific task, the event mask is updated based on the new event. This means the events which are currently set for a task and the new event are connected via the bitwise \emph{or} operation as shown in \autoref{listing:set_event}. Hence, a data write event to one of those arrays is created whenever a event service routine is executed. However, only the new state of the bitmask becomes available. To determine the event \gls{id} it is necessary to remember the previous state of the mask. By executing a bitwise \emph{exclusive-or} operation on previous and current mask, the bit of the current event is computed. Unfortunately, this information is still not enough to create a valid \gls{btf} event. For each bit it is necessary to know the corresponding entity name. \glsdesc{ee} defines the bitmask for each \gls{os} event in the \emph{eecfg.h} file which is created during the code generation process. By parsing the event defines the mapping between bit and event name is retrieved. \begin{code} \begin{lstlisting}[caption={[Spin in for global resource request] In case a global resource (a resource used on multiple cores) is requested, Erika Enterprise uses a spinlock mechanism to lock the CPU until the resource becomes available.}, label={listing:get_resource_spin}] /* if this is a global resource, lock the others CPUs */ if (isGlobal) { EE_hal_spin_in((EE_TYPESPIN)ResID); } \end{lstlisting} \end{code} \textbf{Resource} events or in \gls{btf} terms semaphore events, can be created based on the information provided by \gls{orti} as shown in \autoref{tab:resource_mapping}. However, certain semaphore events like waiting can only occur in multi-core systems. In a single-core system it is not possible that one task polls a resource that is already occupied because of the priority ceiling protocol. Erika Enterprise implements inter-core resource requests via spinlocks. If a task requests a resource that is locked by a task on another core, the service routine does not return an error code but starts spinning as shown in \autoref{listing:get_resource_spin}. As a consequence, the mapping for full, overfull, and waiting actions introduced in the previous section does not work. To solve around this problem, it is necessary to understand how spinlocks are implemented in Erika Enterprise. The state of each spinlock is stored in the \lstinline{EE_hal_spin_status} array where each field corresponds to a separate spinlock. A value of one indicates that the spinlock is locked otherwise the value is zero. The \lstinline{EE_hal_spin_in} method is implemented via the atomic compare-and-swap operation. This method is used to write a one into a certain spinlock field, but only if the spinlock is currently free. Compare-and-swap returns a value that indicates whether the operation was successful or not. In the latter case the operation is executed again until it succeeds. Compare-and-swap operations result in a data access to the variable for which the operation is executed. Therefore, it is possible to detect when a spinlock is polled based on data access events to \lstinline{EE_hal_spin_in}. This information can then be used to create correct semaphore events as shown in \autoref{tab:os_semaphore_process_mapping}. Whenever the \emph{resource locker} attribute is read within the context of the \lstinline{GetResource} service routine, the corresponding resource entity must be stored in the system state. If the resource is free, a write event to the \emph{resource locker} attribute follows and the corresponding \gls{btf} events can be created as described above. If there is no write event to the \emph{resource locker} attribute the resource is currently locked and the \gls{os} starts spinning which is detectable by continuous data access events to the field of \lstinline{EE_hal_spin_status} relating to the requested semaphore. Consequently, the running process is assigned to the semaphore via the waiting action and an overfull action must be created. The process is now in polling mode. Once there are no further accesses to \lstinline{EE_hal_spin_status} the request was successful, the task state changes to running and the resource state to full. \begin{table}[] \centering \begin{tabular}{r l l} Action & Variable & Additional Information \\ \hline waiting & \lstinline!EE_hal_spin_status! & running task, requested resource \\ full & \lstinline!EE_hal_spin_status! & requested resource \\ overfull & \lstinline!EE_hal_spin_status! & requested resource \\ \end{tabular} \caption[OS specific semaphore event mapping]{Not all \gls{btf} semaphore actions can be created based on \gls{orti} alone for an Erika Enterprise multi-core application. This is because inter-core resource requests are implemented via spinlocks. Spinlock operations can be detected via the \lstinline{EE_hal_spin_status} array.} \label{tab:os_semaphore_process_mapping} \end{table} % }}}