SYMRT is built to accommodate the configuration of the execution environment in terms of hardware and JVM implementation. The latter can be a traditional, software implementation, such as the HVM, or a hardware implementation, such as the JOP. Parameters related to the temporal behavior of the system are configurable as well, such as the clock frequency of the hardware. The enabling technology for allowing timing analyses is model checking using UPPAAL. SYMRT and JPF-SYMBC-RT are open source and available from https://bitbucket.org/luckow/symrt/
and https://bitbucket.org/luckow/jpf-symbc-rt.
4.1 Overview
A high-level overview of SYMRT is shown in Fig. 3. SYMRT takes as input the Java class files constituting the real-time system and a configuration which, among others, specifies the analyses and the model generation technique. SYMRT allows the generation of two different timing models. The configuration specifies which model to generate, which can either be a complete timing model or an execution time analysis optimized model:
-
A complete timing model of the real-time system, which includes the real-time scheduling policy, all real-time tasks of the system and controllers for monitoring and controlling the state of the tasks. This timing model can be used for reasoning on schedulability, and facilitates analysis of WCET and BCET on task level, WCBT, and processor utilization and idle time. TetaSARTS is used with JPF-Symbc-rt for model extraction in this case.
-
An execution time analysis optimized model which needs not to reason on task interleavings and interactions, etc. Specifically, this model applies to the analysis of WCET and BCET, which by definition pertain to the unit of interest in isolation, i.e., the behavior of the remaining system is not taking into account. In addition, this model allows execution time analysis on method level. For generating this model, SymRT uses the Optimized Execution Time Analyzer (OETA) module which essentially offers direct interaction with JPF-Symbc-rt through the interface of SymRT.
Common to both generation techniques is the RT System Analyzer, which identifies the real-time tasks and extracts temporal scope information, e.g., release pattern, relative release point, and deadline, or, in case method level execution time analysis is specified, identification of this method information. Based on the configuration, the RT System Analyzer also forwards a specification of the target analyses to the Query Specifier, which constructs the UPPAAL queries accordingly. In summary, the target analyses for which SYMRT is currently envisioned are:
-
Schedulability analysis under the employed scheduling policy taking into account periodic (with offsets) and sporadic task releases, task interleavings, shared resources, and task blocking.
-
Analyzing the lowest possible clock frequency that still guarantees schedulability. This analysis can be used for improving the energy consumption of the system.
-
Processor utilization and idle time analysis (provided that the system is schedulable).
-
Worst case response time (WCRT) analysis similarly taking into account aforementioned task interference and blocking.
-
WCET and BCET analysis on task and method level.
All analyses are expressed in the specification language of UPPAAL, which extends TCTL. In essence, this means that the timing analyses supported by SYMRT are viewed as model checking problems. For example, the schedulability analysis is expressed as a reachability problem: the property of a non-schedulable system is expressed in TCTL and if the model, which is derived from the actual system, satisfies it, then we conclude also the system non-schedulable. The details on how the analyses are formulated are described later.
The model generator component in the TETASARTS module constructs the Program NTA by using either the original CFG NTA Generator or the Real-Time Symbolic PathFinder component. The former is based on reconstructing the CFG, while the latter is based on symbolic execution and works on the symbolic execution tree. The resulting Program NTA is then combined with the NTAs of the execution environment, i.e., the JVM NTA and the Hardware NTA, using the model combiner component. During this process, optimizations are also performed, e.g., for tailoring the JVM NTA to the hosting program. For details on the execution environment NTAs and optimizations, see [25, 44]. The product of the combiner is the complete timing model, which is amenable to model checking using UPPAAL, and the output will be the analysis result: for schedulability, it will be a yes/no answer, and for WCET a number. In addition, a witnessing trace, i.e., a sequence of symbolic states leading to the violating state, can be used for visualization and debugging.
The OETA module has similar major counterparts but does not reason on system level when generating the Program NTA. Using this module, it is possible to extract a trace leading to the WCET (and BCET) and visualize the respective execution paths. We will demonstrate this facility later in the paper.
4.2 Symbolic execution vs CFG-based model generation
Inevitably, considering all execution paths characterized by the CFG as in [7, 22, 24, 25] affects the analysis time, but it may also severely over-approximate the temporal behavior.
Virtual method invocations also complicate CFG-based approaches since all possible callees must be considered unless the reconstruction is complemented with additional analyses such as rapid type analysis [45] that attempts to reduce the set of possible callees. When using symbolic execution, SYMRT does not need to be complemented with such analyses, since the stack is part of the symbolic state, hence the callee is known at every call site of every execution path.
Additionally, in traditional CFG-based approaches, loop bounds are difficult to reason about and are usually either dealt with using annotations in the source code or through static analysis. Annotations are both prone to error and difficult to maintain. A related issue is nested loop structures with loop bound interdependencies, which are difficult to precisely incorporate in the timing model. Symbolic execution unrolls loops, hence, for most cases, neither loop bound annotations nor complementary loop bound analyses are necessary (see Section 5 for examples) except when the bound is dependent on, for example, I/O or the unrolling exceeds the specified analysis depth. In cases where annotations are necessary, SYMRT offers (simple) comment-based loop bound annotations on the form //@loopbound = bound; SYMRT will unroll the loop up to the specified bound and explicitly break it. To represent input values from, e.g., sensory equipment, we introduce a symbolic variable. If the search depth limit of symbolic execution is reached, the resulting timing model will only be correct up to that bound, and hence SYMRT issues a warning. The search depth can then be increased.
4.3 Model construction
The JPF-SYMBC-RT component of SYMRT conducts a post-translation of the symbolic execution tree to the NTA formalism using a newly developed symbolic execution tree capability available in JPF-SYMBC V7 [46].
Capturing the temporal behavior of the execution paths of the real-time tasks is done at Java Bytecode instruction level; for each Java Bytecode of the execution path, a location is created in the TA and connected by outgoing edges to successor locations corresponding to the control flow. For branching instructions, such as IFEQ and FCMPL, there can be up to two and three outgoing edges, respectively, if the path conditions of the branches are satisfiable (or if the decision procedure is inconclusive). For all other instructions, there will be only one outgoing edge.
The translation process distinguishes between how the execution environment timing model is provided:
-
1.
The timing model can be provided as fixed execution times or as intervals for all the (supported) Java Bytecodes using a timing scheme. Elaborating on the construction of timing schemes is beyond the scope of this paper, but let us note here that they can either be constructed by a careful measurement-based method or by using static analysis of the implementation as in our related work in [47].
-
2.
The timing model is directly encoded as an NTA itself, i.e., the temporal behavior of each Java Bytecode is simulated including the hardware state as determined by, e.g., caching and pipelining. This approach has the potential of yielding a more precise timing model than the translation approach 1, because the temporal behavior of each Java Bytecode is not regarded as an interval but actual simulations. For example, this will more precisely capture the effect of a shared pipeline and cache when tasks are scheduled. The potential benefits of this approach come at the expense of a bigger state space, and currently only small, although realistic, applications, such as the Minepump control system [1, 24], are tractable for analysis.
Figures 4 and 5 show excerpts of the two modeling approaches for an imaginary instruction instr1.
In Fig. 4, each location encodes as an invariant the timing constraints of the corresponding instruction: e
x
e
c
u
t
i
o
n
T
i
m
e≤W
C
E
T_i
n
s
t
r1 specifies that the system can at most spend the WCET of instruction instr1 in that location. The stop-watch expression e
x
e
c
u
t
i
o
n
T
i
m
e
′==r
u
n
n
i
n
g[ t
I
D] ensures that the clock is only progressing when the task to which this particular TA belongs is running as governed by the scheduling policy. In case the analysis is targeted solely at execution time analysis, the stop-watch expression is omitted. The guard ensures that the execution time of instr1 is simulated for at least its BCET. Both the WCET and the BCET are obtained from a timing scheme describing the temporal behavior of all the supported Java Bytecodes on the target execution environment (configuration of JVM and hardware).
For this translation approach, JPF-SYMBC-RT employs state reduction on non-breakable, sequentially executed instructions in the NTA inspired by [25]. Sequentially executed instructions are not branching and all instructions except monitor instructions and invocations yielding the firing of a sporadic event are non-breakable. Let E
l
denote the execution time of the instruction represented by location l. When the instruction execution times are known, the total execution time of n sequentially executed instructions represented by locations l
1,l
2,…,l
n
, is \(E_{\{l_{1},l_{2},\ldots,l_{n}\}} = {\sum \nolimits }_{i=1}^{n}E_{l_{i}}\). Thus, this sequence can be replaced by a single location with execution time \(E_{\{l_{1},l_{2},\ldots,l_{n}\}}\). For a bubble sort algorithm, the number of locations before and after the optimization is 163,549 and 1441, respectively, thus reducing 99.1 % of the locations. Effectively, the optimization yields a control flow representation of the basic blocks constituting the feasible paths as determined by symbolic execution. Figure 6 shows the TA (after applying optimizations) of the running example.
JPF-SYMBC-RT also uses progress measures; a variable in the model that is incremented to describe progress in the model. When all traces corresponding to a specific value of the progress measure have been crossed, the memory of previous states can be removed, thus reducing overall memory consumption of the analysis.
The product of translation approach 2, shown in Fig. 5, relies on simulating the execution time based on the state of JVM and the hardware. Separate NTAs are used for capturing the timing behavior of the program, the JVM and the hardware, denoted the Program NTA, the JVM NTA, and the Hardware NTA, respectively. The interactions among them capture the dependencies between the temporal behavior, e.g., the temporal properties of an arbitrary Java Bytecode modelled in the JVM NTA is dependent on the pipeline and cache state of the processor in the Hardware NTA. The interactions are well-defined using dedicated (co-)actions and shared variables, making it possible to replace NTA components to configure the analysis to the desired execution environment.
During the process of combining the Program NTA generated by JPF-SYMBC-RT with the JVM NTA and the Hardware NTA, optimizations are performed, e.g., for tailoring the JVM NTA to the hosting program. For details on the execution environment NTAs and optimizations, see [25, 44, 47].
In [47], we have shown how a JVM NTA can be derived directly from the HVM executable. Here, it suffices to say that the instruction is passed to the JVM NTA by the jvm_instruction shared variable. jvm_execute! initiates the simulation in the JVM NTA. For JOP, SYMRT allows simulating exactly variable block FIFO, FIFO, and LRU method cache replacement policies. The simulation approach is similar to that used in WCA [22].
An example of a Hardware NTA is shown in Fig. 7.
Here, the combination of the fetch channel and asm_inst establishes the communication link with the JVM NTA. The JVM NTA synchronizes on the channel whenever a machine code instruction (as provided by the asm_inst variable) is to be simulated (in this case directly put into the fetch stage of the pipeline). The machine instruction will be simulated for [best_wait;worst_wait] time.
The product regardless of whether translation approach 1 or 2 is used is the complete timing model with the analyses specified as UPPAAL specifications. The output of model checking is the analysis result, e.g., a yes/no answer for TCTL properties, and a number for WCET and BCET analysis. In addition, for execution time analysis, a witnessing trace, i.e., a sequence of symbolic states leading to the violating state, can be used for debugging, visualization, and program understanding.
4.4 Per-task analysis
The timing model of a multi-tasking real-time system is built modularly, based on the symbolic execution of each individual task. Whenever an instance or a static variable is read (via GETFIELD or GETSTATIC bytecodes), the per-task analysis checks to see if the variable is possibly shared among multiple tasks. A variable is shared if it is referenced in a chain of references from a static field or from a task (thread) object. SYMRT also relies on additional checks in JPF for determining sharedness, e.g., if the field is immutable. We have implemented a procedure that propagates the sharedness information along reference chains whenever an update happens (via PUTFIELD and PUTSTATIC) to a variable that was marked as shared. Furthermore, the lazy initialization used in handling symbolic references has also been modified to mark all the newly created objects as shared (if the symbolic fields belong to a shared object).
If the variable is considered shared, a safe modular generation of the timing model for the task must account for values written to that variable from other tasks. This is necessary, because the values may alter the control flow of the logic in the task and possibly make feasible other execution paths that may yield a higher WCET (or lower BCET) thus rendering the analysis unsafe if these are not considered. To account for this, the per-task analysis automatically introduces fresh symbolic variables for the potentially shared variables. Hence, these accounts for all possible values that can be assigned to the shared variables and therefore captures all possible thread interferences. This yields a safe local analysis of the tasks because the symbolic variables over-approximate the values of shared variables and thus the feasible execution paths.
Generating timing models for each task using this per-task analysis significantly reduces the complexity of symbolic execution because any behavior of the system outside the local task needs not to be considered. The composition of all timing models generated from the tasks from the per-task analysis yields a complete system model which is also safe, because the composed model over-approximates the possible interference between the tasks.
4.5 Model analysis
When JPF-SYMBC-RT is used directly for execution time analysis, the TA shown in the screenshot in Fig. 8 of the running example is generated. WCET and BCET can be determined using the sup-query (inf-query) extensions of UPPAAL, which determine the supremum (infimum) value of the specified clock(s). WCET and BCET can be formulated as s
u
p{f
i
n
a
l}:e
x
e
c
u
t
i
o
n
T
i
m
e and i
n
f{f
i
n
a
l}:e
x
e
c
u
t
i
o
n
T
i
m
e, respectively. Note also that the simulator is capable of visualizing the trace (i.e., sequence of states) leading to the (in this case) WCET of the program.
For a complete timing model, the NTA is further extended with TAs from TETASARTS capturing the scheduling policy and for controlling and monitoring the state of associated real-time tasks. A controller for periodic tasks is shown in Fig. 9. Controllers for sporadic tasks are similar except that their eligibility for being scheduled is determined by the previous firing of the associated event. The task TAs are modified for making the association to a corresponding controller resulting in the TA shown in Fig. 10 for our running example.
The connection is created using the run[tID] channel; tID is a task identifier. Note that the values of offset, deadline, and period are extracted from the task instantiations in the source code. Clock variables corresponding to the target analyses are generated as part of the controller TA, hence enabling WCET, WCRT, and WCBT analyses in this example using the same timing model. The controller TA will enter the ExecutingThread location when the associated task is executing. The clock releasedTime is used to track the relative time from the release point. If it exceeds the deadline of the task, the DeadlineOverrun location is entered, otherwise execDone is entered and the process continues when the period is met.
The analyses are conducted by viewing them as reachability problems expressible in temporal logic; we can formulate schedulability analysis as: is it possible to reach a state where a task misses its deadline? This state is represented by the location DeadlineOverrun previously mentioned. Assume a system composed of n tasks T
i
with corresponding DeadlineOverrun
i
locations in the controllers for i∈{1,2,…,n} and let \(\phi = \bigvee _{i} DeadlineOverrun_{i}\) denote the disjunctive state formula of the DeadlineOverrun locations. Schedulability analysis can then be expressed as A□ n
o
t
ϕ, i.e., in all reachable states, ϕ is not satisfied.
For the other supported analyses, we use sup- and inf-queries. WCET and BCET analysis can be conducted using sup{TC.ExecutingThread}:TC.wcet and inf{TC.Done}:TC.wcet, respectively, where TC is the task controller of the real-time task. Note in Fig. 9, that the wcet clock is only progressing when the task is set for execution due to the stop-watch expression. WCRT and WCBT analysis can be conducted using s
u
p{T
C.E
x
e
c
u
t
i
n
g
T
h
r
e
a
d}:T
C.w
c
r
t and s
u
p{T
C.E
x
e
c
u
t
i
n
g
T
h
r
e
a
d}:T
C.b
l
o
c
k
i
n
g
T
i
m
e, respectively. Note that the blockingTime clock is only progressing when the task is blocked. Processor utilization and idle time analysis can be conducted by introducing a new TA with a single location with the stop-watch expression u
t
i
l
′ == !i
d
l
i
n
g && i
d
l
e
′ == i
d
l
i
n
g where util and idle are two new clock variables and idling a boolean variable that is set whenever a task is executing. A sup-query on util and idle clocks is used for the analyses.