7.2.2 Tracing invocations

The tracing facility developed as part of this thesis work can only be enabled at build-time—there are no provisions for enabling and disabling tracepoints at runtime. Unlike the interception techniques described in section 7.1, this solution does not use wrapper objects that masquerade as the target objects and forward invocations. Instead, the IDL compiler emits code that realizes tracing for traced classes.

In theory, ECMX is a binary standard, and developers can thus write classes without relying on Sony Ericsson’s IDL compiler. In practice, Sony Ericsson’s IDL dialect is used pervasively, and developers never write ECMX classes without using the IDL compiler—indeed, the technology is simply known as “IDL” in developer vernacular. This is in stark contrast to COM, where an arbitrary number of IDL compilers and other such tools, created by companies other than Microsoft, create COM-compatible classes. The binary standard is the common denominator that binds these disparate solutions together. At Sony Ericsson, though, the sole IDL compiler, which is under the direct control of the company, is always used to create ECMX-compatible classes. IDL is thus a de facto standard for creating ECMX classes at Sony Ericsson, if not a de jure standard. As such, modifying the IDL compiler to emit tracing code is a workable solution.

Sony Ericsson’s IDL compiler creates a number of files when creating a C binding from an IDL file. Of these, only the file housing the domain-specific implementation of a class is expected to be stored in a version-controlled repository. The other files, containing “plumbing” code such as proxies for inter-process communication, UUIDs and notably dispatch tables, are generated by the build system on-demand, and are stored in a directory dedicated to automatically generated files.

The latter property is exploited by this tracing facility to make already-written classes write their runtime behavior to disk, with no changes required to the developer-maintained class source code. When the IDL compiler encounters a class for which tracing has been enabled, it does not point the generated dispatch tables of the class directly to the implementation functions as it ordinarily does—instead, it points the dispatch tables to generated wrapper functions. These functions call on the services that have been enabled declaratively before and after the original function is invoked. (ECMX also uses these wrappers to enable declarative thread-safety.) Tracing class instantiation and object destruction is straight-forward, as the class factory and implementation of IRoot::Release() are always provided by the system when the IDL compiler is used.

Listing 7.2: Sample trace wrapper
static RVoid
  CTestClassBase_ITestInterface_TestOperation(
    ITestInterface* pITestInterface)
{
  CTestClassBase_t* pThis = (CTestClassBase_t*)pITestInterface->pData;
  RVoid _result;

  CSystemTrace_ISystemTrace_EnterOperation("CTestClass",
                                           "ITestInterface",
                                           "TestOperation",
                                           (FUint32)pThis);

  _result = CTestClass_ITestInterface_TestOperation(pITestInterface);

  CSystemTrace_ISystemTrace_LeaveOperation("CTestClass",
                                           "ITestInterface",
                                           "TestOperation",
					   (FUint32)pThis);

  return _result;
}

A sample trace wrapper generated by the IDL compiler is shown in Listing 7.2. The CSystemTrace class is part of the ECMX runtime system, and is responsible for writing trace entries to disk.1 Instances of this class are protected from concurrent access using ECMX’s support for declarative thread-safety. Return values from the CSystemTrace operations are purposefully thrown away, as a failure to write a trace entry to disk should not prevent the original function from being called, and should not cause the caller to receive a failure code.

An ECMX IDL file ordinarily only contains one class. The IDL compiler generates code that traces invocations when invoked with the command-line argument --trace. The build system used by Sony Ericsson allows for temporary modifications to the build configuration using a file, DescrExtra, that is never checked into the versioned-controlled repository. Using this file, developers can easily add the --trace argument to one or several IDL files housing classes. (IDL files should always be named after the classes or interfaces that reside within them.) DescrExtra also supports wildcards, making it easy to enable tracing for multiple files. As classes are normally prefixed with the name of the module they are part of, the wildcard feature makes it easy to enable tracing for all classes that are part of a specific module. Listing 7.3 shows a sample DescrExtra file.

Listing 7.3: Sample configuration file enabling tracing
[SourceFiles_Options]
CFirstTestModuleTestClass.idl +IDL=(--trace)   # Trace a specific class.
CSecondTestModule*.idl +IDL=(--trace)          # Trace a specific module.
#C*.idl +IDL=(--trace)                         # Trace all classes.

Sony Ericsson’s IDL compiler is written in C++, and its front-end uses GNU Flex for lexical analysis and GNU Bison for generating a parser from a context-free grammar. The intermediate representation consists of an in-memory syntax tree, which the back-end traverses using the visitor design pattern (Gamma et al. 1995). This work has entailed making a number of changes primarily to the visitors of the compiler.

It is debatable whether this tracing facility truly uses interception. The source code of classes is essentially modified in such a way that objects are coerced into writing their own behavior to disk. At runtime, there is no need to intercept calls using separate wrapper objects, as the objects themselves realize tracing.

Footnotes

  1. CSystemTrace is an example of a static class, which is yet another addition to ECMX. Macros of the form [class-name]_[interface-name]_[operation-name] are generated by the IDL compiler for these classes, and expand to calls to system-wide object instances (which are created if necessary). The first version of this work put the required code inline in the wrapper functions themselves, instead of calling on the services of a separate object. After the commencement of this thesis work, Sony Ericsson refactored the tracing facility, and in doing so, created the CSystemTrace class.