7.2.3 Future work
Trace files tend to become quite voluminous, especially if tracing is enabled for many classes. As a result, the resulting UML sequence diagrams become very large and consequently hard to read. One way to make diagrams more compact is to represent redundant data more efficiently. Taniguchi et al. (2005) propose a number of compaction rules that make UML sequence diagrams generated from traces more concise, including the removal of repetitions. The authors report that sample traces were considerably reduced in size when their compaction rules were applied to them, ranging from one hundredth of the original size to seven percent of it. The work of Taniguchi et al. could be profitably applied to the UML sequence diagram generator developed as part of this thesis work.
UML sequence diagrams generated by this tool must be viewed using an external viewer. It might be worthwhile to create a dedicated viewer application allowing the user to filter out specific classes.
It is not clear that UML sequence diagrams are the best way to visualize program traces. Renieris and Reiss (1999) present some alternatives, including a spiral view and a space-efficient linear view that uses the horizontal axis to represent (real) time, the vertical axis to represent call depth and color to represent the called function. A viewer application for traces could allow the user to select between several different visualizations.
The data contained in trace file may not only be used to visualize program behavior, it can also be used for performance analysis. The timestamps present in trace files are not used by the UML sequence diagram generator, but could fruitfully be used by a tool reporting on performance, in effect creating a simple profiler.
The primary benefit of having objects log their own behavior, by redirecting their dispatch table entries to statically generated wrapper functions, is simplicity. There are two significant disadvantages, though. First, source code must be generated statically, leading to an increase in code size. Also, the product must be rebuilt to enable or disable the tracing facility for certain classes, an annoyance in an environment with long build times. (This issue will be significantly alleviated once Sony Ericsson’s efforts to introduce dynamically linked modules get underway, though, as build times will be substantially reduced.) Second, the current tracing facility can not support tracing calls to all objects implementing a certain interface—the trace feature is enabled on a per-class basis only.
These issues could be solved by introducing wrapper objects instead of modifying the source code of classes, the only downside being the added implementation complexity. This would make the implementation of the tracing facility similar to the interception system proposed by Hunt and Scott (1999), and would allow for the easy integration of additional services.
Had wrappers been available, the implementation of IShell::CreateInstance() and IRoot::QueryInterface() would have to be interception-aware, in that these operations would have to determine whether to return direct references or references through wrapper objects. Making IRoot::QueryInterface() interception-aware would be straight-forward, as wrapper objects need only be returned from other wrapper objects, and these objects are free to use any implementation of this operation that they desire. The implementation of IShell is provided by ST-Ericsson, and while patching ST-Ericsson’s source code is possible, it is not desirable. It would be possible to intercept calls, though, which again is similar to the approach taken by Hunt and Scott.
To make declarative attributes, such as tracing, available at runtime, a separate data store would have to be created (the current data store containing class UUIDs and their mappings is part of ECM, and is shipped as part of ST-Ericsson’s platform). To replicate the ease-of-use of the current tracing facility, a means of setting declarative attributes at build-time (using compile-time names) would have to be implemented.
Wrapper classes could be generated at build-time, much like proxy classes, but this would waste space unnecessarily. As demonstrated by Brown (1999a, 1999b), synthesizing wrapper objects at runtime that implement arbitrary interfaces is possible without access to type information.
The current tracing facility manages to include compile-time names in trace files for the simple reason that these names are embedded as string literals in the generated wrapper functions. Statically generated wrapper objects would be generated on a per-interface basis, and while they could include the compile-time names of interfaces and operations, they would not be able to write the compile-time class name to a trace file. If wrapper objects are to be synthesized at runtime, no such information is available, as the synthesized implementation is completely class-agnostic. In order to write trace files in the format exemplified by Listing 7.1, more complete runtime type information would have to be available.
An alternative would be to forego creating human-readable trace files, and instead use runtime names and dispatch table indices. Instead of including the compile-time names of classes and interfaces, as well as human-readable operation names, a trace entry would instead use a class UUID, interface UUID and the index of the operation in the dispatch table. (Indeed, this is the information reported by COM+ Instrumentation.) Such a trace file would be significantly more compact than the current format, and could be post-processed on a computer with access to the source IDL files to create a human-readable trace file.
Another advantage to moving to a runtime solution with dynamically synthesized wrapper objects, instead of statically generated wrapper functions, would be that tracing could be enabled and disabled at runtime. ST-Ericsson provides a tool named Interactive Debug, which allows developers to interact with a running system from a PC.1 This tool could be used for this purpose. Absent runtime type information, developers would have to use runtime names in the form of UUIDs, though.2 Enabling or disabling tracing for yet-to-be-instantiated objects would be easy, doing likewise for already-existing instances would be considerably harder, as wrappers would then essentially have to be used for all objects, at all times.
Implementing a generic interception system for ECMX, in the manner described above, would be a major undertaking. It would enable, though, not just better support for execution tracing, but the possibility of easily introducing a wealth of additional declarative services to Sony Ericsson’s system.
- Interactive Debug appears much like a file system to the developer, and provides a hierarchically organized information space that the developer can interact with. It is somewhat similar to the procfs virtual file system, which allows users to interact with the running kernel of many Unix-like systems.
- As type information is available on the PC, it would be possible to write a tool allowing developers to use compile-time names, that would simply translate these names to runtime names before interacting with the embedded system.