loading...
MARCH 2007 (Vol. 8, No. 3) p. 1
1541-4922/07/$26.00 © 2007 IEEE

Published by the IEEE Computer Society
Gaining Insight into Executable Models during Runtime: Architecture and Mappings
Philipp Graf , University of Karlsruhe

Klaus D. Müller-Glaser , University of Karlsruhe

Model-based development using different domain-specific tools and graphical notations is becoming increasingly important in the design of embedded electronic systems because it allows fast, concept-oriented prototyping from model to code. An extension to a model-based development approach provides an architecture for debugging models that execute on target systems or in dedicated rapid-prototyping environments.

During development, the ever-increasing design complexity of embedded systems frequently comes into conflict with cost, time-to-market, and quality. This complexity results from increasing functionality, the expanding design space, the distribution of functionality to distributed control units, the optimization of power dissipation, and performance requirements. For example, as of today, a luxury car includes up to 80 electronic control units that communicate over various networks. An Airbus A380 contains more than 1,000 field-programmable gate arrays (FPGAs).
As complexity increases, the development focus shifts from electronic and pure control-based systems toward software-based systems. The embedded-software development community is increasingly accepting the object-oriented paradigm, and a growing number of graphical tools for computer-aided systems and software engineering (CASE) support it. Relevant notations include the Unified Modeling Language (UML), 1 statecharts, 2 and signalflow-based modeling. Graphical approaches usually feature a higher level of abstraction, as putting platform-dependent nonbusiness logic into transformations such as the Object Management Group's (OMG) Model-Driven Architecture (MDA) suggests. 3 Such approaches logically follow the progress from low-level assembly language programs to high-level languages to the object-oriented paradigm for specifying embedded software.
Other than pure simulation approaches, only a few tools let you find errors in embedded software at the graphical-modeling level. When a code generator transforms a model into code, its structure will likely change dramatically. A simple Stateflow diagram consisting of just a few states generates several hundred lines of C code. Also, the developer didn't write the code; it was generated, making a source-code-level view seem inappropriate while debugging. Insight into processing the model on a real target system or in the context of a processor-in-the-loop or hardware-in-the-loop simulation isn't possible. If the system was heterogeneously developed using specialized development tools, finding errors in the complete system is possible only at the source-code level. So, the challenge is to construct a system that leverages the debugging of executable models at the model level and that allows debugging executable models across notation boundaries.
Model-based development of software for embedded systems
Here, we briefly describe our development process for specifying software targeted at embedded systems according to different modeling domains and transforming it to an executable binary that's appropriate for rapid prototyping. You can access a longer, more complete description of our approach and tool support elsewhere. 4
In our eyes, defining a complete, potentially complex design process for our approach would be too rigid. Nevertheless, the approach puts constraints on the development process, and you can incorporate those constraints in different process models.
Figure 1 presents a basic top-down design flow. We used the software tool aquintos.GS (formerly GeneralStore), a commercially available research spin-off from our department, to realize and support our design process. It offers versioned model and user management, allowing concurrent engineering of large-scale heterogeneous models.




Figure 1. Top-down design flow from requirements to executable.



The design process starts from a textual specification document, which is the basis for the requirements specification phase that follows. From there, the system architect can extract a preliminary, roughly outlined class model. Subsequently, the architect divides the embedded system's model into different domain submodels, each of which is a software component, a subsystem in the control domain, or a statechart in the time-discrete domain.
Now, developers can use their CASE tool of choice in their preferred notation. The aquintos.GS integration platform automatically integrates them bidirectionally into a UML-metamodel-based top-level model. With respect to the runtime mapping concept we introduce later, it's important to emphasize that we provide a complete structural transformation to and from the UML. So, for example, our database stores state diagrams modeled using Matlab Stateflow and based on the UML state diagram metamodel.
You must link the various model parts so that they can communicate. You can do this by linking the system parts at the code level, but this approach is inflexible, error prone, and difficult to maintain. Alternatively, you can specify interfaces between the modeling domains at the model level in the overall UML system representation and transform them into a generatable class model before code generation.
The aquintos.GS platform lets you partition the whole system into subsystems. So, we enable the use of different domain-specific code generators. Each code generator has benefits in specialized application fields. For control systems, there are commercial code generators such as Embedded Coder or MicroC. In the software domain, we provide a code generator as a plug-in to enable structural and behavioral code generation directly from a UML model.
The generated source code is transformed to an executable binary during the last step. The developer can then deploy the executable file to the execution target, allowing validation of the model.
Debugging and simulation
Debugging and simulation focus on the same task during development: searching for and removing defects in a model that could lead to errors or even cause the whole system to fail. They do this in four phases: detecting, finding, analyzing, and eliminating defects. Although testing can detect errors or failures, finding and analyzing defects requires tool assistance that, in principle, both debugging and simulation approaches can provide.
Whereas debugging requires code generation and execution on the target system or a rapid-prototyping device, simulation approaches interpret the model. However, this interpretation can include code generation—for example, to compile accelerated simulation kernels. 5
Simulation doesn't require using the target system. Using a debugger implies that the model executes on a target system or a rapid prototyping device that is (or at least resembles) the target unit.
Designing embedded software using models imposes additional constraints on a simulation approach. Generally, embedded software exists in the context of peripherals and the surrounding environment. For simulation, this means that you must implement actuators and sensors and simulate the environment. The semantic equivalence of the simulated peripherals to the real system, however, is problematic. The need to model and implement these along with the software adds complexity and additional sources of defects to the design.
Following a model-based approach and automatically transforming this model to code adds yet another level of complexity. In the case of simulation, the simulator provides execution semantics that might not be exactly the same as those implicitly assigned to the model during its transformation into source code. When a developer specifies statecharts, execution semantics can vary among tools, simulators, and code generators.
Simulation offers pure functional validation. When simulating a model's execution, we know of no ways to validate nonfunctional requirements, especially concerning performance characteristics. Testing on real-time constraints or detecting and resolving race conditions requires execution on a platform as similar to the target platform as possible.
For a heterogeneous development environment (such as the one our work focuses on), simulators can be coupled. The visualization is usually accomplished using dedicated simulation tools or a visualization inside the design tools. For debugging, we couple the model before code generation, as we described earlier. The execution is then visualized using either the development tools or a dedicated visualization layer. We chose the latter approach, mainly because existing CASE tools' back-annotation facilities are, if available at all, proprietary, undocumented, and rather rudimentary. A debugging tool exists for models developed with Telelogic (formerly I-Logix) Rhapsody.
However, some advantages we've mentioned for debugging could also be advantageous for a simulation approach. This particularly holds true for early design phases, where hardware and peripherals don't yet exist and pure functional validation is sufficient. Also, simulation can provide better reproducibility.
Runtime models and synchronization
You can think of debugging a system that was developed using a model-based method as reversing the various transformation steps, from the model down to executable code.
Figure 2 illustrates the situation. The software design results in a model, which is detailed enough to be transformed into source code in a high-level language (for example, C or C++ in embedded software). The source code is transformed again using a compiler, resulting in an executable binary ready for deployment to the target platform. Following the OMG's MDA approach, we can regard artifacts on all three layers as models.




Figure 2. Mappings between model layers.



The binary file (for example, the model on the lowest level) executes on the target platform. Basically, the debugger extracts runtime information out of the executed binary from the target platform and transports this information back through the abstraction layers to the model level.
Fortunately, modern source-level debuggers already accomplish the first step—extracting information from the runtime level to the source-code level. Examples include the GNU Debugger (GDB, a part of the GNU Compiler toolchain), the Java Debug Interface (JDI), or proprietary source-level interfaces to debuggers for embedded processors.
The extracted information refers to debugging artifacts at the source level, such as lines of code, variables, and other source-level symbols. Because we want to obtain model-level information (for example, the active state of an executed state diagram), we must provide a mapping to the runtime information's model level.
However, you shouldn't confuse this "reversion" with reverse engineering, which aims to reconstruct the modeling artifacts themselves. From the executed model's viewpoint, artifacts can be static (elements originating from development) or dynamic (runtime information).
To hold and link the artifacts, the UML metamodel, which is based on the Meta Object Facility (MOF), 6 is extended with a runtime metamodel. Figure 3 shows this extension's relation to OMG's metalayer concept. Each layer is an abstraction of the underlying layer, with the top layer (M3) at the highest abstraction level. The bottom layer (M0) comprises the information that we wish to describe. On the model layer (M1) is the metadata of the M0 layer, the so-called model. Object-oriented software is typically described on the M1 layer as a UML model. The runtime information is also stored on this layer and linked with the existing modeling artifacts. The metamodel on the M2 layer consists of descriptions that define the metadata's structure and semantics (for example, the structure of a valid UML model). These metamodels—for example, UML 1.4 or UML 1.5—define the language and notation for describing different kinds of data respectively (M1). We extend the metamodel on this level to allow storage of runtime information. The extension lets our debugger dynamically gather the debugging data needed for debugging and link it with elements of the static-model part on M1. Finally, M3 contains the self-describing meta-metamodel MOF. It's used to describe metamodels and define their structure, syntax, and semantics—that is, it's an object-oriented language for defining metadata.




Figure 3. Object Management Group metamodel layers and runtime information.



The model debugger can use the runtime information on the model level to visualize the executable's internal state. The visualization can also use static artifacts. For example, to visualize a state chart's runtime state, the static information is used to render the diagram itself. The dynamic artifacts are used only to annotate or assign a different color to the active states in the diagram.
Mapping example: Executable Stateflow diagrams
Here, we clarify the work a typical mapper accomplishes by describing the time-discrete execution of Stateflow diagrams and the mapping involved. Matlab Stateflow, frequently used by control engineers, is a CASE tool that lets developers describe event-discrete models in syntax and semantics similar to UML state diagrams. Using the Real-Time Workshop Embedded Coder extension (http://www.mathworks.com/products/rtwembedded), we can generate optimized C code. The source code is integrated into the framework code generated from a UML-based supermodel using the coupling approach we mentioned earlier.
When considering an executable Stateflow diagram at runtime and the artifacts that are of interest to the user during debugging, the following questions arise:

    Which basic states in the diagram are currently active (active state)?

    Which events were triggered and will be relevant for the coming model time step (triggered events)?

    What are the values of the data context in Stateflow (data values)? (Data values are data storage elements similar to variables in programming languages.)

    Which transitions were triggered during the past time step (transitions)?

Using this information, an application developer can gain insight into the model's state and execution properties. Additionally, runtime control must switch from stepping through lines of code to stepping ahead one or several time steps in the execution of Stateflow diagrams.
Our model-level debugger acquires the model artifacts through mappers and model-level run-control of the target using a controller. The controller is based on setting source-level breakpoints at strategic positions. Resuming execution at the source level makes the target stop whenever the next model-level time step is completed.
To allow the mapping of runtime data for later display to the user, the UML metamodel containing static model artifacts is extended with metaclasses that allow storage of the data the mapper acquires. Figure 4 shows a detail of this extension for Stateflow diagrams. While modeling and code generation is accomplished through Stateflow, the debugger works on the representation of the model that was transformed to the UML metamodel. Figure 4 shows the UML metamodel for state diagrams and a simple extension for data values (called Guards in UML). The basis for the runtime model is the DebugContext, to which the debugger can attach any number of GuardValues. Each GuardValue is linked to the static Guard it stores the value for.




Figure 4. Extension of the UML state diagram metamodel to hold dynamic runtime information.



Mappers fill the data structures with values. As an example, we describe the mapping of the currently active basic state from the runtime information available from the source-level debugger.
Figure 5 shows a simple Stateflow diagram (see figure 5 a) and the corresponding data structures in C code when rendering it using the Real-Time Workshop Embedded Coder. Every composite XOR state is rendered into one variable (see figure 5 b) containing information on the activity of its direct substates in the hierarchy. The model debugger can reconstruct these variables purely from model information—namely, the state name and number depending on its position in the hierarchy (this follows a deterministic rule). These numeric values must be mapped to model information again. Figure 5 c shows the mapping. Every level has its own alphabetically sorted enumeration.




Figure 5. The Real-Time Workshop Embedded Coder uses (a) a Stateflow diagram to generate data structures, which contain (b) variables that store state information. These variables encode model information using (c) a specific state encoding.



Based on these observations, we let the debugger perform the mapping using the following algorithm:

    1. Begin with the top-level composite state—for example, the diagram.

    2. Reconstruct a variable name that contains activity information for this level (as we described earlier).

    3. Acquire a value from the target via the driver layer.

    4. Reconstruct the active substate from the value.

    5. Check the type of substate. If it's a basic state, add it to the runtime model. If it's a composite nonconcurrent state, perform step 2 (recursion) on that substate. If the substate is a composite concurrent state, iterate over all its children, performing step 2 (recursing) on every child.

By applying this algorithm, we obtain a list of all concurrently active basic states in the Stateflow diagram. The debugger uses this information for visualization later on.
Architecture for debugging heterogeneous systems
Figure 6 shows the architecture resulting from the approach we introduced in the "Runtime models and synchronization" section. It's built up from layers that continuously abstract further from the target architecture, source-level debugger, and programming language toward model-level visualization.




Figure 6. Layered debugging architecture.



The starting point is the modeled software that executes on the embedded target platform. Different target architectures include or support different source-level debuggers that allow extraction of runtime information over proprietary interfaces. Examples are the JDI, which integrates into the debuggee's class path; GDB's text-based interface; and proprietary debugging hardware for embedded processors.
The driver layer unifies these source-level debuggers as far as possible. Because the debuggers don't offer the same set of features and information, we defined interfaces that group sets of capabilities. Drivers generally implement only a set of the interfaces, influencing the capabilities that the debug system can offer to the higher levels. Common interfaces include run-control (starting, stopping, resetting, and stepping), access to symbol data (memory addresses of methods), and expression evaluation (reading variable values). Hardware-based debuggers often also offer an interface for acquiring and reading real-time trace data from the target.
Viewed from the topmost layer (see figure 6 ), the architecture offers the user different viewpoints of the debugger. A viewpoint defines a specific view of the system and mediates between the target system and the visualization layer that's on top of it. A typical debugging session for heterogeneously modeled software uses several viewpoints. The object configuration of the object-oriented software-intensive part is visualized using a UML object diagram, and every embedded statechart shows the behavior of components, classes, or port protocols. The complete set of viewpoints offers insight to all aspects of the running model.
The visualization layer is based on the open source development platform Eclipse and the associated diagramming framework Graphical Editor Framework (http://www.eclipse.org/gef). The diagram model is based on the Diagram Interchange (DI) metamodel, which has been part of the UML specification since UML 2.0.
Between a viewpoint and driver are a mapper and controller that bridge the model layers. The viewpoint uses the controller to control the system from the model's viewpoint. An execution step in a statechart corresponds to a complex sequence of commands at the source-code level. The mapper updates the runtime information model that provides the basis for the visualization with information from the source-level debug drivers. We outlined an example of mapping Stateflow charts in the "Mapping example: Executable Stateflow diagrams" section.
Prototype
Figure 7 shows a screen capture of our current model debugger implementation. The tool extends the Eclipse platform using various plug-ins that allow handling of models and visual debugging.




Figure 7. The model debugger's user interface.



The prototype lets the user open models from XMI (XML Media Interchange, the format for exchanging UML models) or Matlab Simulink files using the standard Eclipse Navigator view. These files can be visualized using a view showing a model tree of all model artifacts and a tabular detail view of properties and relations (the lower right part of figure 7 ). The user can open the DI-based diagrams these models contain in a graphical viewer.
Debugging centers on the DebugSession view in the upper-left corner of figure 7 . After connecting to a debug target through a driver, the user can add viewpoints, each opening a view or a graphical diagram editor as its visualization component. In the figure, one viewpoint shows a Stateflow chart. This diagram is already augmented with information on the active states in the running target.
The DebugSession view's toolbar lets the user run, reset, and time step the target on the basis of the selected viewpoint. In the figure's lower left part, the DebugContext view provides insight into the model's dynamic part, as we described earlier based on a tree view.
Conclusion
Automated transformation of models into executable code to enable rapid system development is becoming increasingly common. It requires new model-based ways to debug and monitor such models directly on an embedded target platform. Our architecture allows the definition of various debugging perspectives and views independent of the actual execution platform, maximizing reusability inside the architecture.
One key achievement is that our approach maximizes reusability while covering various aspects of heterogeneity:

    Development using different domain-specific modeling tools. Through adapted viewpoints, the user or developer can obtain adequate views of the various subsystems.

    Different development tool chains and target systems. By implementing a driver, you can integrate other target platforms running with different processors, operating systems, and debugging interfaces. Higher-level layers might remain untouched. One example would be to use the real-time tracing capabilities of embedded-processor-debugging hardware to reduce impact on timing.

    Distributed systems. Using various driver instances, you can debug models that execute concurrently on different hardware nodes using one instance of the debugger platform.

    Heterogeneous architectures. Model-based hardware and software codesign can be supported by hardware and software co-debugging. As reconfigurable hardware and parallel hardware and software development become increasingly important, a model-based approach allows late decisions on the execution platform of functionality. We plan to further investigate the transparent debugging of such systems.

References

Philipp Graf is a scientific assistant and PhD candidate at the University of Karlsruhe's Institute for Information Processing Technologies. His research interests include UML-based design methodologies for embedded electronic systems, executable models, and debugging of such models. He received his Dipl.-Ing. in electrical engineering from the University of Karlsruhe. Contact him at the Institut für Technik der Informationsverarbeitung, Universität Karlsruhe (TH), Engesserstr. 5, D-76131 Karlsruhe, Germany; graf@itiv.uni-karlsruhe.de.

Klaus D. Müller-Glaser is a director of the University of Karlsruhe FZI Forschungszentrum Informatik (Research Center for Information Technologies). He is also a professor at the University of Karlsruhe and head of the university's Institute of Information Processing Technologies. His research interests include methods and tools for the design of electronic systems, microsystems and systems-on-chip, executable specifications, and model-based design. He received his Dr.-Ing. from the University of Karlsruhe. Contact him at the Institut für Technik der Informationsverarbeitung, Universität Karlsruhe (TH), Engesserstr. 5, D-76131 Karlsruhe, Germany; mueller-glaser@itiv.uni-karlsruhe.de.