928 lines
47 KiB
TeX
928 lines
47 KiB
TeX
\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}
|
|
|
|
% }}}
|