Understanding Runtime Tracing

To view the UML sequence diagram report:

  1. Select the Runtime Tracing Viewer tab.

  2. As you recall, the Runtime Trace viewer displayed all objects and all method calls involved in the execution of the UMTS base station code. Using the toolbar Zoom Out button, zoom out from the tracing diagram until you can see at least five vertical bars.

  3. Make sure you are looking at the top of the runtime tracing diagram using the slider bar on the right.

What you are looking at is a sequence diagram of all events that occurred during the execution of your code. This sequence diagram uses a notation taken from the Unified Modeling Language, thus it can be correctly referred to as a UML-based sequence diagram.

The vertical lines are referred to as lifelines. Each lifeline represents either a C source file or a C++ object instance. The very first lifeline, represented by a stick figure, is considered the "world" - that is, the operating system. In this UMTS base station tracing diagram, the next lifeline to the right represents an object instance named Obj0, derived from the UmtsServer class.

Green lines are constructor calls, black lines are method calls, red lines are method returns, and blue lines are destructor calls. Hover the mouse over any method call to see the full text. Notice how every call and call return is time stamped.

Everything in the Runtime Trace viewer is hyperlinked to the monitored source code. For example, if you click on the Obj0::UmtsServer lifeline, the header file in which the UmtsServer class declaration appears is opened for you, the relevant section highlighted. (Close the source file by right-clicking the tab of the Text Editor and selecting Close.) All function calls can be left-clicked as well in order to view the source code. Look at the very top of the Obj0::UmtsServer lifeline. It's "birth" appears to consist of a List() constructor first, then a UmtsServer() constructor. Why a call to the List() constructor if the object is an instance of the UmtsServer class? Click on the UmtsServer() lifeline again - see how the UmtsServer() constructor inherits from the List() class? This is why the List() constructor is called first. Click the two constructor calls if you wish to pursue this matter further.

Notice how the window on the left-hand side of the user interface - called the Report Window - contains a reference to all classes and class instances. Double-clicking any object referenced in this window will jump you to its birth in the Runtime Trace viewer. This window can also be used to filter the runtime tracing diagram.

  1. In the left-hand window, close the node labeled NETWORKNODE.H - notice how all objects derived from the NetworkNode class declared in this header file are reduced to a single lifeline.

  2. Reopen the node labeled NETWORKNODE.H.

You've probably noticed the vertical graph with the green bar to the left of the Runtime Trace viewer. This is the Coverage Bar. It highlights, in synchronization with the trace diagram, the percentage of total code coverage achieved during execution of the monitored application. The Coverage Bar's caption states the percentage of code coverage achieved by the particular interaction presently displayed in the Runtime Trace viewer. Scroll down the trace diagram; note how code coverage gradually increases until a steady state is achieved. This steady state is achieved following the moment at which the mobile phone has connected to the UMTS base station. Dialing the phone number increases code coverage a bit; shutting off the phone creates a last burst of code coverage up until the moment the UMTS base station is shut off. Can you locate where, on the trace diagram, the mobile phone simulator first connected to the UMTS base station? (The Coverage Bar can be toggled on and off using the right-click-hold menu within the Runtime Trace viewer.)

Note   If the C++ code in the UMTS base station spawned multiple threads, the Coverage Bar would be joined by the Thread Bar, a vertical graph highlighting the active thread at any given moment within the trace diagram. A double-click on this bar would open a threading window, detailing thread state changes throughout your application's execution.

Continue to look around the trace diagram. Can you locate the repetitive loop in which the UMTS base station looks for attempted mobile phone registration (it always starts with a call to the C function tcpsck_data_ready)? You can filter out this loop using a couple of methods. One is to simply hover the mouse over a method or function call you wish to filter, right-click-hold and select Filter Message. An alternative method would be to build your own filter. You will do both.

  1. Hover the mouse over any call of the tcpsck_data_ready function, right-click-hold and select Filter Message - the function call should disappear from the entire trace.

  2. Select the menu item Runtime Trace->Filters (you'll see the filter you just performed listed here)
    Click the Import button, browse to the installation folder and then the folder \examples\BaseStation_C, and then Open the filter file filters.tft

  3. Check that BaseStation Phone Search Filter is selected. Select it if necessary.

  4. Click the OK button.

The loop has been removed.

Not only can the runtime tracing feature capture standard function/method calls, but it can also capture thrown exceptions.

  1. View the very bottom of the runtime tracing diagram using the slider bar.

Do you see the icon for the catch statement - (you may have to drag the slider bar slightly upward; closing the NETWORKNODE.H node in the left-hand report window will also make things easier to see)? This Catch Exception statement is preceded by a diagonal Throw Exception. Why diagonal? Because when the exception was thrown, prior to executing the Catch statement, the LostConnection constructor and UmtsMsg destructor were called. Click various elements to view the source code involved in the thrown exception and thus decipher the sequence of events.

This exception occurred by design, but it is clear how the runtime tracing feature, through the power of UML, would be extremely useful if you have:

And you are guaranteed the identical functionality for application execution on an embedded target.

Further Work