Cortex-M debugging: Measure execution time using SWV/ITM

Posted by Magnus Unemyr on Apr 10, 2015 10:22:00 AM

By now, I have written a large number of blog articles highlighting the advanced debugger capabilities offered by the Serial Wire Viewer (SWV) real-time event- and data tracing, available in Cortex-M devices, such as STM32 from STMicroelectronics, Kinetis from Freescale, LPC from NXP, etc. In this blog article, I will mention how the Instrumentation Trace Macrocell (ITM), which is part of SWV, can be used to measure the execution time of any-sized and any-partitioned blocks of code.

For example, you may want to know what the execution time is of a while{} loop. Or how long it takes from the user press the “Heat” button until the oven reaches a certain temperature in the code (perhaps detected by an if{} statement code line), or how long time it takes to execute 15 sequential lines  of code in a function. All these time measurement use cases, and more, can easily be accommodated using SWV/ITM in Cortex-M based devices, such as the widely popular STM32 or Kinetis microcontroller families.

First of all, you need to use a SWV capable JTAG/debugger probe, such as SEGGER J-Link, SEGGER J-Trace or ST-LINK (ST-LINK only works with STM32 while the SEGGER debugger probes works with all ARM Cortex-M devices).

Furthermore, SWV only works in SWD debug mode, not in JTAG debug mode. With the debugger hardware selected properly, you need to enable SWV event- and data- tracing in your ARM Cortex C/C++ compiler and debugger IDE, for example Atollic TrueSTUDIO that has great SWV support.

In your IDE, you need to enable ITM tracing on a port, for example ITM port (channel 0) and timestamps, as outlined in this screenshot from the Atollic TrueSTUDIO IDE:

By enabling SWV tracing with an ITM port/channel enabled, the target software can be instrumented to write a byte on an ITM port/channel at desired times. This is what we will exploit to instrument the application to send the “start timer” and “stop timer” trigger commands to the debugger.

Using the ARM standardized CMSIS header file macros for ITM data byte writing (typically provided by your semiconductor manufacturer), instrument the application code to send a data byte on ITM when you want to start measuring time, and also send one byte when you want to stop measuring execution time. In the example below, the value 1 is written to ITM port 0 before and after a source code line containing a function call:

In the SWV Trace Log debugger view in the Atollic TrueSTUDIO IDE, you can now see that the debugger received both ITM byte data writes from the target system (trace packet index 1 and 3) in this screenshot:

You can also see the time stamps of both ITM byte data writes, and so by subtracting them, you get the time it took to execute whatever code was between the two ITM writes. In this example, 1 was written both before and after the code to measure, which may be a bit confusing if you measure more complex scenarios and perhaps different things at the same time, and so in such case you can write for example 0 at the start and 1 at the end, or something else that may make sense in your case.

Also note this debugger technique measures the execution time of whatever code is between the “start” and “stop” ITM data byte writes. It can be one or more code lines containing loops, function calls, etc. But the “start” and “stop” ITM writes can also be in completely different functions, in vastly different parts of the software, with very long execution times between the “start” and “stop” triggers. For example one “start” trigger when the system has booted and enters main(), and another “stop” trigger when the TCP/IP stack has received 1KB of data. Or whatever makes sense for you.

In case you want to go more graphical with your time measurements, you can open the SWV ITM Timeline Graph debugger view in the Atollic TrueSTUDIO IDE, and you will get a nice graph that moves in real-time as execution progress:

By using the simple technique of performing ITM data byte writes, and subtracting the timestamps between them, Cortex-M developers using STM32, Kinetis or other ARM Cortex devices can easily and very accurately measure the execution time of any-sized and any-partitioned code blocks.

Please note this technique is used to measure the execution time of a particular code run; if you want more generic speed and performance analysis capabilities, you can use the SWV statistical profiling to do that.

Standard ECLIPSE and GNU gcc/gdb do not support Serial Wire Viewer tracing, and hence not ITM either. Atollic TrueSTUDIO however, which is based on ECLIPSE and GNU gcc/gdb, do offer all these capabilities using ECLIPSE and GNU gcc/gdb using commercial proprietary extensions. Atollic TrueSTUDIO supports SWV and ITM using both SEGGER J-Link and J-Trace, as well as ST-LINK for STM32 developers using that.

For more information on Serial Wire Viewer event- and data tracing, read this white paper:

Read our SWV event and data tracing whitepaper!


If you want to read more in ARM Cortex development and debugging, read this white paper:

Read our ARM development whitepaper!



Topics: ECLIPSE, ARM Cortex, GNU tools (GCC/GDB), Debugging, Atollic TrueSTUDIO, SEGGER J-Link, ST-LINK