Introduction

Welcome to Tracealyzer

Overview

Percepio Tracealyzer is a powerful tool for tracing and visualization of embedded and IoT software systems at runtime. More than 30 views offers amazing insight into the real-time behavior, speeding up debugging, validation and performance optimization. This saves you many hours of frustrating trial-and-error troubleshooting. With Tracealyzer you see what is really going on in your system!

Tracealyzer provide state-of-the-art visualization developed since 2004 and actually understands the meaning of many software events from supported RTOSes and middleware stacks. This allows Tracealyzer to perform advanced analyses and provide many specialized visualizations, with intuitive links between the views and highlighting of related events. The resulting visualization makes it much easier to draw conclusions from the data, understand the problem and verify the solution.

For RTOS-based systems, Tracealyzer shows task scheduling and timing, calls to RTOS services (including blocking and timeouts) and internal RTOS events such as task activations and OS ticks. Tracealyzer can also show interrupt handlers as well as User Events logged from your application code.

On top of this, Tracealyzer allows you to create user-defined visualizations using State Machines and Custom Intervals. This way, you can visualize specific aspects of importance for your system and the problem at hand.

Tracealyzer can be used side-by-side with a traditional debugger and complements the debugger view with a higher level perspective, ideal for understanding real-time issues where a classic debugger is not sufficient.

Tracealyzer does not require additional tracing hardware, which means that it can be used in deployed systems to capture rare errors which otherwise are hard to reproduce.

Percepio Tracealyzer consists of two main components:

  • The PC application Tracealyzer, that provide trace visualization. Tracealyzer v4.2.0 officially supports Microsoft Windows and Linux hosts. In the latter case, please refer to the Running on Linux section below.
  • A trace creation component. Tracealyzer supports several third-party solutions provided by RTOS vendors, and Percepio also provides the Percepio Trace Recorder library that supports several RTOSes and soon also bare-metal setups. Read more under the Creating and Loading Traces section.

Running on Linux

Tracealyzer v4.2.0 officially supports running the host application on Linux, using the Mono framework. On some Linux distributions, you may need to install additional libraries. For detailed information, see RunningOnLinux.txt in the Tracealyzer application directory.

User Interface

Tracealyzer offers over 30 views, providing different perspectives of the trace data. There are several ways of accessing and arranging these views.

The most frequently used views are found in the Navigation Bar (the left-side icons). You can adjust the contents of the Navigation Bar in the Navigation Bar Settings (File menu -> Settings).

To overview all views and features in Tracealyzer, select "All Views" as shown above. This provides a brief description of each view along with a thumbnail picture, a button to open the selected view ("Show View") and a User Manual link ("Read More"). You can also open the views by double-clicking on the thumbnail pictures.

You may also access the views from the Views menu, just like in older versions of Tracealyzer.

You can rearrange the views by docking them next to other views, or change the view to a free-floating window. To move a view, place the mouse cursor over the name list in the top (where the "X" close button is), hold down the left mouse button and drag the view. When dragging the view, possible docking targets are displayed. Move the mouse cursor to the desired docking target and release the mouse button. If you release the mouse button when not on a docking target, the view will become a free-floating window. This way, you can combine multiple views and arrange them any way you like.

If you have multiple screens, you can create additional main windows (one for each screen) and move views in between them. To do this, right-click on the name list of the view and select "Undock to New Window".

Mouse Actions

Generally, the mouse buttons behave like this:

  • Left Click
    • Set (or clear) selection, highlighting in all views
  • Left Double-Click
    • Drill-down if available, i.e. show more information about the selection, like opening the Instance Details
    • Set (or clear) selection and focus, scrolling most other views to show the information
  • Right Click
    • Open context menu to get more options

There are three types of views that react to mouse wheel actions:

  • Vertical Timeline
    • Wheel will scroll the timeline (up/down)
      The best example of this view is the Trace View
  • Horizontal Timeline
    • Wheel will scroll the timeline (left/right)
      This includes all plots and histograms, like CPU Load
  • Lists
    • Wheel will scroll the position (up/down)
      This includes anything showing a scroll bar, including this manual

For views with different scroll bars, like Trace View, holding SHIFT will switch the wheel scrolling from the timeline to the view (horizontal).

For views with a timeline, holding CTRL will change from scrolling to zooming; wheel up to zoom in, wheel down to zoom out.

If your mouse has additional buttons the first two ones (which normally handles Browse Forward and Browse Back in your normal web browser) will also zoom in/zoom out.
It is up to the operating system to tell Percepio Tracealyzer which buttons they are, and because of this it is not possible to change these mappings within the application.

View Ports and Sync

A View Port is the part of the trace that is currently in view. By default, Tracealyzer has two view ports, "Details" showing 100 ms and "Overview" showing 10 s, and each timeline view is connected to either Details or Overview. All views connected to same view port are synchronized, so if zooming and scrolling one, all are updated.

You may change the view port of view using the Sync option in the view menu. Selecting "Unsynchronized" means that the view is independent from other view ports. The "Unsynchronized" option can be used the pause views when recording in streaming mode with live visualization.

By Selecting Sync -> Custom..., you may create a new view port for this view. You may then connect other views to your new view port in order to synchronized them.

The View Port Overview view lists all view ports and shown their current position on the trace timeline.

Filtering

By default, filtering is synchronized for all views using the same View Port. This is possible to turn off by using Sync -> Unsynchronized Filter. Note! When the View Port is changed the filter will always be set to that View Port.

When changing the filter using either a built in legend (used in most horizontal views) or the Filter tool, all changes are made directly for each view.

When either filter or view is Unsynchronized this will be indicated by the icon in the menu and by showing "No Sync" in the title bar.

Layouts

A layout is the arrangement of the views in Tracealyzer. You may store and restore the layout using the options in the Layout menu:

  • Reset to Default Layout - Applies the default layout.
  • Remember Layout - Enable this option to let Tracealyzer remember the previously used layout and restoring it when starting Tracealyzer.
  • Layout Locked - If this option is enabled, the views can't be rearranged. Can be useful to prevent accidental changes once you are happy with your layout.
  • Save New Layout - Sets a name for the current layout, so it can be restored later. This allows for having multiple layouts for different kinds of analysis.
  • Manage Layout - Allows for renaming or removing a saved layout.
  • Layouts - Allows for restoring a previously saved layout.

Tool Windows

Apart from all visualizations, Tracealyzer provides Tool Windows that are important to know. Some of these are shown by default, but if you close them, you can open them again from the View menu.

Selection Details show additional information and statistics about the selected entity, e.g. a task in the trace.

Performed Events show a list of all trace events corresponding to the selected entity.

Navigation opens the Navigation Bar, if not displayed.

View Port Overview shows the available view ports, which synchronize the timeline views.

Filter allows for selecting what information that are displayed in the views.

Time Formats

Tracealyzer supports different time formats and modes that can be selected through the View -> Time Format menu.

  • Trace Time - A human readable time mode. The format is typically hh:mm:ss.ms.µs, where the more significant parts are omitted if zero.
  • Native Ticks - The timestamp from the trace format in its native frequency.
  • Event Index - This uses the order of events in Tracealyzer event list instead of time.
  • Wall Time - The full date and time, formatted using .NETs DateTime and TimeSpan objects. This mode is only available when there is some form of time reference.

Time Offset Mode

In addition to different formatting modes, Tracealyzer also supports different offset modes configurable from the View -> Time Offset Mode menu.

  • Relative Trace Start - The first event in the trace is time 0.
  • Relative Trace End - The last event in the trace is time 0. This means everything except the last event will have a negative timestamp.
  • Absolute - The absolute time according to this trace format and/or trace recording solution. This is usually relative to system startup or the point where tracing was enabled.
  • Relative to user defined point - If you right-click a point in any view that has a timeline, you can specify that time as relative time 0.

Creating and Loading Traces

Introduction

This section explains how to create and load traces.

Percepio Trace Recorder

Overview

Tracealyzer relies on a recorder library, that needs to be included in the build of the target system. The recorder library are called by the RTOS kernel in order to store important events, such as context-switches and RTOS API calls. These calls are made using code instrumentation, already available in supported RTOSes. You may also call the recorder library directly in order to store "User Events", allowing for logging any software event or data in your target system. The event data is then transferred to the Tracealyzer application on the host computer for visualization, either continously (streaming) or on demand (snapshot).

The general steps for enabling tracing is to (1) configure the build settings of the RTOS to enable the trace instrumentation, and (2) call the initialization function of the recorder library. You may also need to configure the recorder library to match your processor and target connection.

What recorder library that should be used, and how it should be integrated, however depends on the RTOS used. Percepio provides a recorder library which is used for several RTOSes, including FreeRTOS. This is found in the Tracealyzer application directory, in the <RTOS name>/TraceRecorder subdirectory. Other RTOSes are supported using other recorder libraries and integrations. For instance Keil RTX5, where Tracealyzer relies on the "Event Recorder" library and an interface to Keil uVision.

For details on how to enable tracing, please refer to the below RTOS-specific section(s). Note that Tracealyzer supports several leading RTOSes, but the User Manual only includes those covered by your current license.

Recording Setup and Control

Once you have enabled tracing in your target system, you can start and stop the trace recording from the Tracealyzer application. For instance, you have the "Record a Trace" options on the welcome page, and after loading a trace you find similar trace control buttons in the Navigation Bar. But first, you need to configure Tracealyzer to match your target system setup using the Recording Settings option. The settings can also be accessed from the File menu.

Recording Settings - This is where you configure how the data is to be received from the target system, when using streaming. What settings that are displayed depend on the RTOS and recorder library used. If using an RTOS suppoted by Percepio's own recorder, the Recording Settings looks like this:

Note the FileSystem option, that can be used to replay an already recorded .psf file. By using this option on the provided demo trace, you can easily test the live visualization, without first setting up your target system.

To learn more about on how to configure these settings, see the section below for your specific RTOS.

Record Streaming Trace - Starts a recording in streaming mode, assuming the target system has been configured for trace streaming. This opens the Live Stream view, that displays information about the trace data collection.

By default, Tracealyzer provides live visualization when recording. All views supporting "live mode" are updated continously as the data is received. However, not all views support live update, and some views provide reduced functionallity in this mode.

When using live visualization, the trace data is loaded into Tracealyzer, which may consume several GB of RAM if recording for long durations. Eventually the RAM will fill up, causing reduced performance due to page swapping. However, it is often possible to record up to an hour with live visualization enabled, depending on the data rate and the amount of RAM available.

You may however disable live visualization using a checkbox in the Live Stream view. This way, you can record traces of unlimited duration, as long as you have disk space.

Read Snapshot Trace - Reads the trace buffer from target RAM, assuming the target system has been configured for snapshot trace via a supported interface.

The first time you use "Read Snapshot Trace", you will be asked to select the snapshot interface (if not already done) and the memory range where to search for the trace data. The provided memory range does not need to match the trace buffer exactly, as long as the data is fully included.

Stop Recording - Stops the current recording session and exits the "live mode", if using live visualization. Thereby, all Tracealyzer features are now enabled. If you recorded without live visualization, the trace is now loaded and displayed.

FreeRTOS

Introduction

The trace recorder library is the target system component of Tracealyzer. The recorder integrates with the FreeRTOS kernel and records a trace of RTOS events and your own User Events.

An example trace can be found in the FreeRTOS folder.

The recorder has two main operating modes, described below.

In snapshot mode, the trace data is kept in target RAM, allowing you to take a "snapshot" at any point by saving the contents of the RAM buffer. The snapshot mode is highly optimized for memory efficiency and the resulting data rate is often just 10-20 KB/s, depending on the system. A trace buffer of a few KB is often sufficient to get a decent trace of the most recent events. This can be used in essentially any system, and even used as "black-box" during field testing or in deployed systems.

In streaming mode, the trace data is transfered continuously to the host PC and thereby allows for tracing over long durations. This supports streaming via debug probes such as IAR I-Jet, Keil ULINKpro and SEGGER J-Link, but may also utilize other interfaces in your system, such as USB, TCP/IP, SPI, high-speed UARTs, or device file systems.

The recorder library is provided in C source code, and is found in the FreeRTOS folder in the Tracealyzer installation directory. The snapshot mode and streaming mode share a common API, which makes it easy to switch between them.

Snapshot Mode

The snapshot mode keeps the trace in a target RAM buffer, allowing for saving "snapshots" at any point by saving the RAM buffer to a host-side file. This approach has minimal hardware dependencies and can therefore be used on essentially any 32-bit processor, assuming there is some way to retrieve the data, like a debug connection or a file system.

The snapshot recording is optimized for memory efficiency and saves the events as four-byte records, often using only one such record per event, including the timestamp. As a result, our standard demo application only generates about 18 KB/s of trace data in snapshot mode, less than 7 bytes per event on average. However, the optimizations used in the snapshot mode prevents streaming the trace, so the streaming mode uses a different implementation and data format.

The trace data can be uploaded to your host PC in several ways:

  • Directly from Tracealyzer, for supported debug probes like SEGGER J-Link or ST-LINK.
  • Using a Percepio plugin, like the one we offer for Eclipse-based IDEs.
  • Programmatically in your target system, allowing for custom transfer to host.
  • Manually saving a RAM dump in your debugger IDE (there is often a "Save Memory" function).
  • Using a debugger script, possible in Keil µVision and IAR Embedded Workbench.
The two latter options are usually always possible, independent of processor and development setup. Tracealyzer can open RAM dump files created by any means, as long as the trace data structure (RecorderDataPtr) is fully included. Tracealyzer supports data files in binary format (.bin) and in Intel Hex format (.hex). Note that the RAM dump does not need to match the exact location of the trace data, since Tracealyzer locates the trace data automatically.

The snapshot mode can be used in two ways, decided by the TRC_CFG_SNAPSHOT_MODE setting in trcSnapshotConfig.h:

  • TRC_SNAPSHOT_MODE_RING_BUFFER
  • TRC_SNAPSHOT_MODE_STOP_WHEN_FULL
If using TRC_SNAPSHOT_MODE_STOP_WHEN_FULL, the recorder stops recording when the buffer gets full. This is suitable when you want to capture the events after a particular point in your code, where the recording is started. When using TRC_SNAPSHOT_MODE_RING_BUFFER, the recording is continuous and overwrites the oldest events with the latest. This is suitable for capturing the events before a point in the code, where the recorder is stopped or the system is simply halted. The ring-buffer mode allows for using the recorder as a "black-box flight recorder", especially if you have the possibility to place the recorder buffer in non-volatile RAM or save the trace to a device file system in your general error handling.

It is important that the recorder is not modifying the trace data while saving the snapshot. So before saving the snapshot, you need to either stop the recorder (vTraceStop()) or halt the system, e.g., using a breakpoint. So if you save the trace programmatically while the system is running, make sure to stop the recorder first and also ensure that no new tasks or other kernel objects are created while saving the trace, since this modifies the recorder data.

The recorder library has several settings which you should inspect before using it, such as the two modes described above. The settings are found in the header file trcSnapshotConfig.h, together with detailed documentation.

By default, all events are stored in the same buffer. User events, which are generated by the application, can however be stored in a separate User Event Buffer (UB). This allows for a longer history of less frequent but important user events, since they are not overwritten by kernel events. See the API documentation for xTraceRegisterUBChannel for further information.

For further information on how to use the trace recorder in snapshot mode, see the integration guide, and also the documentation for the Common API and the Extended API for Snapshot mode.

Making a snapshot

This section describes how to upload the trace data from the target system to Tracealyzer, when using snapshot mode.

Integrated support for ST-LINK and SEGGER J-Link
Tracealyzer has built-in support for ST-LINK and SEGGER J-Link (including J-Link compatible debuggers such as Atmel SAM-ICE). This integration works independently of your IDE and supports snapshot trace (see below). The J-Link integration also supports
streaming.
The ST-LINK support is currently limited to snapshot mode.

To upload a snapshot using a SEGGER J-Link or ST-LINK, click the snapshot button in the Navigation Bar.
The trace is then opened in Tracealyzer within a few seconds.

The first time, you get a dialog "Select Memory Region" where you need to enter the address range of the recorder's trace buffer. This can be found by inspecting the trace buffer (RecorderDataPtr) with your debugger (e.g., "watch"). However, you don't need to use the exact memory range, as long as the trace buffer is fully included in the specified memory range. We therefore recommend specifying a larger memory block, to get some tolerance for minor changes in between builds. This setting is saved and reused in between Tracealyzer sessions.

Typical values are 0x0, 0x10000000 or 0x20000000 as start address and 0x10000 or 0x20000 as size (64 KB or 128 KB).

Note: Even if you don't have a stand-alone J-Link or ST-LINK probe, the USB debug connection on your development boards may actually be a J-Link or ST-LINK interface. Those on-board debuggers are supported in the same way as stand-alone debug probes, although their performance may be lower. Look for a ST-LINK or SEGGER J-Link label next to a USB connection on your board.

Snapshot trace using Eclipse-based IDEs
The Percepio Trace Exporter plugin makes it easy to upload trace snapshots from Eclipse-based IDEs. The plugin supports any debug probe that is supported by your Eclipse IDE.

As shown in the above screenshot, the plugin gives you a new "Percepio" menu from which you can save snapshot traces via the currently active debug session, and then open these in Tracealyzer. The plugin finds the trace data automatically, so no need to enter the address of the trace buffer.

To install the plugin, see https://percepio.com/exporter/ for instructions. Note that the plugin does not include Tracealyzer itself, it is a separate download and runs as a standalone application.

The plugin works with most Eclipse-based IDE's, but we have noted issues with some IDEs where the vendors have made changes to the Eclipse debugging framework. In that case, please let us know (support@percepio.com) and we will try to fix it.

Snapshot trace using Xilinx SDK (2018.3)
Unfortunatly our Eclipse plugin is not compatible with Xilinx SDK, but you may use the XSCT Console to save snapshot traces (or otherwise use TCP/IP streaming). Just follow the below steps (but don't type in the quotation marks).

  • Ensure that you are in an active debug session, the target system is halted (e.g. on a breakpoint) and that vTraceEnable(TRC_START) has been executed.
  • Open the XSCT Console, found in the Xilinx menu.
  • Set the working directory where the trace file should be saved by entering "cd [desired output directory]" or simply "cd" to move to your home directory.
  • Enter "print RecorderDataPtr" to see the address of the trace data structure.
  • Enter "print RecorderDataPtr->filesize" to see the size of the trace data structure (in bytes).
  • Enter "mrd -bin -file trace.bin [address] [size in words]" to save the trace data to the host file "trace.bin".
    • Note that RecorderDataPtr->filesize expression gives the size in bytes, not words as expected by the mrd command. It is no problem is you enter the size in bytes instead of the size in words, but it might take a bit longer to save the data. Calculate the word size as [byte size] / [word length, 4 or 8] + 1. In general, you don't need to specify the exact address range. A larger range is fine, as long as the trace data is fully included.
    • You can use CTRL-C to copy the results from the "print" commands and then use CTRL-V to paste them into the "mrd" expression.
  • Open the resulting file (trace.bin) in Tracealyzer.
Within a debug session, you can save multiple traces by repeating the same "mrd" command. Note that you can repeat the XSCT commands in the XSCT console using the arrow keys.

Snapshot trace using Microchip MPLAB X IDE
We provide a plugin for MPLAB X IDE supporting snapshot data upload for Tracealyzer. The plugin can be downloaded here and supports any debug probe that is supported by MPLAB. To learn more about this plugin, read this blog post.

Snapshot trace using IAR Embedded Workbench for ARM
The IAR debugger can be configured to save the trace buffer to a host-side file, either manually or automatically, using a debugger macro. Follow these steps:

  1. Create a macro file in the project directory (e.g. "save_trace_buffer.mac") with the following contents:
    
    __var start;
    __var end;
    
    save_trace_buffer()
    {
    	start = __smessage "Memory:0x",RecorderDataPtr:%x;
    	end  =  __smessage "Memory:0x",(RecorderDataPtr + 1):%x;
    	__memorySave(start,end,"intel-extended", "$PROJ_DIR$\\trace.hex");
    
    	return 0;
    }
                        

  2. Add the macro file under Options -> Debugger -> Use Macro File(s).
  3. When in a debug session, open View -> Macros -> Debugger Macros and check that "save_trace_buffer" is included.
  4. Now, to call the macro and thereby save the trace, you have three options:
    • Manually: In the Debugger Macros view, right-click on you macro and select "Add to Quicklaunch window". Now you can save the trace by double-clicking on the blue "refresh" icon in the Quicklaunch window.
    • On a breakpoint: Place a breakpoint on a suitable location in the code. Open it in the breakpoint editor and enter your macro name (e.g., "save_trace_buffer()") in the Action -> Expression field. The trace is now saved every time that breakpoint is hit.
    • On every halt: To update the trace on every halt, rename the "save_trace_buffer" function to execUserExecutionStopped(). That is a special hook that is called every time the execution is halted. Note that this can slow down single-stepping if the buffer is large.

To enable quick access to Tracealyzer and the current trace, you may include Tracealyzer in the Tools menu, with "trace.hex" specified as parameter.

  1. Select "Configure Tools..." in the Tools menu
  2. Add a new entry "Tracealyzer"
  3. Set the path to the Tracealyzer executable (the ".exe" file).
  4. Set the argument to "$PROJ_DIR$\trace.hex"
This will open Tracealyzer and load the provided trace file.

Snapshot trace using Renesas High-performance Embedded Workshop (HEW)
In the debugger view, when stopped on a breakpoint:

  • Select "Debug" menu, "Save Memory..." (keyboard shortcut: ALT,d,a)
  • In the Save dialog
    • Format: Binary
    • Filename: "name.bin"
    • Start Address: 00000000 (example start address)
    • End Address: 0000FFFF (example end address)
    • Access size: 1
  • Press "Save" button and open "name.bin" in Tracealyzer.

Snapshot trace using Microchip MPLAB v8

  • Select "View" -> "File Registers". This shows you the memory contents.
  • Make sure "Hex" is selected in the bottom left (instead of "Symbolic"). Hex mode seems to be default.
  • Right click in the view and select "Export Table...".
  • In the dialog ("Export As"), make sure "Single Column Output" is selected (seems to be default).
  • Select start address 0x0000 and make sure the end address is beyond the RecorderData structure. The default values seems to be the whole RAM, so you probably don't need to change this.
  • Save as a .mch file and open this file in Tracealyzer.

Streaming trace using STM32 ST-LINK

Streaming is not yet directly supported on ST-LINK, but it is quite easy to reprogram an onboard ST-LINK debug interfaces, found on many ST development boards, with J-Link firmware. This effectively transforms the ST-LINK interface into a J-Link interface. In this way, you can use the built-in J-Link integration (also streaming), although performance will not be on the same level as a stand-alone J-Link. Note that this is an official initiative from SEGGER.

See this blog post for instructions.

Note: This does not work for stand-alone ST-LINK units.

Snapshot trace using Rowley CrossStudio for ARM v3.2

  • Open a "Watch" window and enter "*RecorderDataPtr" (click in the right-side part of the "Name" field to enable editing).
  • Right click on "*RecorderDataPtr" and select "Locate Memory", which opens the Memory view on that specific address range.
  • Right-click anywhere in the Memory view table and select "Save As" and then "Intel Hex" or "Binary".
  • Open the resulting file in Tracealyzer.

Snapshot trace using Keil MDK/µVision

  • Open the "Command" window in µVision
  • Enter the command exec("SAVE \"out.hex\" RecorderDataPtr , (RecorderDataPtr + 1)");
  • Open the resulting file in Tracealyzer, located in the project directory.

You can automate this procedure and get a tool bar button for this command, as illustrated above. To do this, open the "Function Editor" (in "Debug" menu, enabled when debugging...) and add the below code:

FUNC void SavePercepioRecorderData(void) {
printf("Saving Recorder Data in out.hex!\n") ;
exec("SAVE \"out.hex\" RecorderDataPtr , (RecorderDataPtr + 1)");
}
DEFINE BUTTON "Save Recorder Data", "SavePercepioRecorderData()"

Snapshot trace using other IDEs or debug probes
Most debuggers are able to save the RAM contents to a file. Tracealyzer supports the following common formats:

  • Binary (.bin or .dump), supporting gdb, J-Link and Renesas HEW.
  • Intel Hex (.hex), supporting IAR Embedded Workbench and Atmel MemoryLogger.
  • MCH (.mch), supporting Microchip MPLAB 8.
When you store the RAM dump, you must also make sure to select the right region, i.e., start address and size. The recorder data is stored in a single data block, identified by the pointer RecorderDataPtr. This can be found by inspecting RecorderDataPtr with your debugger (e.g., "watch"). However, you don't need to use the exact memory range, as long as the trace buffer is fully included in the specified memory range. We therefore recommend specifying a larger memory block, to get some tolerance for minor changes in between builds. This setting is saved and reused in between Tracealyzer settings.

Streaming Mode

When using the streaming mode, the data is continuously transferred to the host PC. This way, you can record as long as you have disk space on your PC. Since the amount of data produced by RTOS tracing is moderate (about 20-200 KB/s) you may in theory record traces spanning several days, or even weeks with a big hard drive.

The implementation of the streaming mode is optimized for speed, and stores an event much faster than the snapshot mode that is highly optimized for low memory usage.

Connecting and Recording

To connect to the target system in streaming mode, select "Connect to Target System..." in the File menu and click "Start Recording". This establishes a connection with the target and activates the tracing. This assumes the following:

  1. The recorder has been properly integrated in your system.
  2. The recorder has been properly configured for streaming.
  3. The system is running and vTraceEnable() has been called.

When recording, a live graph, updated in real-time, shows the CPU load in the target system.

The red line shows the CPU usage of the application tasks, i.e., the relative number of clock cycles used. This excludes the Idle task, so 100% load means that the Idle task is not executing at all.

Tasks and RTOS API calls are traced automatically. To trace ISRs, you need to call vTraceStoreISRBegin() and vTraceStoreISREnd() in your ISRs. See Recorder API for further details.

  • Start Recording: Sends a "Start Recording" command to the target system (i.e., to the TzCtrl task), and begins capturing trace data from the target. This button toggles between "Start Recording" and "Stop Recording".
  • Stop Recording: Sends a "Stop Recording" command to the target system, waits for the final data, and then finalizes the trace. This button toggles between "Start Recording" and "Stop Recording".
  • Settings: Opens the streaming settings.
  • Save Trace: Allows for saving the trace to a file, without opening it.
  • View Trace: Opens the trace in the main Tracealyzer application. If the trace has not been saved, you'll be prompted to do so.

Note
If using Tracealyzer in parallel with a debugger IDE, the recording must not be active while launching a new debug session, otherwise Tracealyzer may get junk data when the device is programmed.

Stream ports

A stream port is a set of macros that define how the recorder shall write the trace data to the streaming interface, and how to read commands (Start/Stop) from Tracealyzer. The recorder includes several predefined stream ports, defined by the trcStreamingPort.h files found in the streamports directory. The header file contains preprocessor macros and prototypes, while the I/O functions referred to are typically implemented in trcStreamingPort.c. These predefined ports include support for streaming via Arm ITM, e.g. for IAR Embedded Workbench and Keil µVision, SEGGER J-Link debug probes, as well as examples of USB streaming, TCP/IP streaming and streaming to a device file system.

The stream port is selected by including the appropriate trcStreamingPort.h in your compiler's search path. The stream ports may also contain some .c files, that also needs to be included in the build.

Some stream ports use an internal RAM buffer in the trace recorder for temporary storage of the data, periodically flushed to the streaming interface by the trace control task (TzCtrl). This is the default setup. For other stream ports, like the Arm ITM port, the WRITE_DATA macro however writes directly to the streaming interface without involving the trace control task. This requires a fast interface where the data transfer doesn't generate any new trace events (e.g., by RTOS calls) as this would cause infinite recursion.

You can also create your own stream port to utilize any suitable communications interface in your system. Check the provided stream ports and this blog post for a quick introduction.

The main definitions of a stream port (in trcStreamingPort.h) are:

  • TRC_STREAM_PORT_READ_DATA - How to read commands (start/stop) from Tracealyzer via the streaming interface. Should return 0 on success. If streaming e.g. to a device file system (without a PC connection to Tracealyzer) this should be defined as 0.
  • TRC_STREAM_PORT_WRITE_DATA - How the recorder should write trace data to the streaming interface. Should return 0 on success.
There are other TRC_STREAM_PORT_ definitions in trcRecorder.h that can be overridden by redefining them in trcStreamingPort.h, but this is rarely required. One exception is perhaps TRC_STREAM_PORT_USE_INTERNAL_BUFFER, which should be defined as 0 if the stream port is writing directly to the streaming interface instead of using the internal RAM buffer.

SEGGER J-Link Streaming

The J-Link stream port works on all ARM Cortex-M and Renesas RX MCUs. It also works on many ARM Cortex-R and ARM Cortex-A processors, see this application note from SEGGER. With a sufficient RAM buffer size, this allows for streaming the trace data at speeds upwards of 700 KB/s on a standard J-Link (Version 9) and upwards of 2 MB/s on the high-end models. It works even on the J-Link On Board (OB), found integrated on many development boards, although these have lower performance (around 100 KB/s). RTOS tracing usually generates about 20-200 KB/s, so systems with high event rate may require a proper stand-alone J-Link probe.

The SEGGER J-Link streaming uses a proprietary SEGGER feature called RTT, Real-Time Transfer. It relies on RAM buffers in the target system, which the J-Link reads in the background without disturbing the execution. The Tracealyzer recorder uses two RTT buffers, one control channel for receiving commands from Tracealyzer and one data channel for streaming the trace. All source code required for SEGGER RTT is included in the J-Link stream port directory and relevant settings are found in trcStreamingPort.h.

  • TRC_CFG_RTT_BUFFER_SIZE_UP: The size of the target->host RTT buffer, used for streaming the trace data. Default 5000 bytes.
  • TRC_CFG_RTT_BUFFER_SIZE_DOWN: The size of the host->target RTT buffer, used for start/stop commands. Default 32 bytes.
  • TRC_CFG_RTT_UP_BUFFER_INDEX: The RTT buffer index to use for the UP buffer (target->host). Must match the corresponding setting in Tracealyzer (File -> Settings). Default 1.
  • TRC_CFG_RTT_DOWN_BUFFER_INDEX: The RTT buffer index to use for the DOWN buffer (host->target). Must match the corresponding setting in Tracealyzer (File -> Settings). Default 1.
  • TRC_CFG_RTT_MODE: What to do if the streaming buffer becomes full...
    • SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL: The recorder blocks (stalls) the system until the J-Link has made room in the buffer. This is default, since it ensures correct data transfer.
    • SEGGER_RTT_MODE_NO_BLOCK_SKIP: Events are skipped if the RTT buffer is full. If this should occur, the number of dropped events is displayed in Tracealyzer while receiving the trace. Moreover, Tracealyzer also highlights the intervals with incomplete data using a light red background color. We recommend trying this mode as well, to see that the RTT buffer is large enough.

Note that the UP buffer (target->host) is quite large by default (5000 bytes). If you have a stand-alone J-Link probe, you can typically reduce this buffer size to 1-2 KB. If using an integrated J-Link On-board, 5-10 KB can be necessary to maximize throughput - the maximum seem to be about 140 KB/s in this case.

If there would be recorder blocking or dropped trace events, try the following:

  • Verify the J-Link Speed in the Settings dialog of Tracealyzer. Default is 4 MHz, but can be increased a lot depending on your J-Link model. In many cases speeds of 10-20 MHz is possible, but according to SEGGER there is a small risk of getting poor signal quality (i.e., problems) if going above 6 MHz, depending on the development board. But don't worry, nothing will break and any corrupted data will result in obvious error messages when processing the trace. And if you set the J-Link Speed higher than the maximum supported speed, the J-Link driver will instead use the highest speed supported.
  • Increase the trace buffer size (TRC_CFG_RTT_BUFFER_SIZE_UP in trcStreamingPort.h).
  • Reduce the amount of data produced, e.g., by excluding frequent User Events.
  • If using an integrated J-Link OB on your development board, consider upgrading to a stand-alone J-Link probe (which is several times faster).

Before making your first trace recording, please install the latest J-Link drivers and make sure all listed development tools are updated, including Tracealyzer. Also make sure the firmware of your J-Link debug probe is updated correctly, if the J-Link drivers would propose this.

Check J-Link Settings, found under File -> Settings... in Tracealyzer.

  • Debugger: Select the connected J-Link debug probe to use.
  • J-Link Speed: The debugger clock frequency for the JTAG/SWD interface (KHz).
  • Debugger Interface:
    • JTAG: Configures the debug probe for JTAG. This is the default setting of J-Link debug probes.
    • SWD: Configures the debug probe for SWD.
    • Default (don't change): Tracealyzer does not change the JTAG/SWD setting of the debug probe.
      NOTE! It is recommended to explicitly select JTAG or SWD, matching the corresponding setting in your IDE. This "passive" option is known to cause problems with certain J-Link driver versions.
  • Target Device: Opens a SEGGER J-Link dialog where you can select the device (processor). This is necessary in order for SEGGER RTT to connect automatically.

Also check PSF Streaming Settings.

  • Target Connection: Should be "SEGGER RTT".
  • RTT Control Block Address: How to find the RTT control block in the target memory. Normally this should be "auto-detect" (translates to 0). In case the automatic detection fails, we recommend to add the SEGGER_RTT_SECTION definition in the recorder code, as described in Troubleshooting J-Link RTT streaming - The RTT Control Block. It is also possible to specify the address of the RTT control block (_SEGGER_RTT) explicitly in this field, but that option might not work if using Tracealyzer in parallel with an IDE.
  • RTT Up Buffer Index: The RTT buffer to use for the trace data channel (target -> host). Default is 1 and must match the setting in trcStreamingPort.h.
  • RTT Down Buffer Index: The RTT buffer to use for the control channel (host -> target). Default is 1 and must match the setting in trcStreamingPort.h.
  • Reset Target on Connect: Enable this to reset the target system when the recording is started, in order to trace the system startup. For use together with the TRC_START option for vTraceEnable().
  • Target Starts Tracing: Enable this if using the TRC_START option for vTraceEnable(). This way, Tracealyzer won't send a start command when the recording session begins, just wait for the data.

Note
All tools using the J-Link driver (i.e., Tracealyzer and the debugger IDE) must use the same setting for Debugger Interface (JTAG/SWD). So if you sometimes start a Tracealyzer session without an active debug session in your IDE, it is recommended to specify this setting explicitly, using the same setting as your debugger IDE. This to avoid conflicts in the J-Link drivers.



Troubleshooting J-Link RTT streaming

If you will only see "Starting session..." in the Live Stream window, Tracealyzer is not getting any data. In that case, double-check the below steps.

In case Tracealyzer gets some data, but you are having performance problems (e.g. missing events or high overhead) please refer to this FAQ post on our website. Also see the general Troubleshooting section.

  1. Target Device

    Under Settings -> J-Link Settings, make sure you have specified the "Target Device" correctly. The "Select Device..." button shows a list of all devices supported by your SEGGER J-Link driver. This setting is required for the SEGGER driver to locate the RAM address range(s) and find the RTT data structure.

  2. J-Link Driver Version

    Make sure to install the latest J-Link drivers from SEGGER. They are frequently updated, especially for new devices. It is important that the same version of the J-Link driver version is used by Tracealyzer and your IDE. Therefore, make sure to install the latest J-Link drivers as the last step, after Tracealyzer has been installed. After updating the J-Link driver, it may want to update the J-Link firmware as well. We strongly recommend allowing that.

  3. Debugger Interface (JTAG/SWD)

    Make sure the Debugger Interface setting (JTAG/SWD) is the same in Tracealyzer (Settings -> J-Link Settings) as in your debugger IDE. If case they differ, you get a warning from the J-Link driver ("Second debugger connection to the same J-Link detected...", as shown below) and a question if to change the interface setting. In that case, just abort and correct the Tracealyzer setting under Settings -> J-Link Settings.

    Note that Tracealyzer offers a third option in the Debugger Interface setting, Default (don't change). This means that Tracealyzer will not attempt to change the JTAG/SWD selection and instead uses the current setting (e.g. applied by the debugger IDE). This can be convenient in some cases. However, the J-Link probes use JTAG by default and will revert to JTAG if power-cycled. So if using "Default (don't change)" you may get conflicts under certain circumstances and thereby a warning from the J-Link driver (like above). Moreover, some J-Link driver versions (around v6.22 - v6.30) are known to cause problems if not setting the JTAG/SWD selection explicitly in Tracealyzer.

  4. Tool Connection Order

    If using Tracealyzer together with a debugger IDE, make sure to first start the debug session and thereafter connect with Tracealyzer. If modifying your code and reprogramming the device, you need to stop the Tracealyzer recording and then restart the Tracealyzer recording for the new debug session.

    Note that you don't need to start the target system before connecting with Tracealyzer. It is sufficient that the debug session has been launched and that the target is halted in main.

    When using vTraceEnable(TRC_START), we recommend the following order:

    1. Launch the debug session and let the target halt on a breakpoint in main, before vTraceEnable is called.
    2. Select "Start Recording" in Tracealyzer. The "Live Stream" window it should now say "Starting session...", as it waits for data.
    3. Start your target system (resume/run). You will now capture every event after vTraceEnable.
    NOTE: Make sure to CHECK the option "Target Starts Tracing" when using the TRC_START option (Tracealyzer settings -> PSF Streaming Settings).

    If using vTraceEnable(TRC_START_AWAIT_HOST) or vTraceEnable(TRC_INIT), the order is simply:

    1. Launch the debug session and start the target system.
    2. Click "Start Recording" in Tracealyzer.
    NOTE: Make sure to UNCHECK the option "Target Starts Tracing" when using these start options (Tracealyzer settings -> PSF Streaming Settings).

  5. The RTT Control Block

    The J-Link driver needs to locate the address of the RTT control block before the RTT interface can be used. Normally this works automatically, but in some cases it is necessary to configure this manually.

    You can see the status of the J-Link RTT interface in the J-Link Control Panel, that can be accessed via the "J-Link" icons in the task bar (if using Windows). Note that there might be two icons, as shown below. This is not a mistake. Each development tool using the J-Link drivers spawns a separate driver instance, with a separate Control Panel. So if you are using a debugger IDE and Tracealyzer at the same time, you get two control panels. This is normal and supported by SEGGER.

    The J-Link RTT interface is handled by the primary J-Link Control Panel (the first started) while the secondary J-Link Control Panel instance will report "RTT handled by other J-Link instance". If the primary Control Panel reports "Looking for RTT CB", it means that the J-Link driver is still searching for the RTT control block and is not yet ready. This is normal before vTraceEnable has been called, where the J-Link RTT interface is initialized. The J-Link driver should find it directly after vTraceEnable has been called, and then start receiving data.

    In case Tracealyzer is not getting any data and the "Looking for RTT CB" message is still shown after vTraceEnable has been called, it typically means that the J-Link driver is scanning wrong address range. You can verify this by checking the address of _SEGGER_RTT in your debugger and compare with the addresses shown next to the "Looking for RTT CB" message. If incorrect, you can specify the address of the RTT control block (_SEGGER_RTT) in the "RTT Address" field. Make sure that you are using the primary J-Link Control Panel, where the "Looking for RTT CB" message is shown.

    Tracealyzer allows for specifying the address of the RTT Control Block in the PSF Streaming Settings. However, this requires that you know the exact address, and that it does not move between builds. Moreover, it seems the SEGGER J-Link driver only allows for specifying the RTT address in the primary driver instance, i.e. the first one started. The RTT communication is handled by the primary J-Link driver instance. So, if you have started a debug session in your IDE before connecting with Tracealyzer, it seems as the secondary J-Link driver just ignores the RTT address specified by Tracealyzer.

    A better way of resolving this issue is to add a definition of SEGGER_RTT_SECTION in your SEGGER_RTT_Conf.h. This instructs the linker where to place the RTT control block. The J-Link driver only seems to scan the "primary" RAM bank of the device (and only the first 64 KB of this, it seems), but by specifying SEGGER_RTT_SECTION you can make sure _SEGGER_RTT is placed where the J-Link will find it. The _SEGGER_RTT control block is pretty small, so moving it should not be a big deal. This does not contain the actual RTT data buffers, only pointers to them.

    First you need to check what address range that is scanned by the J-Link driver. You see this in the J-Link Control Panel, under "RTT". The scanned addresses appear next to the "Looking for RTT CB" messages.

    Once you know where the J-Link driver expects to find the RTT control block, you need to take a look at your linker file (or linker project settings). The easiest approach is to identify an existing section that is already placed in the right address range, i.e. where the J-Link scans. If so, specify this section in your SEGGER_RTT_SECTION definition to place the RTT control block there.

    In the below example, the scanned address range was 0x20000000 - 0x2000FFFF. In the linker file we noted that this address range contained the ".data" section of RAM2, so we placed it there.

    			   
    /* In SEGGER_RTT_Conf.h */
    #define SEGGER_RTT_SECTION ".data.$RAM2" /* for NXP LPC54018 */
    
    Another solution, that might be "cleaner" but a bit more difficult, is to create a new section dedicated for the RTT control block, that is placed in the desired address range.

TCP/IP Streaming

To stream the trace data over a network connection, i.e., TCP/IP transfer, select the TCPIP stream port. The existing example is for lwIP, so if you are using a different TCP/IP stack you need to modify this accordingly.

The TCP/IP stream port should act as a server, to which Tracealyzer connects as a client. You need to decide on an available TCP port and specify this in the stream port as well as in the Tracealyzer TCP/IP settings, shown below.

This stream port uses the recorder's internal RAM buffer. This is necessary since a TCP/IP stack is quite complex and should not be called directly from the kernel instrumentation code. That may even cause infinite recursive calls, if the TCP/IP stack generates new RTOS events when sending the data.

In Tracealyzer, check the PSF Streaming Settings, found under File -> Settings... in Tracealyzer.

  • Target Connection: Should be "TCP".
  • TCP/IP Address: The IP address of your target system.
  • Port: The port used by target-side TCP/IP socket that you have created for the recorder.

ITM Streaming

The ARM_ITM stream port is a generic solution for streaming over the ITM interface on Arm processors. This is available on virtually all Arm Cortex-M3/M4/M7 MCUs, but not on Arm Cortex-M0/M0+ MCUs.

The benefit of the ITM interface is that the data can be transferred over the SWO pin, available on all Arm Cortex debug connectors. ITM provides hardware buffering, allowing for high data rates. Due to this, it is not necessary to use a RAM buffer for temporary storage, so this stream port instead writes the data directly to the ITM stimulus register. Assuming the ITM buffer has room for the data, a 32-bit word can be written in less than 10 clock cycles.

However, the hardware ITM buffer is pretty small (typically 10 bytes) and the trace data are often generated in bursts that can easily fill the ITM buffer. It is therefore important to use a high SWO frequency (ideally over 30 MHz, in Manchester mode), so the debug probe can pull out the data fast enough.

The stream port blocks in case the ITM buffer is full, but typically only for very brief durations. The worst case blocking time corresponds to the time needed to transmit the full 10 bytes ITM buffer over SWO. At 24 MHz SWO frequency, we have measured this to about 15 µs. However, if you have a fast debug probe like a Keil ULINKpro, blocking does typically not occur.

To receive the data on host side, you need a debugger with high-speed SWO support, at least 10 Mhz, but the faster the better. This is supported by e.g. Keil ULINKpro and IAR I-jet. Moreover, your debugger must allow for outputting the ITM data so Tracealyzer can read it. Both Keil µVision and IAR Embedded Workbench offer such possibilities.

By default, this uses ITM port 1, but this is possible to change in trcStreamingPort.h.

For detailed instructions on how to use this with Keil µVision, see Percepio Application Note PA-021.

For users of IAR Embedded Workbench, see Percepio Application Note PA-023.

USB Streaming

The USB_CDC stream port provides an example of how to stream trace data over a USB connection, using a CDC class endpoint. The example provided is for STM32, with USB drivers generated by STM32Cube. If you are using a different MCU, you need to modify the stream port accordingly.

If your system is already using the USB controller for other purposes, you may consider setting up a Composite Device that includes also a CDC endpoint. The performance of USB (even USB 2.0) is many times more than required for RTOS trace streaming.

The USB stream port uses the recorder's internal RAM buffer. This may not be necessary, depending on the internal buffers in the USB stack. If you need to reduce RAM usage, you can try writing directly in the WRITE_DATA macro, like in the J-Link stream port.

In Tracealyzer, check the PSF Streaming Settings, found under File -> Settings... in Tracealyzer. Select "SerialPort" and specify the COM port (e.g. "COM5") created for this connection. The other settings are not relevant for USB CDC connections. They allow for streaming over a classic UART-based serial connection. This however requires a fast UART and an appropriate stream port.

  • Target Connection: Should be "SerialPort".
  • Device: The COM port created for your USB CDC connection (e.g. "COM5").
  • Others: Not applicable for USB CDC connections.

Custom Streaming

You may configure the streaming to use any interface you have available between target and the host PC, assuming it provides sufficient throughput. The data rate resulting from RTOS tracing depends on your application and RTOS configuration (like tick rate), but typically you need something like 20-200 KB/s. Read more about custom trace streaming in this blog post, RTOS Tracing, your way. For instance, if you have a flash file system on your target system (e.g., a memory card) you can stream to a local file.

To setup a custom transfer method, copy one of the stream port directories and use that as a starting point. The main file is trcStreamingPort.h.

Typically, you only need to define the following macros, together with prototypes for the functions they use:

  • TRC_STREAM_PORT_READ_DATA - How to read commands (start/stop) from Tracealyzer via the streaming interface. Should return 0 on success. If streaming e.g. to a device file system (without a PC connection to Tracealyzer) this should be defined as 0.
  • TRC_STREAM_PORT_WRITE_DATA - How the recorder should write trace data to the streaming interface. Should return 0 on success.
There are other TRC_STREAM_PORT_ definitions in trcRecorder.h that can be overridden by redefining them in trcStreamingPort.h, but this is rarely required. One exception is perhaps TRC_STREAM_PORT_USE_INTERNAL_BUFFER, which should be defined as 0 if the stream port is writing directly to the streaming interface instead of using the internal RAM buffer.

Most stream ports should use the internal RAM buffer in the recorder, in the same way as the TCP/IP port and the USB CDC port. In this case, trcStreamingRecorder.c writes the data to the internal buffer, which is periodically flushed by the trace control task (TzCtrl) to the streaming interface. Note that the buffer used a multi-page structure. The data is not sent until a page becomes full. You may want to tweak the settings for trace control task (periodicity and priority) and also the buffer layout (bytes per page and number of pages). These settings are found in trcStreamingConfig.h.

It is however possible to omit the internal buffer and instead write directly to the transfer channel, but only if (1) the streaming channel is dedicated for this purpose, and (2) the writes do not generate any kernel events, e.g., from Mutex or Semaphore operations.

Tracealyzer can receive the data in four ways, using a TCP connection, a COM port, by opening a file, or via a Named Pipe. The latter is for Windows only. If there the streaming interface doesn't provide two-way communication between Tracealyzer and the target system, you can start the tracing programmatically from target using vTraceEnable(TRC_START), which assumes that the trace interface is ready to receive the data. If using another target connection, you may consider creating a proxy tool that forwards the data to a TCP or COM port, or writes it to a host-side file. The trace data is a binary format and should be stored to a binary file exactly as received. Name the output file ".psf" to make it easier to find in Tracealyzer.

File Structure

The recorder consists of the below files and directories. Some code is specific for the snapshot or streaming modes, but we recommend including all these source files in your build. Any code that is not used by the selected recording mode, is automatically excluded by the preprocessor when compiling the recorder. Check the Recorder Integration section for a step-by-step guide of how to integrate the recorder in your system.

/config trcConfig.h The main configuration of the recorder library.
/config trcSnapshotConfig.h Specific configuration for the snapshot mode.
/config trcStreamingConfig.h Specific configuration for the streaming mode.
/include trcRecorder.h The public API of the recorder. Needs to be included from FreeRTOSConfig.h, as described in the integration guide.
/include trcHardwarePort.h All hardware dependencies. Contains several predefined hardware ports, including ARM Cortex-M, PIC32, Renesas RX etc.
/include trcKernelPort.h FreeRTOS-specific definitions, most notably the trace hook definitions.
/include trcPortDefines.h Various constants for the configuration files.
/streamports JLink_RTT A stream port for SEGGER J-Link debug probes. See trcStreamingPort.h for relevant settings.
/streamports TCPIP A stream port for TCP/IP network connections. The example provided is for lwIP. Defined by trcStreamingPort.h.
/streamports USB_CDC A stream port for USB CDC connections. The example provided is for STM32, with USB drivers generated by STM32Cube. Defined by trcStreamingPort.h.
/ trcSnapshotRecorder.c Implementation of snapshot recording mode.
/ trcStreamingRecorder.c Implementation of streaming recording mode.
/ trcKernelPort.c FreeRTOS-specific functions and definitions.

Integrating the Recorder

Follow the steps below to integrate the trace recorder in an existing project, using snapshot mode with default settings. To use streaming mode, some additional steps are needed.

Step 1. Make sure your project uses FreeRTOS version 7.3 or later. If using an older version of FreeRTOS, upgrading is usually just a drop-in replacement, since backwards-compatible.

Step 2. Locate the trace recorder library in the Tracealyzer installation directory. On Windows, this is found in <Program Files>\Percepio\Tracealyzer 4\FreeRTOS\TraceRecorder. Copy this directory to a suitable location in your code repository, e.g. next to FreeRTOS.

Step 3. Add all three .c files to your project. The files are stripped of any unused code by the preprocessor, based on the recorder configuration.
Step 4. Copy all config headers to a suitable location your project structure, e.g., next to FreeRTOSConfig.h. It is not advised to share these between multiple projects.
Step 5. Add the include directory to your compilers "include paths" to ensure the header files are found, or just copy the headers files to an existing directory where you have other header files for your project.

Step 6. Configure TRC_CFG_HARDWARE_PORT and TRC_CFG_FREERTOS_VERSION in trcConfig.h to reflect your system. Also check the settings in trcSnapshotConfig.h, especially TRC_CFG_NTASK, TRC_CFG_NQUEUE etc. Read more in Configuration and in Tuning the Snapshot Configuration.

Step 7. In your FreeRTOSConfig.h, ensure that you have the following setting:

#define configUSE_TRACE_FACILITY 1

This is the "master switch" for the trace recorder. If you set this to 0, the trace recorder is completely disabled and excluded from the build.

Step 8. Insert the following in FreeRTOSConfig.h, in the end.


/* Integrates the Tracealyzer recorder with FreeRTOS */
#if ( configUSE_TRACE_FACILITY == 1 )
	#include "trcRecorder.h"
#endif
					

Note: Since FreeRTOSConfig.h is also included from some FreeRTOS assembly files, depending on your IDEs you may need to use a conditional include, like in the examples below.


/* IAR Embedded Workbench */
#ifndef __IASMARM__
	#if ( configUSE_TRACE_FACILITY == 1 )
		#include "trcRecorder.h"
	#endif
#endif
                          


/* Microchip MPLAB X IDE */
#ifndef __LANGUAGE_ASSEMBLY
	#if ( configUSE_TRACE_FACILITY == 1 )
		#include "trcRecorder.h"
	#endif
#endif
                          

Step 9. Call vTraceEnable(TRC_START) in your main function to initialize and start the recording. This must be after the initial hardware setup, but before any RTOS objects (tasks etc.) have been created.

Step 10 (optional) Early Recorder Initialization. If your system creates traced kernel objects (i.e. semaphores, mutexes) before hardware is initialized or in some cases even before main(), it is important to ensure the recorder has been initialized prior to that to avoid hardfaults, errors or missing objects.

Step 10.1 Set TRC_CFG_RECORDER_DATA_INIT to 0 in trcConfig.h. This will prevent RecorderInitialized from being initialized to 0.

Step 10.2 Configure TRC_CFG_RECORDER_DATA_ATTRIBUTE in trcConfig.h to set a RAM section attribute to all recorder data that require it. Note: This RAM section must be configured to NOT be zeroed.

Step 10.3 During startup, add the following code to manually clear RecorderInitialized once, and then call vTraceInitialize().

extern "C" uint32_t RecorderInitialized;
RecorderInitialized = 0;
vTraceInitialize();

If you are using C++ you can instead use TraceRecorderInit from the extras folder and call TraceRecorderInit::Initialize().

TraceRecorderInit::Initialize();

Note
For Arm Cortex-M devices, the recorder needs the Arm CMSIS library. To ensure this is accessible from the recorder code, we recommend including your processor's header file (e.g., "lpc17xx.h", "stm32f4xx.h", "board.h", etc.) from your trcConfig.h.

If you run into problems, please refer to the Troubleshooting section.

Tracing on a 16-bit architecture

If you're not running on 32-bit architecture, make sure that all kernel objects have 32-bit IDs.
Examples:


/* In struct tskTaskControlBlock in tasks.c */
UBaseType_t uxTaskNumber; /* This will only be 32-bit if a 32-bit architecture is used. */

/* In struct QueueDefinition in queue.c */
UBaseType_t uxQueueNumber; /* This will only be 32-bit if a 32-bit architecture is used. */

/* In struct EventGroupDef_t in event_groups.c */
UBaseType_t uxEventGroupNumber; /* This will only be 32-bit if a 32-bit architecture is used. */

/* In struct StreamBufferDef_t in stream_buffer.c */
UBaseType_t uxStreamBufferNumber; /* This will only be 32-bit if a 32-bit architecture is used. */

/* In struct tmrTimerControl in timers.c */
UBaseType_t uxTimerNumber; /* This will only be 32-bit if a 32-bit architecture is used. */
            

Setting up Streaming

Assuming you have followed the recommended steps for basic integration, the following additional steps are needed to enable streaming.

  1. In trcConfig.h, set TRC_CFG_RECORDER_MODE to TRC_RECORDER_MODE_STREAMING.
  2. Decide on which stream port to use, i.e., how to transfer the trace data from target to host.
  3. Specify the stream port to use. This is done by updating your compiler's include search paths to include the directory of your trcStreamingPort.h (e.g, "/streamports/Jlink_RTT/include").
  4. If the selected stream port contains any .c files, those should also be added to your project.
  5. In your vTraceEnable call, for streaming you should normally use TRC_INIT or TRC_START_AWAIT_HOST. See the vTraceEnable documentation for details.

If you run into problems, please refer to the Troubleshooting section.

Configuration

The trace recorder library have several settings that allow for tuning the recorder setup. The main settings are found in trcConfig.h.

  • TRC_CFG_RECORDER_MODE - Selects the recording mode (snapshot or streaming mode).
  • TRC_CFG_HARDWARE_PORT - Selects the hardware port, i.e., the hardware-specific definitions in trcHardwarePort.h.
  • TRC_CFG_FREERTOS_VERSION - Must match your version of FreeRTOS.
  • TRC_CFG_RECORDER_BUFFER_ALLOCATION - Select how the recorder's data structure are allocated:
    • TRC_RECORDER_BUFFER_ALLOCATION_STATIC: Static allocation at compile time, inside the recorder library.
    • TRC_RECORDER_BUFFER_ALLOCATION_DYNAMIC: Dynamic allocation on the heap, inside vTraceEnable. May fail if there is not enough heap space.
    • TRC_RECORDER_BUFFER_ALLOCATION_CUSTOM: In the custom allocation mode, you make the necessary allocation yourself and then register the buffer using vTraceSetRecorderDataBuffer, before calling vTraceEnable. If combined with linker directives, you can place the recorder data in a fixed memory location of your choice.

trcSnapshotConfig.h contains specific settings for the snapshot mode. Some examples are:

  • TRC_CFG_SNAPSHOT_MODE - If to stop recording when the buffer becomes full, or use ring-buffer mode.
  • TRC_CFG_EVENT_BUFFER_SIZE - The size of the event buffer, expressed as the number of 4-byte records.
  • TRC_CFG_NTASK, TRC_CFG_NQUEUE, etc. - The maximum number of simultaneously active objects, i.e., the number of created objects minus the number of deleted/closed objects, of each type.
  • TRC_CFG_SYMBOL_TABLE_SIZE - The size of the Symbol Table, used for storing strings in an efficient manner, e.g., for User Events channel names and the names of deleted/closed objects.
  • USE_SEPARATE_USER_EVENT_BUFFER – Allows longer history of User Events by storing them in the separate User Event Buffer (UB).

trcStreamingConfig.h contains specific settings for the streaming mode. Some examples are:

  • TRC_CFG_SYMBOL_TABLE_SLOTS - The maximum number of symbols names that can be stored, including names for tasks and traced ISRs, other named kernel objects and user event channels.
  • TRC_CFG_SYMBOL_MAX_LENGTH - The maximum length of symbol names.
  • TRC_CFG_OBJECT_DATA_SLOTS - The maximum number of "object data entries", used to store task priorities. Must be sufficient for all simultaneously active tasks, i.e., the number of created tasks minus the number of deleted/closed tasks.
  • TRC_CFG_CTRL_TASK_PRIORITY - The scheduling priority of the TzCtrl task, that receive start/stop commands from Tracealyzer. Some stream ports also rely on this task to transmit the data from the internal buffer to the stream interface (most except for the J-Link port). If your system is highly loaded, you may need to increase the priority of this task to ensure it can execute periodically.
  • TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT - The number of pages used by the internal trace buffer. This may need to be increased if there are missed events.
    (Not used by the J-Link stream port, see below).
  • TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE - Specifies the size of each page in the internal trace buffer. This can be tuned to match any internal low-level buffers used by the streaming interface, like the Ethernet MTU (Maximum Transmission Unit).
    (Not used by the J-Link stream port, see below).

Note
If using the J-Link RTT stream port, the "page count" and "page size" settings are not used. The settings for the RTT buffers are instead found in trcStreamingPort.h.

Tuning the Snapshot Configuration

In snapshot mode, there are several settings that affect RAM usage, e.g., TRC_CFG_EVENT_BUFFER_SIZE, TRC_CFG_SYMBOL_TABLE_SIZE, TRC_CFG_NTASK, TRC_CFG_NQUEUE and a few more. TRC_CFG_EVENT_BUFFER_SIZE is usually the main factor, as it controls the size of the main event buffer. This is by default 4000 bytes. The usage of this buffer can be reduced in several ways described in the Recorder API e.g. by excluding certain objects or by only including task-switches.

TRC_CFG_SYMBOL_TABLE_SIZE is typically the second largest factor, by default 800 bytes. This controls the size of the symbol table, allowing efficient storage of names, format strings, etc.
TRC_CFG_NTASK, TRC_CFG_NQUEUE and a few similar ones controls the size of the object table, that is used for keeping track of the active RTOS objects.

TRC_CFG_SYMBOL_TABLE_SIZE and TRC_CFG_NTASK etc. must not be too small, as that would cause the recorder to report an error and stop recording. It is therefore advised to start with relatively large values. But too large values will waste precious RAM. Tracealyzer can however report the resource usage from a trace session, allowing you to tune these settings and thereby optimize the RAM usage. Assuming you have a snapshot trace open in Tracealyzer, this is found under View -> Trace Overview.

Note the entries under Object Table - they show the number of slots allocated, based on TRC_CFG_NTASK, TRC_CFG_NQUEUE, etc., and also the actual usage of these slots. Each Object Table slot holds meta data about an active RTOS object, like a task or a queue, and requires about 20 bytes each, depending on the maximum name lengths specified in TRC_CFG_NAME_LEN_TASK etc. (this can also be tuned, to further reduce RAM usage). In this example, TRC_CFG_NQUEUE was set to 10 but only 3 queues were created by the system, meaning that TRC_CFG_NQUEUE can be reduced to 3. If optimizing all these settings, we can thereby eliminate 34 slots and free up about 680 bytes of RAM.

Troubleshooting

If you get build errors, make sure that TRC_CFG_FREERTOS_VERSION is specified correctly in trcConfig.h.

Runtime errors in the recorder are often captured by the ASSERT macros. They call prvTraceError or prvTraceWarning if an internal error is detected in the recorder code, e.g., due to incorrect parameters or configuration. This attempts to save the error message in the trace and then stops the recorder. The error message is then presented when opening the trace.

But if no error message is presented, or you like to see the context of the error, it is advised to put a breakpoint inside prvTraceError and/or prvTraceWarning. Note that this function has two implementations, one in trcSnapshotRecorder.c and another in trcStreamingRecorder.c.

You may also call xTraceGetLastError() in order to obtain any error messages in your target code. This returns NULL if no error messages are available.

In case you get "hard faults" (i.e. crashes...) when adding the recorder, this is often due to a stack overflow. The added instrumentation will increase the stack usage of your tasks somewhat, as a few function calls are added to the call stacks. If your application was close to a stack overflow before, this might push it over the edge. In that case, increase the stack size where necessary. Note that some RTOSes include stack overflow detection, although not always 100% reliable.

In case you have problems connecting to the recorder in streaming mode, or it reports lost events, make sure to check the following.

  • Double-check the streaming settings in Tracealyzer (File -> Settings). Also check that the stream port settings match where relevant.
  • Using a SEGGER J-Link and RTT streaming? See the Troubleshooting J-Link RTT streaming section above.
  • Check that tracing is properly started. Put a breakpoint in prvSetRecorderEnabled() in trcStreamingRecorder.c and check if it's reached. If using vTraceEnable(TRC_INIT) or vTraceEnable(TRC_START_AWAIT_HOST), this function is only called when the "start tracing" command is received from Tracealyzer. If the breakpoint is not hit, no such start command is received from the connection, indicating a general connection problem. Note: if using vTraceEnable(TRC_START) the prvSetRecorderEnabled function is called directly from within vTraceEnable.
  • Is the trace control task (TzCtrl) executing? Put a breakpoint in the start of this task to verify this. Note that TzCtrl normally is started automatically from vTraceEnable.
  • Is your streaming interface sufficiently fast to handle the data produced? If not, there may be lost events or blocking in the recorder, depending on your recorder settings. If blocking mode is used, this may affect the timing of your system, but ensures that data is not lost. In case of data loss, Tracealyzer will show a counter for "dropped events" in the "Connect to target system" window.
    • Make sure the trace buffer is sufficiently large. If using J-Link streaming, you find the buffer size setting in trcStreamingPort.h, otherwise in trcStreamingConfig.h.
    • In most stream ports except J-Link, the trace control task (TzCtrl) performs the writing to the streaming interface. In such cases, try reducing TRC_CFG_CTRL_TASK_DELAY to make it execute more frequently. Especially if you don't have enough RAM for a larger buffer.
    • If your system is highly loaded, you might need to increase the priority of the trace control task to make sure it runs periodically. This is done by increasing TRC_CFG_CTRL_TASK_PRIORITY. This is relevant for stream ports that use the internal paged buffer, e.g., TCP/IP and UDB CDC, but not J-Link.
  • Check if you get any warnings related to TRC_STREAM_PORT_WRITE_DATA or TRC_STREAM_PORT_READ_DATA. These define the I/O functions used by the stream port to read commands and write trace data, and should return zero (0) on success. Any other return values result in warnings (e.g. "TRC_STREAM_PORT_WRITE_DATA returned error (!= 0)"). This can be checked by calling xTraceGetLastError() (returns a string, or NULL if no error), or by placing a breakpoint in prvTraceWarning().

What if the trace can be recorded, loaded into Tracealyzer but doesn't contain any task-switches or kernel calls? This typically means that the trace macro definitions are not included into the kernel, so the recorder is not notified of the events. Make sure you have included trcRecorder.h from your FreeRTOSConfig.h, as described in the integration guide.

If events appear to be occurring in the (startup) task, but you know for certain that they actually take place in another task, you have found a known FreeRTOS issue. When the scheduler is started the first task switch never calls upon the proper trace macro. This is fixed as of FreeRTOS v10.1.0. If an upgrade isn't possible for you, you can easily patch the kernel yourself. It is a very minor fix in vTaskStartScheduler() in tasks.c: portCONFIGURE_TIMER_FOR_RUN_TIME_STATS(); traceTASK_SWITCHED_IN(); /* Setting up the timer tick is hardware specific and thus in the portable interface. */ if( xPortStartScheduler() != pdFALSE )

And finally, don't hesitate to contact support@percepio.com if you need assistance.

Recorder API

This section describes the public API of the trace recorder library, used in both snapshot and streaming mode. The API is found in trcRecorder.h.

Note that the API has two parts, the Common API (just below) and the Extended Snapshot API, with functions that are only relevant for advanced usage of the snapshot mode.

If you would run into problems, please refer to the Troubleshooting section.

Common API

vTraceEnable

void vTraceEnable(int startOption)

Initializes and optionally starts the trace, depending on the start option.

When the trace recorder is included, you must call vTraceEnable in your startup code, before any RTOS calls are made (including "create" calls) but after the initial hardware setup (of clocks etc.).

The parameter startOption should be one of:

  • TRC_START:

    Starts the tracing directly.

    vTraceEnable(TRC_START) can be called in two ways - either directly in the startup, or from a task after the kernel has started. However, the recorder must always be initialized before the RTOS is started, so if not starting the trace directly, you should call vTraceEnable(TRC_INIT) in the startup code.

    In streaming mode, this option is recommended if the recorder is controlled from target code, without a direct Tracealyzer connection, e.g., if streaming to a device file system.

    The TRC_START option may also be used when streaming directly to the Tracealyzer application. In that case, make sure to enable "Target Starts Tracing" in the Tracealyzer PSF streaming settings. Or, if you are using TCP/IP tracing, make sure to use the "TCP (Target initiated)" option.

    If using J-Link RTT streaming, you may combine vTraceEnable(TRC_START) with the "Reset on Connect" option. This will reset the target system when clicking "Start Recording" in Tracealyzer and trace the system from the startup, without having to reset it manually in your debugger IDE.

    An alternative to "Reset on Connect" is to instead set a breakpoint in the early startup. Launch a debug session and let the system halt on the breakpoint. Then select Start Recording in Tracealyzer so it begins waiting for data, and finally resume the target system execution.

  • TRC_START_AWAIT_HOST:

    Waits for a Start command from Tracealyzer ("Start Recording" button) and then begins tracing from this point. This way, you don't miss the initial events.

    This is not supported in snapshot mode, but for streaming mode only. Intentionally blocking!

    This option is only intended to be used when calling vTraceEnable from the startup code, i.e., before the RTOS has been started. Thus, this option requires that the stream port has two-way communication and that the stream port is fully operational before the RTOS kernel has started. It works fine with J-Link RTT streaming, but we don't recommend this method for other stream ports.

    When using this option, make sure that "Target Starts Tracing" is NOT selected in the Tracealyzer PSF streaming settings.

  • TRC_INIT:

    Initializes the trace recorder, but does not start the tracing.

    You don't need to call vTraceEnable(TRC_INIT) if you call vTraceEnable(TRC_START) or vTraceEnable(TRC_START_AWAIT_HOST) in the startup code, as these options also initialize the recorder if needed. However, if you prefer to start the recording at a later point (after the RTOS has started) you need to call vTraceEnable(TRC_INIT) in the startup code.

    If using streaming mode, you can start the tracing from Tracealyzer ("Start Recording" button) as long as vTraceEnable(TRC_INIT) or vTraceEnable(TRC_START_AWAIT_HOST) has been called.

    When using this option in streaming mode, make sure that "Target Starts Tracing" is NOT selected in the Tracealyzer PSF streaming settings.

Examples:
Snapshot mode Streaming mode

myBoardInit();
...
/* From startup */
vTraceEnable(TRC_START);
...
/* RTOS scheduler starts */
vTaskStartScheduler();
                      

myBoardInit();
...
/* From startup - blocks until start from host */
vTraceEnable(TRC_START_AWAIT_HOST);
...
/* RTOS scheduler starts */
vTaskStartScheduler();
					   

myBoardInit();
...
/* Init only, trace starts later...*/
vTraceEnable(TRC_INIT);
...
/* RTOS scheduler starts */
vTaskStartScheduler();
...
/* In a task or ISR */
vTraceEnable(TRC_START);
                      

myBoardInit();
...
/* Init only, trace starts later...*/
vTraceEnable(TRC_INIT);
...
/* RTOS scheduler starts */
vTaskStartScheduler();
...
/* "Trace Start" command from Tracealyzer
is received by TzCtrl task. */
                      

The tracing does not start if the recorder has detected an error, e.g. related to the configuration. An error message is then presented when opening the trace. To see the context of the error, put a breakpoint inside prvTraceError. Note that prvTraceError has two alternative implementations, one for snapshot mode and another for streaming.

vTraceStop

void vTraceStop(void)

Stops the recording. Mainly intended for snapshot mode or if streaming to device storage or a USB drive, without host control.

vTracePrintF

void vTracePrintF(traceString chn, const char* fmt, ...)

Generates User Events, i.e., formatted text and data, with similar interface as a classic "printf" call. User Events can be used for very efficient logging from your application code. It is very fast since the actual string formatting is done on the host side, when the trace is displayed. The execution time is measured in microseconds on a 32-bit MCU.

User Events are shown as yellow labels in the main trace view, if enabled in the View Filter.

User Events with data arguments can also be plotted in the User Event Signal Plot. This way, you can visualize any kind of data that your code can access, such as software states, hardware states, system inputs and outputs.

You may group User Events into named channels, for filtering in Tracealyzer. The yellow User Event labels show the logged string, preceded by the channel name within brackets ("[MyChannel] Hello World!").

The User Event Channels are shown in the View Filter, which makes it easy to select what User Events you wish to display. User Event Channels are created using xTraceRegisterString().

Example:


traceString adc_uechannel = xTraceRegisterString("ADC User Events");
...
vTracePrintF(adc_uechannel,	"ADC channel %d: %d volts", ch, adc_reading);
                  

The following format specifiers are supported in both modes:
%d - signed integer.
%u - unsigned integer.
%X - hexadecimal, uppercase.
%x - hexadecimal, lowercase.
%s - string (see comment below)

For integer formats (%d, %u, %x, %X) you may also use width and padding specifiers. For example, assuming -42 as data argument, two examples are:


"%05d" -> "-0042"
"%5d" -> " -42"

String arguments are supported in both snapshot and streaming, but in streaming mode you need to use xTraceRegisterString and use the returned traceString as the argument. In snapshot mode you simply provide a char* as argument.

Snapshot:

vTracePrintF(myChn, "my string: %s", str);
Streaming:
vTracePrintF(myChn, "my string: %s", xTraceRegisterString(str));

In snapshot mode you can specify 8-bit or 16-bit arguments to reduce RAM usage.

vTracePrintF(myChn, "%hd", val); // 16 bit (h) signed integer (d)
vTracePrintF(myChn, "%bu", val); // 8 bit (b) unsigned integer (u)

In streaming mode all data arguments are assumed to be 32 bit wide. Width specifiers (e.g. %hd) are accepted but ignored, so e.g., %hd is treated like %d.

The maximum event size also differs between the modes. In streaming this is limited by a maximum payload size of 52 bytes, including format string and data arguments. So if using one data argument, the format string is limited to 48 byte, etc. If this limit is exceeded, the format string is truncated and you get a warning in Tracealyzer.
In snapshot mode you are limited to maximum 15 arguments, that must not exceed 32 bytes in total (not counting the format string). If exceeded, the recorder logs an internal error (displayed when opening the trace) and stops recording.

vTraceVPrintF

void vTraceVPrintF(traceString chn, const char* fmt, va_list vl)

vTracePrintF variant that accepts a va_list. This can be used to integrate with existing logging solutions. See vTracePrintF documentation for further details.

Example:


traceString debugChannel = xTraceRegisterString("Debug");
...
void vDebugPrintF(char* fmt, ...)
{
	va_list vl;

	va_start(vl, fmt);
	vTraceVPrintF(debugChannel, fmt, vl);
	va_end(vl);
}
                  

vTracePrint

void vTracePrint(traceString chn, const char* str)

A faster version of vTracePrintF for logging strings without data arguments.

Example:


traceString chn = xTraceRegisterString("MyChannel");
...
vTracePrint(chn, "Hello World!");
                  

xTraceRegisterString

traceString xTraceRegisterString(const char* name)

Storing strings generally require that they are assigned a traceString handle, provided by this function. Duplicates are avoided by reusing any previous handle, if there already is an identical string saved.

Example:

traceString chn = xTraceRegisterString("MyChannel");
...
vTracePrint(chn, "Hello World!");
vTracePrintF(chn, "Value: %d", myValue);
                

vTraceConsoleChannelPrintF

void vTraceConsoleChannelPrintF(const char* fmt, ...)

Wrapper for vTracePrint, intended to be used as a drop-in replacement for printf and similar console print functions, e.g. in a debug logging macro.

Example:

// Replace this old logging macro
// #define LogString uart_printf
                  
// Log to Tracealyzer instead                  
#define LogString vTraceConsoleChannelPrintF 
...                  
LogString("My value is: %d", myValue);
                

vTraceSet...Name

void vTraceSetQueueName(void* object, const char* name)
void vTraceSetSemaphoreName(void* object, const char* name)
void vTraceSetMutexName(void* object, const char* name)
void vTraceSetEventGroupName(void* object, const char* name)
void vTraceSetStreamBufferName(void* object, const char* name)
void vTraceSetMessageBufferName(void* object, const char* name)

Functions for setting names of kernel objects, for display in Tracealyzer.

Parameter object: pointer to the kernel object that shall be named (e.g., a queue).
Parameter name: the name to display in Tracealyzer.

xTraceSetISRProperties

traceHandle xTraceSetISRProperties(const char* name, uint8_t priority)

Stores a name and priority level for an Interrupt Service Routine, to allow for better visualization. Returns a traceHandle used by vTraceStoreISRBegin.

Example:


#define PRIO_ISR_TIMER1 3 /* the hardware priority level */
traceHandle Timer1Handle;

void main()
{
	Timer1Handle = xTraceSetISRProperties("ISRTimer1", PRIO_ISR_TIMER1);
	...
}

void ISR_handler()
{
	vTraceStoreISRBegin(Timer1Handle);
	...
	vTraceStoreISREnd(0);
}
                

vTraceStoreISRBegin

void vTraceStoreISRBegin(traceHandle handle);

Registers the beginning of an Interrupt Service Routine, using a traceHandle provided by xTraceSetISRProperties.

Example:


#define PRIO_ISR_TIMER1 3 /* the hardware priority level */
...
traceHandle Timer1Handle = xTraceSetISRProperties("ISRTimer1", PRIO_ISR_TIMER1);
...
void ISR_handler()
{
	vTraceStoreISRBegin(Timer1Handle);
	...
	vTraceStoreISREnd(0);
}
                

vTraceStoreISREnd

void vTraceStoreISREnd(int isTaskSwitchRequired)

Registers the end of an Interrupt Service Routine.

The parameter pendingISR indicates if the interrupt has caused a task-switch (= 1), e.g., by signaling a semaphore. Otherwise (= 0) the interrupt is assumed to return to the previous context.

Example:


#define PRIO_ISR_TIMER1 3 /* the hardware priority level */
...
traceHandle Timer1Handle = xTraceSetISRProperties("ISRTimer1", PRIO_ISR_TIMER1);
...
void ISR_handler()
{
  signed BaseType_t xHigherPriorityTaskWoken;
  vTraceStoreISRBegin(Timer1Handle);

  /* Wakes up a pending task, causing a task-switch */
  xSemaphoreGiveFromISR(xSemaphore, &xHigherPriorityTaskWoken);
  vTraceStoreISREnd(xHigherPriorityTaskWoken);
}
				

vTraceInstanceFinishedNow

void vTraceInstanceFinishedNow(void)

Creates an event that ends the current task instance at this very instant.
This informs the viewer to split the current fragment at this point and begin a new actor instance, even if no task-switch has occurred.

vTraceInstanceFinishedNext

void vTraceInstanceFinishedNext(void)

Marks the current "task instance" as finished on the next kernel call.

If that kernel call is blocking, the instance ends after the blocking event and the corresponding return event is then the start of the next instance.
If the kernel call is not blocking, the viewer instead splits the current fragment right before the kernel call, which makes this call the first event of the next instance.

vTraceSetRecorderDataBuffer

void vTraceSetRecorderDataBuffer(void* pRecorderData)

The recorder supports three modes of allocating the trace data structure: static, dynamic and custom allocation mode. In custom allocation mode (TRC_RECORDER_BUFFER_ALLOCATION_CUSTOM) you are expected to declare and allocate the buffer yourself, intended for maximum control. If you combine this with linker directives, you can place the recorder data in a specific memory location. Then use vTraceSetRecorderDataBuffer to register the buffer in the recorder, before calling vTraceEnable.

To declare a trace buffer, use the macro TRC_ALLOC_CUSTOM_BUFFER. This is portable and independent of recording mode. Moreover, it is ignored if you don't use custom allocation mode.

Example:


/* Allocate, typically in global context */
TRC_ALLOC_CUSTOM_BUFFER(myTraceBuffer)

/* Register the buffer, before vTraceEnable */
vTraceSetRecorderDataBuffer(&myTraceBuffer);

vTraceEnable(TRC_INIT);
                

xTraceGetLastError

char* xTraceGetLastError(void)

Returns the first registered error in the recorder, if any, as a string. The return value is NULL if no errors have been registered. The errors reported here are typically from internal "assert" statements within the recorder code, that checks the configuration and inputs.

Any error or warning is also shown in Tracealyzer when loading the trace, assuming a trace could be created. In streaming mode, this however requires User Events to be enabled (see trcConfig.h).

To get more information about the context of the error, put a breakpoint in prvTraceError and/or prvTraceWarning. Then start a debug session and reproduce the problem. Then check the call stack in your debugger to see what recorder operation that resulted in the error.

vTraceClearError

void vTraceClearError(void)

Clears any internal errors from the recorder (see also xTraceGetLastError).

vTraceSetFrequency

void vTraceSetFrequency(uint32_t frequency)

Registers the clock rate of the timestamping time source. Allows for overriding the default value (TRC_HWTC_FREQ_HZ) in case this would be incorrect for your setup.

Note: In snapshot mode, the frequency value is divided by the TRC_HWTC_DIVISOR, and may therefore seem lower than expected in the Trace Overview.

xTraceIsRecordingEnabled

int xTraceIsRecordingEnabled(void)

Returns true (1) if the recorder is enabled (i.e. is recording), otherwise 0.

vTraceSetFilterMask

void vTraceSetFilterMask(uint16_t filterMask)

Note: This is disabled in FreeRTOS v7.3 since it uses an incompatible data type for object numbers.

Sets the Filter Mask, used for filtering the events based on the object they refer to, such as tasks, queues, semaphores and mutexes. This can be used to reduce the trace data rate, i.e., if your streaming interface is a bottleneck or if you want longer snapshot traces without increasing the buffer size.

The parameter filterMask should include one or several Filter Group IDs (FilterGroup0 .. FilterGroup15). Multiple filter groups can be included using a bitwise OR expression, for example: FilterGroup0 | FilterGroup3 | FilterGroup6.

Every kernel object is assigned to a specific filter group. By default, all kernel object are assigned to FilterGroup0, but this can be changed using vTraceSetFilterGroup.

An event is included if the following bitwise AND condition is true:

Object.FilterGroup & FilterMask != 0
This means that if calling vTraceSetFilterMask(FilterGroup0 | FilterGroup2), we include events from filter groups 0 and 2, but exclude all events from the other filter groups.

Example:


// Assign tasks T1 to FilterGroup0 (default)
[Create Task T1]

// Assign Q1 and Q2 to FilterGroup1
vTraceSetFilterGroup(FilterGroup1);
[Create Queue Q1]
[Create Queue Q2]

// Assigns Q3 to FilterGroup2
vTraceSetFilterGroup(FilterGroup2);
[Create Queue Q3]

// Only include FilterGroup0 and FilterGroup2, exclude FilterGroup1 (Q1 and Q2) from the trace
vTraceSetFilterMask( FilterGroup0 | FilterGroup2 );

// Assign the default RTOS objects (e.g. Idle task) to FilterGroup0
vTraceSetFilterGroup(FilterGroup0);
[Start the RTOS scheduler]
                
Note: There are two kinds of filters in the recorder. While vTraceSetFilterMask and vTraceSetFilterGroup provides filtering on object-level, it is also possible to filter by event type/category, regardless of object. See the TRC_CFG_INCLUDE... settings in trcConfig.h.

vTraceSetFilterGroup

void vTraceSetFilterGroup(uint16_t filterGroup)

Note: This is disabled in FreeRTOS v7.3 since it uses an incompatible data type for object numbers.

Sets the Filter Group for kernel objects created after this point, such as tasks, queues, semaphores and mutexes. Together with vTraceSetFilterMask, this allows you to filter the events based on the objects they refer to. This can be used to reduce the trace data rate, i.e., if your streaming interface is a bottleneck or if you want longer snapshot traces without increasing the buffer size. And by grouping related objects into filter groups, you can exclude whole subsystems from the trace simply by changing the filter mask.

The parameter filterGroup should be one of the 16 predefined filter groups IDs, named FilterGroup0 .. FilterGroup15, corresponding to each bit in the filter mask. The provided ID is stored and assigned to every kernel object created after this point, including tasks, queues, semaphores and mutexes. You typically call vTraceSetFilterGroup at multiple occations in your startup code to divide your kernel objects into multiple filter groups.
Note: We don't recommend filtering out tasks, as this can affect the visualizations in unexpected ways. It can however be motivated for frequent, periodic tasks with short execution time. To avoid filtering out the Idle task by accident, make sure to call vTraceSetFilterGroup(FilterGroup0) before starting the RTOS scheduler in order to restore the default assignment.

Example:


// Assign tasks T1 to FilterGroup0 (default)
[Create Task T1]

// Assign Q1 and Q2 to FilterGroup1
vTraceSetFilterGroup(FilterGroup1);
[Create Queue Q1]
[Create Queue Q2]

// Assigns Q3 to FilterGroup2
vTraceSetFilterGroup(FilterGroup2);
[Create Queue Q3]

// Only include FilterGroup0 and FilterGroup2, exclude FilterGroup1 (Q1 and Q2) from the trace
vTraceSetFilterMask( FilterGroup0 | FilterGroup2 );

// Assign the default RTOS objects (e.g. Idle task) to FilterGroup0
vTraceSetFilterGroup(FilterGroup0);
[Start the RTOS scheduler]
                

Note that you may define your own names for the filter groups using preprocessor definitions, to make the code easier to understand. Example:


#define BASE FilterGroup0
#define USB_EVENTS FilterGroup1
#define CAN_EVENTS FilterGroup2
...
vTraceSetFilterMask( BASE | CAN_EVENTS );
                
Note: There are two kinds of filters in the recorder. While vTraceSetFilterMask and vTraceSetFilterGroup provides filtering on object-level, it is also possible to filter by event type/category, regardless of object. See the TRC_CFG_INCLUDE... settings in trcConfig.h.

Extended API for Snapshot Mode

This section describes the extended API for snapshot mode, with extra functions that are typically only needed for more advanced setups. The extended API is not self-contained but should be used together with the Common API when in snapshot mode.

xTraceGetTraceBuffer

void* xTraceGetTraceBuffer(void)

Returns a pointer to the snapshot trace buffer, for programmatic access. See also uiTraceGetTraceBufferSize.

Example:


/* Save the snapshot trace buffer */
f = fopen("mytrace.bin","wb");
ptr = xTraceGetTraceBuffer();
size = uiTraceGetTraceBufferSize();
vTraceStop();
fwrite(ptr, size, 1, f);
fclose(f);
vTraceClear();
vTraceEnable(TRC_START);
                

uiTraceGetTraceBufferSize

uint32_t uiTraceGetTraceBufferSize(void)

Returns the size of the snapshot trace buffer, in bytes. See also xTraceGetTraceBuffer.

Example:


/* Save the snapshot trace buffer */
f = fopen("mytrace.bin","wb");
ptr = xTraceGetTraceBuffer();
size = uiTraceGetTraceBufferSize();
vTraceStop();
fwrite(ptr, size, 1, f);
fclose(f);
vTraceClear();
vTraceEnable(TRC_START);
                

vTraceSetStopHook

void vTraceSetStopHook(TRACE_STOP_HOOK stopHookFunction)

Sets a callback function to be called when the recorder is stopped. The data type TRACE_STOP_HOOK is defined as typedef void(TRACE_STOP_HOOK)(void).

Example:


void mySaveTraceFunction(void);
...
vTraceSetStopHook(mySaveTraceFunction);
                  

uiTraceStart

(DEPRECATED) Use vTraceEnable instead.

Starts the recorder. The recorder will not be started if an error has been indicated using prvTraceError, e.g. if any of the Nx constants in trcSnapshotConfig.h has a too small value (TRC_CFG_NTASK, TRC_CFG_NQUEUE, etc).

Returns 1 if the recorder was started successfully.
Returns 0 if the recorder start was prevented due to a previous internal error.
In that case, check xTraceGetLastError to get the error message.
Any error message is also presented when opening a trace file.

vTraceStart

(DEPRECATED) Use vTraceEnable instead.

Starts the recorder. The recorder will not be started if an error has been indicated using prvTraceError, e.g. if any of the Nx constants in trcSnapshotConfig.h has a too small value (TRC_CFG_NTASK, TRC_CFG_NQUEUE, etc).

vTraceClear

void vTraceClear(void)

Resets the recorder. This is not needed in the normal initialization, only if you want a clean restart of the tracing while the system is running.

xTraceRegisterUBChannel

traceUBChannel xTraceRegisterUBChannel(traceString channel, traceString formatStr)

The separate user event buffer (UB) allows for storing User Events separately from other events, e.g., RTOS events. Thereby you can get a much longer history of user events as they don't need to share the buffer space with more frequent events. User events in the UB are structured as UB channels, which contain a channel name and a default format string.

This function looks up an existing UB channel matching the parameters, or registers a new UB channel if no match is found.

The parameter channel is the name of the UB channel, that is to be shown in Tracealyzer. The parameter formatStr is a format string or a plain event name, that is to be used for all events stored on this channel using vTraceUBEvent and vTraceUBData. Both parameters are traceStrings, obtained using xTraceRegisterString.

Returns a channel handle for use in vTraceUBEvent and vTraceUBData.

Events and data arguments are written using vTraceUBEvent and vTraceUBData. They are designed to provide efficient logging of repeating events, using the same format string within each channel.

Examples:


traceString chn1 = xTraceRegisterString("Channel 1");
traceString fmt1 = xTraceRegisterString("Event!");
traceUBChannel UBCh1 = xTraceRegisterUBChannel(chn1, fmt1);

traceString chn2 = xTraceRegisterString("Channel 2");
traceString fmt2 = xTraceRegisterString("X: %d, Y: %d");
traceUBChannel UBCh2 = xTraceRegisterUBChannel(chn2, fmt2);

// Results in "[Channel 1] Event!"
vTraceUBEvent(UBCh1);

// Results in "[Channel 2] X: 23, Y: 19"
vTraceUBData(UBCh2, 23, 19);
                

Set TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER to 1 in trcSnapshotConfig.h to enable the UB mode and related functions.

Only a certain number of UB channels are allowed, by default 32, defined by TRC_CFG_UB_CHANNELS.

The buffer uses ring-buffer semantics, meaning that older events are overwritten if the buffer gets full. The buffer size is defined by TRC_CFG_SEPARATE_USER_EVENT_BUFFER_SIZE, by default 200 slots (x 4 byte each).

When using the UB, if using ring-buffer mode also for the main event buffer (quite typical), the earliest part of the trace often only contains User Event data (from the UB) and no RTOS events (since overwritten). Tracealyzer displays such intervals using a placeholder "task" labeled "Unknown Actor".

You may use vTracePrintF and vTracePrint also in UB mode, as they are then rerouted to the UB instead of the main event buffer. vTracePrintF then looks up the correct UB channel based on the provided channel name and format string, or creates a new UB channel if no match is found (combination of channel name and format string). To avoid running out of UB channels, the format string should therefore not contain "random" messages but mainly format specifiers. Random strings should be stored using %s and with the string as an argument.

vTraceUBData

void vTraceUBData(traceUBChannel channel, ...)

Writes a user event to the separate user event buffer (UB), with data arguments. The parameter channel is obtained from xTraceRegisterUBChannel and specifies the format string for this event.

In UB mode, user events are stored separately from other events, e.g., RTOS events. Thereby you can get a much longer history of user events as they don't need to share the buffer space with more frequent events.

Set TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER to 1 in trcSnapshotConfig.h to enable the UB mode and related functions.

Examples:


traceString chn2 = xTraceRegisterString("Channel 2");
traceString fmt2 = xTraceRegisterString("X: %d, Y: %d");
traceUBChannel UBCh2 = xTraceRegisterUBChannel(chn2, fmt2);

// Results in "[Channel 2] X: 23, Y: 19"
vTraceUBData(UBCh2, 23, 19);
                

vTraceUBEvent

void vTraceUBEvent(traceUBChannel channel)

Writes a user event to the separate user event buffer (UB), without data arguments. The parameter channel is obtained from xTraceRegisterUBChannel and specifies the format string for this event. Since this function is intended for basic events without data arguments, the "format string" set in the UB channel should not contain any format specifiers, but is simply a string.

In UB mode, user events are stored separately from other events, e.g., RTOS events. Thereby you can get a much longer history of user events as they don't need to share the buffer space with more frequent events.

Set TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER to 1 in trcSnapshotConfig.h to enable the UB mode and related functions.

Examples:


traceString chn1 = xTraceRegisterString("Channel 1");
traceString fmt1 = xTraceRegisterString("Event!");
traceUBChannel UBCh1 = xTraceRegisterUBChannel(chn1, fmt1);

// Results in "[Channel 1] Event!"
vTraceUBEvent(UBCh1);
                

Hardware Ports

The recorder library needs a hardware timer port in order to give accurate timestamps on recorded events. This is the only hardware dependency of the recorder library. Some hardware architectures are already supported in the recorder library, such as ARM Cortex M0, M3 and M4 (all chips using Cortex M cores), and other ports are in development. However, there are many chips that we do not yet have direct support for, with respect to hardware timestamping. In case your chip is not yet directly supported, the recorder library includes a hardware independent fall-back option providing low resolution time stamping equivalent to the FreeRTOS tick, typically 1 ms. However, it is strongly recommended to use to a hardware timer for any serious use of this tool. Fortunately, developing a hardware timer port yourself is quite easy.

Developing a hardware port is mainly a matter of setting of the timestamping. This relies on a set of macros (TRC_HWTC...) that you define according to your specific hardware in trcHardwarePort.h. The central macro is TRC_HWTC_COUNT, that is expected to provide the current value of a suitable hardware timer/counter. You typically use the same interrupt timer that drives the kernel tick. Please refer to the comments in trcHardwarePort.h for additional instructions.

To make a custom hardware port, you may also need to provide a definition for interrupt-safe critical sections within the recorder. This since the standard critical sections offered by FreeRTOS, like portENTER_CRITICAL/portEXIT_CRITICAL, might not safe to use from interrupt (kernel) context, and some recorder functions may be called from both contexts. It is therefore advised to disable interrupts completely in the recorder's critical sections, and store the previous state to avoid enabling interrupts when not suitable. If your FreeRTOS port implements portSET_INTERRUPT_MASK_FROM_ISR and portCLEAR_INTERRUPT_MASK_FROM_ISR, you can use the following definitions:


#define TRACE_ALLOC_CRITICAL_SECTION() int __irq_status;
#define TRACE_ENTER_CRITICAL_SECTION() {__irq_status = portSET_INTERRUPT_MASK_FROM_ISR();}
#define TRACE_EXIT_CRITICAL_SECTION() {portCLEAR_INTERRUPT_MASK_FROM_ISR(__irq_status);}
            

The definitions of TRACE_ENTER_CRITICAL_SECTION etc. are normally found in trcKernelPort.h, feel free to modify those if necessary.

User Event Logging

To log custom User events from your application code, use the function vTracePrintF() or vTracePrint() (less powerful but faster). To define User Event Channels for grouping your user events, use xTraceRegisterString().

Stack Usage

You can configure the Trace Recorder to report the unused stack space for each task in your application. This is done by setting TRC_CFG_ENABLE_STACK_MONITOR to 1 in trcConfig.h. You also need to ensure that the setting TRC_CFG_STACK_MONITOR_MAX_TASKS allows for including all tasks. If this is too small, some tasks will not be included in the stack monitoring.

By enabling the Stack Analysis, the Tracealyzer Control task (TzCtrl) will periodically generate "Unused stack" events, which are shown in the Stack Usage graph and also in the Trace View as Notices.

Notes:

  • Short-lived tasks might be missed by the stack analysis, i.e. if deleted shortly after creation.
  • The unused stack space is reported in words, i.e. just like the stack size parameter for xTaskCreate.
  • The "Unused stack" events does not show exactly where an increase in stack usage occurred, but only where the sample was made.

The stack usage is analyzed using the FreeRTOS function uxTaskGetStackHighWaterMark, that reports the unused stack space for a specified task. The runtime of this function can be quite long, around 100 us was noted on an Arm Cortex-M4, but it depends a lot on how much unused stack space there is, the processor speed and what compiler optimizations that are used. To avoid long runtimes, the TzCtrl task only analyzes one task stack per TzCtrl execution, but it cycles between the different tasks.

You can configure how many task stacks that should be analyzed by each execution of the TzCtrl using TRC_CFG_STACK_MONITOR_MAX_REPORTS in trcConfig.h. In this file you also find settings for the TzCtrl task, which is of relevance for the stack analysis. For instance, if you want more frequent samples you can reduce the delay time in TRC_CFG_CTRL_TASK_DELAY. Moreover, you can set the scheduling priority of the TzCtrl task using the TRC_CFG_CTRL_TASK_PRIORITY setting. Due to the potentially long runtimes, you should ensure that TzCtrl runs on lower priority than any time-critical tasks in your system.

Live Stream

This view displays information about the data collection itself, while recording a streamed trace. The diagram in the middle shows the CPU load of the target system, i.e., the percentage of processor time spent in application tasks (i.e. not idle) in relation to the total processing time.

The Live Stream view also shows if the trace data rate is higher than the streaming connection can handle, causing events to be lost. In such cases, it displays a counter showing the number of dropped events. If you encounter that, please refer to the Troubleshooting section corresponding to your RTOS.

Using the "Disable Live Visualization" checkbox, you can disable all live updating views in Tracealyzer, and the continuous loading of the trace. This way, you can record traces of unlimited length, and then use the Trace Preview to analyze them and load relevant sections.

The CPU load visualization is however not affected by this setting. This can remain active also when recording very long traces, as its memory usage is constant and independent of the recording length.

While streaming, use Sync -> Unsynchronized to pause the live updates for a view, making details in the view easier to find. To have the view update again, use Sync menu and pick the Details or Overview, marked with default one for the current view.

Trace Preview

The trace preview window shows a high level summary, from which you can select and load a smaller section of the trace of relevance. This is intended for very large traces that can't be loaded in full, due to the amount of RAM required.

The preview shows the CPU load of the target system over the entire trace, which gives a high-level overview of the system behavior. From this graph, you may select and load a smaller section by holding down the left mouse button in the graphs and dragging.

The table below the graphs shows statistics and extreme values for actor properties, such as execution times and response time, over the entire trace. You can locate the corresponding point of an extreme value by double-clicking on the corresponding table cell. This will highlight the point in the graphs and select a section centered on this point.

Memory Estimate

In the bottom of the preview window, you find the memory estimate indicator. Since loading a very long trace can easily eat up all available memory, you should make sure to not load too long sections. The memory estimate shows the estimated memory usage of loading the current selection, helping you avoid running out of RAM.

The gray part (on the left) shows the amount of memory used by your operating system and other applications.

The blue part (in the middle) shows how much memory Tracealyzer is currently using.

The right-most part is green if the current selection is estimated to fit in memory, yellow if the selection is estimated to be a close fit, or red if estimated to be too large to load.

Note
A yellow or red area does not necessarily mean that the trace can't be loaded. This is just an estimate, and if there is enough virtual memory available the trace will load anyway, but the performance of your computer is likely to be affected.

User Events

Introduction

You may log any event or data in your application code as User Events by adding calls to the recorder library.

As shown below, user events are displayed in in the Vertical Trace view (as yellow labels in the left view), in the Event Log (lower right view) and if you include data arguments in your user events, you can plot this data using the User Event Signal Plot.

If you log any kind of state transitions in your system as user events, you can define a State Machine based on these events.

User events inserted at strategic locations can be used for detailed profiling of your system, i.e., to measure the time between these events. This by defining a Custom Interval based on the user events.

The details of logging user events depends on the recorder library used, which depends on which RTOS you are using. Learn more under Creating and Loading Traces, in the subsection about your specific RTOS.

Intervals and State Machines

Introduction

Tracealyzer allows for defining custom data sets, based on events in the trace, which can be visualized and analyzed in several ways. This allows you to analyse system-specific properties, i.e. the things that really matters for your system.

There are two kinds of custom data sets: Intervals and State Machines.

An Interval is used to measure or highlight the time between two specific events. By adding an Interval definition, you create a data set containing all intervals (pairs of events) matching the definition.

Example: Assuming a trace containing the user events "On" and "Off", you can define an interval starting at "On" and ending at "Off", and thereby see all "On" -> "Off" sequences, independent of other events in between.

A State Machine is used to visualize any kind of state information logged in the trace. When defining a state machine, you specify the events corresponding to related state changes, and how to extract the state information from those events. This results in a group of interval data sets, one for each observed state, representing the state machine.

Example: Assuming a trace containing the user events "On" and "Off", you can define a state machine "MyFSM" based on these events. Each occurrence of "On" or "Off" is then interpreted as the new state of "MyFSM".

Tracealyzer also provides a predefined list of intervals and states for objects that Tracealyzer is aware of. This way you can include, e.g., task scheduling states, and even TCP socket states (assuming you are using a TCP stack supported by Tracealyzer).

Intervals and states can be visualized and analyzed in several ways, as shown in the below example. In this example, the intervals are generated by defining a state machine based on user events, but all kinds of intervals can be shown in this way.

Intervals and states can be displayed in several Tracealyzer views, and you can also generate statistics.

  • Trace View
    Intervals/states are shown in the trace view as a separate "Interval" field, in parallel with the RTOS trace. This effectively provides a software logic analyzer.
  • Interval Timeline
    Intervals/states can also be displayed in a separate timeline using Interval Timeline view, as shown in the upper right view above.
  • Interval Plot
    The duration of intervals can be plotted over time, as shown in the lower right view above. The X axis indicates the start time of the interval, and the Y axis shows the duration. This way, you can study the time between two events and how it changes over time.
  • State Machine Graphs
    A state machine can be viewed as a directed graph, showing all observed states and state transitions. Just open the State Machine Graph.
  • Statistics
    You may generate a statistics report for intervals, including state intervals, where you can see the shortest, longest and average duration over the whole trace. Do this by opening the Intervals and State Machines window and then right-click on the interval definition in the list.
Note: You may use the Filter view to select which intervals to display.

Intervals and state machines are added by using Views -> Intervals and State Machines, shown in the below screenshot. Here you see all your custom data sets and you also have three buttons for adding new definitions. Learn more about this dialog on the Intervals and State Machines tool page.

Views

Actor Instance Graphs

The Actor Instance Graph views display timing properties of actor instances, like execution time, response time, response interference and fragmentation. Use the combo box at the right to select which property to see.

Each data point in the graph represents a specific actor instance, where the x-axis shows the timing information and the y-axis the property value.

This example shows execution time per actor.
Clicking a plotted instance will show and highlight it in the trace view. You can filter actors by clicking on an actor in the legend to the right.

Actor Migrations

The Actor Migrations graph shows the amount of context switches over time. For each time interval, a bar is drawn for each actor beginning or resuming execution at least once in that interval.

The height of each bar, or bar section, shows the number of migrations within the given interval.

Actor Statistics Report

The Statistics Report provides performance statistics for tasks and traced ISRs. This includes minimum, average and maximum values for properties like task executions times and response times. Moreover, most metrics are linked to the main trace view, allowing you to quickly find the corresponding trace locations. The report can be generated for a selected interval, or for the whole trace.

You generate the Statistics Report using the option in the View menu. This option is also available when right-clicking on a selected interval in other views. A configuration dialog is then shown where you can select which tasks, ISRs and properties for these you wish to include.

The available properties include high level statistics per task and ISR, like CPU usage, but also provides more details statistics for individual Actor Instances. As explained in Terminology section, an "Actor Instance" means one iteration of a task loop, or an ISR execution from entry to exit.

The interval in focus of the report is shown in the bottom ("Interval: "), either the selected interval from the main trace view, or the full trace if no selection exists.

Available properties are:

  • Count: The number of Instances of the Actor in the trace or selected interval.
  • CPU Usage: The relative amount of processor time used by the Actor (in percent).
  • Execution Time: The time in microseconds for executing one Actor Instance, excluding any time spent in preempting tasks and traced ISRs. If there are Actors not included in the trace (ISRs without trace calls, or excluded tasks), the reported Execution Time may include the time spent in such Actors.
  • Response Time: The time from the start of an Actor Instance until it is finished. If "Actor Ready" events are included in the trace, those are counted as the starting point of the Instance.
  • Periodicity: The time between two adjacent Instances of the same Actor, measured from start to start. If "Actor Ready" events are included in the trace, they are counted as the Instance start.
  • Separation: The time between two adjacent Instances of the same Actor, measured from end to start. If "Actor Ready" events are included in the trace, they are counted as the Instance start. A separation of 0 means that the Instances follow in direct sequence.
  • Fragmentation: The number of scheduling fragments within the Instance (i.e., the trace view rectangles). This value indicates the number of interruptions, e.g., ISRs, preemptions by higher priority tasks, blocking on mutexes etc.

Click the Show Report button to generate and view the report. The report has three sections, an introduction, a table with descriptive statistics (min, average, max values). The distribution histograms are only included if the checkbox Show Graphical Diagrams is enabled

All properties related to time are by default expressed in microseconds, but this is affected by the "Time Format" setting found under the View menu. The report can also be generated in text format, that is easy to import in other tools. Use the "Data Export" option to output the data in text format. To save the report, select "Save As" in the File menu of the Statistics Report Viewer.

All min and max values are linked to the Finder dialog, as well as the histogram bars. When clicked, the Finder dialog is opened with the filter set to find matching Instances. The first match is then shown directly in the main trace view.

Asynchronous Stack Trace

This view shows stack trace information from asynchronous data. It will show the current stack trace state at any given time.

Default behavior is to reload the stack trace when selection or view area is updated. This can be changed in the View menu.

Communication Flow

The Communication Flow graph offers a quick overview of the communication and synchronization between actors in a trace, through message queues, semaphores and mutexes.

This graph can be generated over a whole trace, or for a specific interval only. For example, you might use the CPU Load Graph view to identify a peak where there is a lot of activity, then select that peak using a mouse drag selection, right click and select "Show Communication Flow" in the context menu to show the communication flow graph of that specific interval.

Actors are shown as rectangles, and other objects are shown as ellipses or hexagons. Ellipses are used for directional communication and synchronization objects, while hexagons are used for bi-directional objects like Mutexes and similar.

Double-clicking on any node opens a related view that displays all matching events, such as the Object History view.

There are two modes in this view:

  • Actors and Objects: Shows all objects and dependencies, both actor communication and dependencies on synchronization objects, like Mutexes.
  • Actors Only: In this mode, only those actors are shown which have communication dependencies to other tasks. Dependencies on bi-directional objects (e.g. Mutexes) are not shown.

The classification of objects into directional objects (ellipses) and bi-directional objects (hexagons) are based partially on the static type of the object, partially on the service calls found referencing the object. This since semaphores can be used for both purposes, as a directional signal (a form of communication), and as a synchronization lock, i.e., like a Mutex. A object is treated as a synchronization object (hexagon) if there are actors that both increment and decrement the object state (e.g., do both a "LockMutex" and "ReleaseMutex"). This means that a semaphore can show up as a hexagon (if one actor both signals and waits for it) while a mutex in rare cases might show up as an ellipse, if only one type of operation ("LockMutex" or "ReleaseMutex") is recorded on the particular object.

Applying filters

Sometimes it's useful to filter out specific tasks or objects, such as if you have a debug or log writer task that many other tasks send data to. By default, all actors and objects that do not perform any communication are hidden, but you can adjust these settings using View -> Select Objects.... You can also right-click a node to hide it.

When right-clicking a node, you'll also be presented with options to show only connected nodes, in one, two or unlimited steps. This shows only actors and objects that affect or are affected by the selected actor or object via directed communication (undirected communication such as through mutexes are not followed even though the objects will be displayed).

The Show All Connected and the Show All Connected Only options will show the same nodes (actors/objects) but might show different sets of edges (lines). The difference is that the former does not hide communication between those nodes even if it's unrelated to the selected node. For example, if you have the communication chains taskA -> queueB -> taskB -> outputQueue and taskA -> outputQueue and you show nodes connected to taskB, Show All Connected Only (2 steps) would show only the first chain while Show All Connected (2 steps) would also show the second chain.

Context Switch Intensity

The Context Switch Intensity graph shows the amount of context switches over time. For each time interval, a bar is drawn for each actor beginning or resuming execution at least once in that interval.

The height of each bar, or bar section, shows the number of context switches within the given interval.

CPU Load Graph

The CPU Load Graph displays CPU usage over time, per actor and in total. By default, it shows all actors except the idle task. The analysis works by dividing the trace into a number of intervals, the default is 100 intervals.

The CPU usage for an actor in an interval is the amount of CPU time used by the actor within this interval, divided by the length of the interval. For each interval, all actors executing in that interval will be drawn as rectangles stacked on top of each other. The height of each actor's rectangle represents the CPU usage for that actor in that time interval and the combined height is the total CPU usage for that interval.

To customize the view, use the Select Actor(s) menu. There you can select which actors you wish to include in the view. If the graph is "noisy" (due to short intervals), you can reduce the number of intervals through the Resolution menu. If you wish a more detailed graph, you can increase the number of intervals by selecting a higher resolution. If you wish to focus on a specific area, you can click and drag to select an interval and use the Zoom menu or right click to zoom in on it. You can also use the Zoom or right click menu to show the selection or current view in the trace view or in all open views.

Clicking an actor in the graph will display information about that actor in the clicked interval and double clicking an actor will center the trace view on that interval. A gray outlined rectangle shows the interval of the current trace view. This rectangle may be very narrow and appear as a line if the trace view is small.

Event Intensity

The Event Intensity graph displays the number of events per event type, during the selected interval.

By default, the interval is divided into 50 time slices. The number of slices can be changed via the Resolution or Time Resolution menus.

Event Log

The Event Log displays the trace as a textual event listing, with powerful filtering tools. The view also supports exporting the trace as text file.

Clicking on any entry will highlight the corresponding event in the Vertical Trace View.

Filters

The text box above the event log functions as a quick text-based filter. Type any text and click Apply, and only entries containing that text will be displayed. To revert to displaying all entries, delete the search string and click Apply again.

The next four buttons - User Events, Service, Info Events and Raw Events - toggles the visibility of their respective class of events.

Clicking the Advanced button opens a panel with even more filtering options:

By Content
In the upper part of the panel you have the line content filters. You can choose to include only entries matching one or more regex patterns and/or excluding any entry matching one or more regex patterns. Both text boxes supports multiple patterns by placing one pattern on each line.

By Timestamp
By using the Exclude Events Before/After Timestamp filters, you can display events within a specific interval only.

By Event Type
In the bottom of the panel you have the Sources tree view. Here you can select which types of events you want to include as well as which individual channels you want to include for user events.

Find

Using the Find menu item, you can quickly locate a particular event.

  • Find: Opens the Find dialog. This lets you find an event or log message by string contents.
  • Find Next: If a search pattern has been entered in the Find dialog, the next match will be shown. Otherwise the Find dialog will open.
  • Goto Timestamp: Opens the Goto Timestamp dialog. This lets you find an event by timestamp.

Formatting

Using the Formatting menu item, you can configure the view.

  • Show Timestamps: Toggles the display of event timestamps.
  • Color Events By Type: Toggles the coloring of line backgrounds based on event type.

Export

Using the Events -> Export menu item, you can export the trace as a text file. This can be used to compare traces (using a plain diff/merge tool), e.g., for debugging (compare the event order in two traces with different behavior) and for regression testing (Does v1.2 behave the same as v1.1? If not, what differs?). All formatting and filtering used in the Event Log view is applied also in the Export function. This can be very powerful when comparing traces, as you can exclude irrelevant events and also the timestamps, e.g., if you wish to compare traces with small differences in timing.

I/O Intensity

The I/O Intensity view shows the amount of data sent or received on a particular I/O Channel object, per time interval. An I/O Channel is a traced object correponding to a system-level input or output. For instance, if using the Keil TCP stack, all the TCP sockets are recognized as I/O channels.

A histogram is displayed over the timeline (X axis), with a fixed number of bars each representing a fraction of the current view port. The height (Y axis) of the bars shows the total number of bytes sent or received in each time interval. Double-clicking on any of the bars in the I/O Intensity view will show the correponding time interval in the Trace View (and also in other views associated to the "Detailed" view port).

The display depends on two filters, as well as a Resolution setting. The "Send/Receive" filter in found the window menu, and in the right-side panel you can select which I/O Channel objects to include.

The resolution (i.e. number of bars) can be set in the menu. For instance, if selecting Resolution "High (100)", and the zoom level is 1 second, it will be divided into 100 intervals of 10 ms each.

I/O Plot

The I/O Plot displays the amount of data sent or received in "I/O Channel" events. An I/O Channel is a traced object correponding to a system-level input or output. For instance, if using the Keil TCP stack, all the TCP sockets are recognized as I/O channels.

Each data point represents an I/O Channel Event, where the X axis shows the time of the event and the Y axis shows the amount of data sent or received, in bytes. Double-clicking on the data points shows the correponding event in the trace view.

The display depends on two filters, the "Send/Receive/Combined" filter setting in found the window menu, and in the right-side panel you can select which I/O Channel objects to include. In using the "Combined" option, both Send and Receive events are plotted. Send events are then shown as positive values on the Y-axis and Receive events as negative values on the Y-axis.

Interval Coverage Graph

The Interval Coverage Graph displays the percentage of time covered by intervals in each channel in a set. Depending on the nature of the channels in the set, the value may be higher than 100%.

  • For a state machine, this view will show the amount of time spent in each state. In this case, the total should always be 100%.
  • If used with the Actor Fragments/(All) interval set, this will display CPU load across all cores. In this case, the total will add up to (number of cores) * 100%.
  • If used with the Actor Instances/(All) interval set, this will show some form of demand for processing time.

By default, the interval is divided into 50 time slices. The number of slices can be changed via the Resolution or Time Resolution menus.

Memory Heap Utilization

This view visualizes the heaps in the current trace.

You can show or hide individual heaps by clicking on them in the legend field to the right. If you click on a marker in the graph you can see information about that event in the information panel. Double-clicking will focus the main view on that event.

Message Receive Time

This plot shows the message receive time, i.e., the time from a queue is put in a message queue, until it is received. This way, you can see if messages to a task are delayed.

Object History

The Object History view displays all service calls for a specific object, or memory allocations (malloc/free) on a Heap object. This view is easiets to open by double-clicking on an event label, e.g., in the Vertical Trace View.

The Object History is displayed as a list, where each line corresponds to an event - the actor making the call, the type of event and the status of the object.

For queue objects, the current length of the queue is shown in the right column, with sequence numbers on the individual messages (the rectangles). The color of a message indicates the actor that sent the message. If selecting a successful send or receive event, it is possible to follow the message to the receiver or sender by using the buttons in the tool panel on the right, "Goto sending event" and "Goto receiving event". This allows you to follow the messages sent between individual task instances, e.g. to find the location where a queue message with incorrect data was sent.

The event list can be filtered to only display events of a certain service or from a certain task, using the two Filter menus. Clicking an event will display details about it in the panel to the right, which also features navigation buttons. Double-clicking an event will highlight it in the trace view.

When viewing heap events, such as "malloc" and "free", it is also possible to filter out all the allocations that have been freed, leaving only the remaining allocation. This can be used to find any memory leaks. See also Memory Heap Utilization.

Object Utilization

This view visualizes the state of objects over time, such as the number of messages in a message queue. It can be used to identify situations where the system has trouble processing all input within a reasonable time.

You can filter what actors to visualize by clicking on them in the legend field. If you click on a marker in the graph you can see information about that event in the information panel. Double-clicking will focus the main view on that event.

Priority Changes

In case a task changes scheduling priority, it is displayed in this horizontal view. The Y-axis shows the new priority level.

Service Call Block Time

The Service Call Block Time graph displays the kernel blocking times of service calls, i.e., the time between entry and return of blocking calls.

Each data point represents a specific service call, where the x-position indicates the point in time and the y-position the blocking time. Clicking a data point (a service call) will highlight it in the trace view. This can be used to identify unintentional blocking, e.g. on a Mutex, which could be a cause to unusually high response times of tasks.

Note
If accessed from the View menu of the main window, this view will plot all calls on any object. You can bring up the view for a single object by right-clicking on a service call in the trace view and selecting Blocking Time Graph from the [Object Name] submenu.

Service Call Intensity

The Service Call Intensity graphs displays the number of Service Calls over time. This allows you to find hot spots with many service calls.

The individual services are color coded using a separate color scheme, shown in the right-side legend. You can toggle the visibility of services in this view by clicking on the labels in the legend.

Stack Usage

The Stack Usage view shows how much stack is used or unused for each task, which allows for optimizing the memory usage. Note that this feature is only available for some target platforms. Check for a "Stack Usage" section in the platform-specific documentation under Creating and Loading Traces/[YourTargetPlatform] to learn more. In case this is not available, the Stack Usage analysis is not yet supported for your target platform.

State Machine Graph

This view displays a directed graph showing the state transitions in the trace as defined by a state machine. In the screenshot below, the state transitions have been logged in the user event channel "SystemState". See Intervals and State Machines introduction for further information on state machines and the related concept of intervals.

Any kind of state information can be displayed like this, assuming a state machine has been defined that tells Tracealyzer how to interpret the events into state transitions. See Intervals and State Machines view for further information on how to define state machines. Defining a state machine also generated intervals between state transisions that can be displayed in timeline views.

Tracealyzer also has pre-defined awareness of some states, such as task scheduling state. In the Intervals and State Machines view, select Add Predefined to see the available data sets. For instance, if using TCP stack supported by Tracealyzer, you can add each TCP socket as a state machine and also display the socket states as intervals on the timeline.

Trace View

This is the main view of Percepio Tracealyzer, showing all recorded events on a vertical timeline going downwards, or a horizontal timeline going right.

First some terminology. By actor we mean an execution context - a task or ISR. The colored rectangles (fragments) in the "CPU0" field represent uninterrupted execution of an actor, starting and ending with a context-switch.

Each actor has a unique color, based on its scheduling priority. The same color is used to represent the actor in all Tracealyzer views. The default color scheme is the natural light spectrum, going from red (high priority) to blue (low priority), and finally light gray for the idle task. The exact colors used depends on the number of actors in the trace and their relative priorities. The color scheme can be changed and you can even set your own custom colors, see View -> Trace View Settings -> Set Color Scheme.

Event Type Priority

When using a zoom setting that will not show all events, the Trace View (Events field) will try to hid events depending on the Event Type priority. By default this option is turned off, making sure events are not hidden without the operator knowing about it.
See Events for information on the sections.

To enable this and to change the priority, go to Event Priority Settings and re-order the types.

Fields

Each section in the Trace View is called a Field. The different Fields are separated by thick lines. The field names are shown in the header, i.e. in the top part of the trace view, when using the vertical orientation. Fields can be configured or hidden by right-clicking the header, or by clicking on the "gear" icon ().

There are three main field types, showing different kinds of information:

  • Scheduling field: Labeled "CPU0" for single-core systems. Shows the execution of actors, as solid rectangles (i.e. fragments). On multi-core systems you will also have "CPU1", "CPU2", etc.
  • Intervals field: Displays intervals and states. Such fields are named after the displayed data set.
  • Metrics field: Shows metrics embedded next to all other trace fields.
  • Events field: Shows event labels for e.g. kernel API calls and user events. This is always named "Events Field". The field will show all events from fields to its left, making it easy to see different events at the same time.

Moreover, there is always an "Actor Names" field available, although not always visible. To see it, click View -> Show Actor Names. There you also find an option to toggle the display of all Event fields, View -> Show Events.

To add a new Field, click View -> Add Field and select one from the list.
It is also possible to configure and rearrange the fields, using View -> Setup Fields.
All fields have configuration available which can be accessed using the gear icon in its header (at the top or to the left) of the field, or by right-clicking on header.

Note that Events field only displays events originating from fields on its left side. So, if adding additional fields, or rearranging the fields, note that the make sure that each Scheduling field has an Events field on its right side. Multiple Scheduling fields may however share a common Events field.

Horizontal Mode

You may change the orientation of the trace view between vertial and horizontal in the local View menu of the trace window. Both modes offer the same features, but we recommend vertical orientation to make it easier to read text labels.

In horizontal mode, you may close the Event field and instead add Interval fields to display application states and kernel objects, such as message queues. An example is shown in the above screenshot. To do this, select View -> Add Field -> Interval field and then click the "Add Interval..." button. You then get a list of all available data sets, including predefined data sets for e.g. message queues.

Trace View Options

For multi core systems actors can, depending on scheduling rules, run on different cores (even within the same instance). In traces where this happens, it is not always clear how to show that an actor is running on a core that is not in the current field.
The option View -> Show Actor Fragments on other Cores can select if actor fragments running on cores not included by current filter are drawn with gray lines, or not drawn at all.
The image on the left shows with this option enabled, the one on the right with it disabled.

Scheduling Field Options

This field can be customized to only show a subset of the available actors by using Select Actors or CPUs (for multi core traces) by Select CPUs
Note! Applying actor selection will work together with current filter; if an actor is not in the current filter it will not be shown in the Scheduling Field either.

Normal sort order for the field is highest priority to the right for vertical mode, or bottom for horizontal mode. This can be changed by checking Reverse Draw Order.

For traces with many actors it is possible to activate Hide Inactive Actors. This will only show "lanes" for actors that have an active instance in view, otherwise they will be hidden.
Each hidden actor will be "shrunk" to a slim line, making it easy to get an indication on if there are many or few actors hidden.
Note! Each field will remember the setting for hiding, as long as Percepio Tracealyzer is set to remember layout. If the default value is to be changed, use Settings -> Project Settings.

Metrics Field Options

This field shows metrics, like CPU load, or Actor Execution time. When the field is created a Select Metrics dialog will be shown to show the available metrics. The same dialog can be opened by clicking Select Metrics. Some metrics has different channels available, and when this is available it will be possible to switch the channel directly from the menu without having to open the dialog.

Event Field Options

This field can be set to show Event Hotspots, which will indicate where the events are located when zooming out as gray squares at the edge of the Event Field. This will help identifying if there are certain times when more events than usual is happening.

Intervals Field Options

The interval field can be changed to show a different interval than it was originally created with, see Interval for more information.

View Presets

The execution of tasks and interrupts can be visualized using different visualization presets, which you can quickly switch between to get best clarity in each situation.
Each preset will set up the fields needed to show the type of information required.
The presets are:
Gantt Preset Shows one column per task and interrupt. This is best for spotting execution patterns, rare tasks or interrupts.
(Default shortcut key "G")
Merged Preset Shows all tasks and interrupts in a single column, with sideways indents to show preemption and blocking. This gives a more compact display compared to Gantt View Mode and the best sense of execution order and preemption hot-spots. This preset uses calculated data it is not available for live tracing.
(Default shortcut key "M")
Split Preset Shows tasks and interrupts in two columns, with indents like in the Merged View Mode. This removes the "noise" from interrupts by presenting them separately. This preset uses calculated data it is not available for live tracing.
(Default shortcut key "S")
Flat Preset Shows all tasks and interrupts in one single column (per core).
(Default shortcut key "F")
Intervals Preset Only show intervals, see Intervals for more information. This preset is only available when there are intervals active.

It is also possible to set up custom presets. Under the View -> View Presets, either select Save Preset or Manage Presets.

Events

The main view also show event labels of different types, notices, service calls and user events, if enabled in the visibility filter in the lower right. The events are shown as color coded labels to the right of the fragment in which they occur.

Events labels are shown in different colors depending on type:

  • Red labels - blocking service calls.
  • Green labels - successful return of blocking service calls.
  • White labels - service calls that completed without blocking.
  • Orange labels - service calls that returned due to a timeout.
  • Yellow labels - user events.
  • Light blue labels - notices, such as "Actor Ready" - when tasks become ready to execute.
  • Blue-green labels - asynchronous events, any events from asynchronous data sources.

Note that delay calls are shown in white, not red, even though they block the executing task. This since delays are unconditional blocking, and the sole purpose of these service calls. The red, green and orange labels are used only for blocking on shared resources, e.g., message queues, semaphores and mutexes, where the blocking may not be intentional and thus of greater interest to study.

Clicking on a task or ISR fragment selects the corresponding actor instance and highlights it. You can follow the execution of the selected actor using the "Previous" and "Next" buttons in Selection Details Clicking an event label selects and highlights both the actor instance and the event. When an actor instance is selected, the Actor Information display is updated, as illustrated above. This is a tree structure containing a lot of information, both general statistics of the actor and information about the specific instance. Most tree nodes that refer to a particular point in the trace are links to that location. By double-clicking them you navigate the trace view to that position. The linked tree nodes include all "Lowest" and "Highest", Triggered By", "Triggers" as well as the list of events in the end.

Double-clicking on an actor opens the Instance Details view, which gives lots of information focused around that actor. Double-clicking on a system call opens a focused view showing a list of all related events, e.g., the Object History View. This shows all service calls on a selected object, i.e., a message queue, semaphore or mutex. Double-clicking on a user event shows the Event Log, with filters applied.

When selecting a blocking call (red label) or a resume from blocking (green label), the matching event (call or return) event is also highlighted. You may jump to that event by using the button in Selection Details pressing F8, or by using the context menu option "Find Entry/Exit of Blocking Service Call".

Note
When there are too many events in the current view to fit on the screen, they'll be hidden and replaced by the text X events not shown. If this happens, zoom in or use the visibility filter to reduce the number of events. If the number of events for a selected actor is not too many, they will be shown even if the rest of the events are hidden.

Note
If a large number of events are hidden, it is possible to see where they are located with the event hotspots; gray rectangles showing where the events are located, see Event Field.

Zoom and navigation features

To navigate the trace, you can use the mouse wheel or the scroll bar (in the right). You can also drag the view by holding down the mouse wheel or middle mouse button. The arrow buttons and page up/down buttons can also be used when the trace view area has focus.

You can select an interval by holding in the left mouse button. By right-clicking on the selection, you open a context menu with various options for the selection interval, such as Zoom In.

To measure the time between two events, select one of the events and then hold the SHIFT key while selecting another event.
The first event will still be selected, making it possible to measure to different events and see the result.

Note
When searching for a particular location, it is often easier to use the Finder or one of the graphical overviews to find it. When using another view to navigate the trace, you can click or double click to focus the trace view on this location. All graphical views also support selecting a time interval (by pressing the left mouse button and dragging) and showing this interval in the trace view.

To zoom in or out, use the zoom buttons on the tool panel, the numpad + and - buttons or the zoom options in the right-click menu.

You can also zoom with your mouse wheel when holding down the Ctrl key. The scroll-to-zoom behavior is always active when Scroll Lock is enabled. If your mouse features back and forward buttons, you can use these to quickly zoom in and out.

User Events Signal Plot

This view allows for plotting data from user events arguments. If a user event have multiple data arguments, only the first is plotted. Each user event channel is plotted as a separate curve. You can change what user event channels that are displayed in the Filter.

For more information about user events, see User Events section.

View Port Overview

This tool shows the view ports that are used by any view. Multiple views can share the same view port, see User Interface section for more details.

Both the view ports and the view selection is visible.

Tools

Actor Overview

The Actor Overview displays a list of instances of an actor.

All Views

The All Views window shows an overview of all views and features in Tracealyzer. Type something in the quick filter box to only show views that match your search term.

Select "Show View" or double-click the thumbnail picture to launch the selected view. Click "Read More" to open the User Manual page about this view.

API Connection Monitor

The API Connection Monitor shows the current status of connections to the Tracealyzer API, which allow other tools to communicate with Tracealyzer.
This is for instance used by the "Percepio Trace Exporter" plugin for Eclipse (found in the Eclipse marketplace) and for Atmel Studio 7 (found in the Microchip Gallery).

When the monitor is running, a status icon will be shown at the bottom right corner of the main Percepio Tracealyzer window. The color is green if connected, yellow if trying to connect, and red if there are problems with the connection.

If using our Eclipse or Atmel Studio plugin, it is possible to request a snapshot from the target directly, provided it is possible to do inside Eclipse or Atmel Studio.

The Tracealyzer API also allows for tool partners to integrate with Tracealyzer. Details can be provided on request.

Application Warnings

This view shows any warnings from the Tracealyzer application during the current session. This shows if the recorder library has reported a configuration problem, or other issues that may occur.

Bookmark Organizer

Bookmarks are saved locations in a trace that are of particular interest.

Bookmarks are saved with the trace and restored when you reload the trace. Because they are saved in an internal directory it is recommended to use the bookmark organizer to export and import the bookmarks.

Export Actor Data

The Actor data exporter will Export all information from the selected actors to a text file. This allows you to either view the data offline or import it to a different tool.

Filter

Filtering in Percepio Tracealyzer is done in the Filter view, which shows application objects organized in different groups. Each group lists all objects of that type that can be filtered on.

Filterable objects are sometimes also organized in a hierarchy, giving you the option to easily enable or disable a whole group of objects.

Since filtering is potentially set per view, the filter dialog will show the attached view that the filter affects. All views belonging to the same synch group will be affected when changing the filter.

If the filter view is wide enough, the group selection will be shown as a list instead of a combo box.

Filters will by default be saved between Tracealyzer sessions. This can be disabled in the window menu by toggling View > Auto Load Filter.
It is also possible to save or load explicit filters using View > Save Filter from Current View/Load Filter to Current View.

Finder

The Finder window lets you quickly find actor instances, service calls and user events, using various filters. It also lets you jump to a particular point in time.

Two Finder Tools

Tracealyzer includes two "Finder" tools, the "Quick Finder" and the more advanced "Finder". They allow for searching for just about anything in Tracealyzer, including events, actors, views, and even help pages. Events are matched with respect to their displayed text, including user event channel names etc.

When combining multiple terms in a search query, the result will include hits on any search term, but the best matching entries will be shown first.

Quick Finder

The Quick Finder is a small search bar which will open inside the current view. It performs fast searches but only shows a limited amount of hits. Use the arrow keys and Enter, or the mouse, to select something from the list of hits, or refine the search keywords. When something is selected the default behavior is to close the Quick Finder. Cancel the search with the close button, or by pressing Escape.

The best way to open the Quick Finder is via the keyboard shortcut (default is Ctrl + F), but the Find menu can also be used. There is a special case of the Quick Finder that only finds timestamps in the current trace, with the default keyboard shortcut of Ctrl + G. These keyboard shortcuts can be changed using the Keyboard Mapping settings.

To keep the Quick Finder open when something is selected, click the small Pin button on its top right corner. The small D (for Detach) button on top will open the same search in the full Finder.

Full Finder

The full Finder view can be opened from the Find menu, or using the key shortcut Ctrl + Shift + F (default mapping). The main difference compared to the Quick Finder is that it will keep finding all items until done, or until you stop it. This makes it useful for larger searches, i.e. that may result in many matching events.

Advanced Find using Tracealyzer Query Language (TQL)

With the Tracealyzer Query Language (TQL) it is possible to quickly apply advanced filters on the items to find. Two parts will affect the outcome, any prefix keywords and the where clause.

If the first word in the search string matches a keyword, like actor or time, items from the corresponding group will be ranked higher in the find result.

To apply advanced filters, start by adding a where clause at the end. The where clause will not actually apply until it is complete, so while typing the find result may even become empty. You may add several filters if you wish to restrict the search further, using and or or.

If both keywords and where is applied, only results matching the keywords will appear.

Examples are shown later in this section.

Actor Instances

Finding actor instances can be prioritized by adding actor or instance as a keyword.

If an actor is selected in the result, press the TAB key to see min/max values for the current actor, like execution time and fragmentation. This will help when setting an advanced filter.

Supported keywords for where clause:

  • start - the start time of the instance
  • ready - the ready time of the instance
  • end - the end time of the instance
  • timestamp - same as start
  • instance - the instance number, starting from 1
  • index - same as instance
  • execution - the execution time of the instance
  • response - the response time of the instance
  • wait - the wait time of the instance
  • fragments - the number of fragments of an instance
  • period - the period of the instance (time from start of previous instance to start of this instance)
    Not available for live traces
  • separation - the separation of the instance (time from end of previous instance to start of this instance)
    Not available for live traces
You don't need to use the full name of keywords after where, as Tracealyzer then guesses which one you mean. For instance, entering "... where exec > 1000" works will be interpreted as "... where execution > 1000".

Keywords can be compared with decimal values, and most can also be compared to min and max.

Example where clauses for actor instances:

  • where exec is max
  • where frag > 2 and wait < 10000

Events

Finding events can be prioritized by adding event as a keyword.

The whole event text is used for matching, including displayed parameter values. Events will not be included in the search until terms with at least three characters are included.

Supported keywords for where clause:

  • time - the time of the event, in current time mode

Example where clauses for events:

  • where time < 100000
  • where time between 200000 and 300000

Timestamps and Intervals

Finding timestamps or intervals can be prioritized by adding time as a keyword.

If one time is entered, it will be used as a timestamp. If two times are entered, it will be used as an interval. Any more times after this will be used as timestamps.

Timestamps and intervals will ignore where clauses.

Opening Views

Finding views to open can be prioritized by adding view or open as a keyword.

The view will be matched by the name, but also additional keywords that describes what the view shows. Results will not only allow new views to be opened, but also currently active views that match the search terms.

Opening views will ignore where clauses.

User Manual

Finding views to open can be prioritized by adding help as a keyword.

All pages from the User Manual can be found from the Finder.
It will however not search through the whole text of the page, but do a quick match on keywords, similar to how views are matched.
To perform free text searches in the whole User Manual, simply open it (default shortcut is F1) and use the built in find.

User Manual will ignore where clauses.

User manual searches is only included if the built in User Manual is available.

Keywords

In addition to the contents of the current trace, all views, and user manual, there are a few useful keywords to perform certain actions:

  • start - scroll to the start of the trace
  • top - same as start
  • left - same as start
  • end - scroll to the end of the trace
  • bottom - same as end
  • right - same as end
  • all - zoom out to show the whole trace
  • full - same as all
  • zoom in - same as using the zoom in button
  • zoom out - same as using the zoom in button
  • zoom - same as zoom in

Keywords will ignore where clauses.

Examples

  • time 200000
    Centers the current View Port on timestamp 200000.
  • actor MyTask where exec is max
    Instances of actor "MyTask" with highest observed execution time.
  • actor MyTask where resp > 2000
    Instances of actor "MyTask" with response times above 2000 time units (normally µs).
  • actor MyTask where frag > 2 and wait < 10000
    Instances of actor "MyTask" with more than 2 fragments and wait time below 10000.
  • event MyEvent where time < 1000000
    Events containing the word "MyEvent" occuring before timestamp 1000000
  • event MyEvent where time between 100000 and 200000
    Events containing the word "MyEvent" occurring after timestamp 100000 and before timestamp 200000.
  • end
    Scrolls to the end of the trace.
  • all
    Zooms out to show the whole trace.

Instance Details

Whenever an instance is double-clicked, its details will be shown.

The details includes the currently selected instance. Besides the details, these views are also available:

  • Actor Instances shows all available instances of the selected task. The current selection is highlighted with light blue background, and if different the selection of the main window as well with a teal background.
  • Local Trace shows the current trace view with the selected instance focused, see Trace View for more information.
  • Communication Flow shows any communication that this particular instance performs, see Communication Flow for more information.

Interval Details

Whenever an interval or state machine is double-clicked, its details will be shown.

The details includes the currently selected interval. Besides the details, these views are also available:

  • Local Trace shows the current trace view with the selected instance focused, see Trace View for more information.
  • Interval Instances shows all available instances of the interval. The current selection is highlighted with light blue background, and if different the selection of the main window as well with a teal background.
  • State Machine will show a state machine graph of the current machine, only available of the interval describes a state machine.
  • Transitions will show all transitions, if the interval describes a state machine. It can also be set to filter for specific From or To states, either with Or logic (match either) or And logic (match both).

If the interval describes a state machine, additional buttons "Prev State" and "Next State" will be available in the Details section, which will step to the previous/next transition of any channel, while the normal Previous and Next buttons will step to the previous/next interval instance of the same channel.

Intervals and State Machines

This view allows for defining Intervals and State Machines, which allows for user-defined visualization of the recorded events in several views.

The view also lists all Intervals and States machines that have been activated. You can right-click these entries for the following options:

  • Statistics - Shows a statistics report focusing on the durations.
  • Show Timeline - Shows the states/intervals over time, much like a logic analyzer view.
  • Show Plot - Plots the durations of the states/intervals.
  • Create Inverted - Creates a new inverted data set. If the original data set is intervals from Event A to Event B, the inverted data set is the intervals from Event B to the next Event A.
  • Compute Overlap - Creates a new data set that is the intersection of two data sets

Predefined

This opens the Predefined States and Intervals, where you can select from predefined defitions of known states and intervals in the trace. You may activate these data sets to see additional information about objects that Tracealyzer is aware of. For instance, if you are using a TCP stack supported by Tracealyzer, you can include TCP socket states this way.

Custom State Machine

This lets you define a custom state machine. There are two ways:

The simple option assumes the state transitions are logged as user events, on a user event channel specific for this purpose. All messages on this user event channel are assumed to be state transitions.

The advanced option lets you define a state machine based on any events that match a regular expression, including both user events and kernel events.

Custom Intervals

Select this option to open an editor for custom interval definitions. Begin with specifying a name for the interval, and then provide two rules for the beginning and end of the interval. The first interval will begin at the first event matching Interval Start, and finish at the first following event matching Interval End.

To check if the definition will actually generate any intervals, use the Test button. It might take a little while to do for a long trace, because it will read the whole trace until matches are found, or the trace ends. When the definition is completed, use Save to save and apply to the loaded trace. This will show the interval in any open Vertical Trace view.

Keyboard Mapping

All keyboard shortcuts can be changed for the current user. It is also possible to assign shortcuts to your favorite view.

Select a command to add or edit its shortcut. Clicking Restore restores the default shortcut for the command.

Navigation Bar

The Navigation Bar is by default docked to the left, and shows a list of available views.

The list is normally ordered based on how much time is spent with each view open, thus keeping the most used views easily accessible. Note the All Views option, that gives an overview of all views and features in Tracealyzer.

To configure what is displayed on the Navigation Bar, see the Navigation Bar Settings (found under File -> Settings -> Navigation Bar Settings).

Object List

The Object list shows all Objects.

The list can be sorted on either column by clicking the column headers.

Double-clicking an entry in the list opens the Object History view for that object.

Performed Events

When anything is selected in any view, this view shows any associated events.

Selection Details

The Selection Details view displays information about the currently selected Actor in the main view. The info shown include among others timing, fragmentation and any events that have occurred. Property values for the selected instance, as well as actor average, minimum and maximum values. Double-clicking on a maximum or minimum value scrolls the main view to show the corresponding instance in the trace.

Snapshot

The Snapshot tool is used to overview snapshot creation.

Use the combo box on the top to change between different supported connection types. For each type, different Settings will be available.

When ready with the setup, simply press Read Snapshot button, or use the Snapshot button in Navigation Bar directly.

With the snapshot tool you can also Halt, Resume, or Reset the selected Target.

Note
The actions might not work on all targets, depending on the the connection type.

Trace Overview

The Trace Overview shows details of the recorded trace as well as any warnings produced by the recorder.

User Manual

Pressing F1 will open the context sensitive help.
If any view is active it will show the help page for that view.
If no view is active the User Manual is shown.

Settings

Overview

All settings for connections and user interface can be found under Settings.

To make it easier to find settings, a Find text box is in on top of the settings tree.

Projects

All settings, with the exception of those found under Global Settings, are specific to a project. These combine settings, like target connection information (streaming/snapshot settings) and the recently used traces, making it easier to switch.

When starting Percepio Tracealyzer the first time the Default Project is selected, to allow new users the easiest way to start using it.
If you are developing for multiple targets, it is a good idea to set up different projects for each.
Uncheck Reopen last Project either from the checkbox at the bottom of the Welcome screen, or from Global Settings, to allow project switching on startup.

To switch between different projects, Percepio Tracealyzer has to be restarted. All currently available projects can be accessed by the File > Project menu, which allows simple switching.

Global Settings

These settings affect how Percepio Tracealyzer behaves. They are not tied to a particular project.

File associations can be modified here.

Project Settings

These settings, and all pages in the tree, apply to the currently active project. Changes take effect when you click OK or Apply.

Percepio Tracealyzer usually saves trace data in your local Documents folder. If you want to save data somewhere else, e.g. if you plan to record a very long trace and need extra disk space, you can specify another folder as Trace Directory. Note that if the current directory is the default one, the Trace Directory field will be empty when opening the settings.

For trace previews there are two threshold values.

  • The lower limit (ask if exceeding) sets when preview mode is suggested.
  • The higher limit (always use if exceeding) sets when preview mode is automatically used.

To always use preview for all traces, set the always limit to 1, or to completely disable preview, set suggest limit to a very high value.

Note
The limit is not the raw trace size (i.e. size on disk), but the estimated RAM memory consumption; the difference is depending on the used trace format.

API Connection Monitor Settings

Settings for the Tracealyzer API, which allows for other tools to interact with Tracealyzer.

Check "Start API Connection on Startup" to start the API connection directly when starting Tracealyzer.

Use the Host and Port sections to select what host and port to use. Leave host blank to use localhost.

Tracealyzer support both XML and JSON formats, select the appropriate one.

Note
Normally when the API is used Tracealyzer will be launched by the other application. When it is, the Host, Port, and Type settings are overridden.

Check "Reconnect if Disconnected" to have the API try to reconnect if the other end disconnects.

Check "Ask on Trace Received" to always get a message box if a new trace is sent over the API.

Automatic Event Filtering Settings

This setting controls which event labels that are displayed in an Event Field, in case the window is too small to display all events enabled in the main Filter. By enabling the automatic event filtering, you can often avoid the "all or nothing" display in Event Fields when scrolling or zooming. This way, you can still see important evens (e.g. User Events) even if there are a lots of less important events in the current view. Note that the Automatic Event Filtering is independent of the main Filter settings.

Note
Automatic Event Filtering is disabled by default.

When the Trace View is zoomed out too much to show all events in the view, the events with lower priority will be hidden first, see the Trace View for more details.

To change the priority order, drag and drop the event types to the desired priority level (highest at the top, lowest at the bottom).

Note
In Mono there is a problem with the drag and drop support, so instead buttons are added to move the types to higher or lower level.

Note
Changes will not be saved until Apply or OK is clicked.

To reset to default display priorities, click the Reset to Default button, and then apply.

Docking Settings

The docking settings can be set to be suit the current monitor setup quickly, or set to custom behavior.

To understand the difference between different variants, see the section on User Interface.

Layout Mode

  • Default - In this mode, new docked views will open in up to four different tab groups before starting to add the views as tabs.
  • Tabbed - In this mode, new docked views will add to the main tab group.

Floating Mode

  • Default - In this mode, new floating views will be shown as separate floating views.
  • Docked - In this mode, new floating views will instead be docked.

J-Link Settings

Settings for SEGGER J-Link debug probes.

Navigation Bar Settings

The Navigation Bar Settings will allow you to customize which icons will show up in the navigation bar, and also the sort order.

Sort Order
  • Sort by activated time - In this mode the sort order is the time spent with each view open.
  • Sort by number of activations - In this mode the sort order is the number of times a views has been opened, including times it is opened by setting/changing layout.
  • Custom order - In this mode it is possible to change the order of the icons, where the first ones are on top.

Note
Even if using Custom order, views that are part of a group will be shown in the extended menu.

Performance Settings

Here are all settings that can affect performance in a negative way.

Many trace formats support raw events, but they are normally not included when loading a trace. If raw events are wanted, check Include Raw Events in Trace check box.

Note
Loading raw events will normally result in double the number of events in the trace, which will both affect the time it takes to load the trace and how much memory the trace will require.

PSF Settings

These settings are for configuring streaming when using the Percepio trace recorder. PSF stands for Percepio Streaming Format. This can be streamed over multiple target connections (corresponding to stream ports on the target side). There are several settings for each target connection. See the Streaming Mode section for details.

Snapshot Settings

Settings for the Snapshot tool.

Select the snapshot engine to use. Apply (or OK) will automatically reflect this in the Snapshot tool.

ST-LINK Settings

This settings page lists all ST-LINKs that have been identified. It is possible to manually refresh the list by clicking the Refresh button.

In case multiple probes are connected, you may click Identify to flash a LED on the selected ST-LINK probe.

View Settings

These settings are the default values for views.

Terminology

ActorAn execution context - a task, thread or an Interrupt Service Routine (ISR).
Actor InstanceAn execution of an actor. For interrupt service routines, this means from start to finish of the ISR handler. For tasks, this is application-dependent but typically means one iteration in the main loop. See Instance Finish Event. An Actor Instance consists of one or several fragments, depending on preemptions, blocking and interrupts.
Execution TimeThe amount of CPU time used by an Actor Instance, excluding preemptions.
Response TimeThe time from the start of an actor instance until it finishes.
FragmentA time interval when a specific actor executes uninterrupted. Fragments are visualized as colored rectangles in the scheduling trace. A fragment belongs to a specific Actor Instance.
FragmentationThe number of fragments within an Actor Instance. If an Actor Instance executes in full without preemptions, the fragmentation of the instance is 1.
Instance Finish EventA service call that is considered as the finish of a task instance, typically in the context of repeating tasks with a main loop. By default, Percepio Tracealyzer considers blocking "receive" calls (including waiting for semaphores and other events) as well as "delay" calls to be Instance Finish Events. Blocking on Mutex calls are however not considered as IFEs.
ISRInterrupt Service Routine, i.e., the handler of an interrupt.
ObjectAn object referenced in a traced event, such as a queue, semaphore, mutex or task.
ServiceTypically an API function provided by the kernel, often performing an operation on a object.
PeriodicityThe time between two consecutive instances of an actor, counted from the start of the previous actor instance to the start of the current actor instance.
SeparationThe time between two consecutive instances of an actor, counted from the end of the previous actor instance to the start of the current actor instance.
TaskA thread of execution. Percepio Tracealyzer generally refer to threads as "tasks".

Support and Licensing

For technical support, contact support@percepio.com.

To request a quote, contact your nearest distributor. If we are not represented in your region, or you have other licensing questions, please contact sales@percepio.com

Want some help getting started?
Get up and running fast with a free 45 minute consulting session with Niclas Lindblom, Senior FAE at Percepio. This is not a slideshow presentation – Niclas will assist you via video conference, hands-on, using your own project, tools, and hardware. Contact support@percepio.com to book a time!


Copyright Percepio AB 2019, all rights reserved.

Generated for Percepio Tracealyzer, version 4.3.4.12806