Profiling Applications with GPROF

Applications running on the Pico can be profiled using GNU GPROF to show where the CPU is using its time on the device and how often certain functions are called. It does this by recompiling the application and adding a small preamble to each function built to identify what functions call what others (and how frequently). It also uses the SYSTICK exception timer to sample and record the PC 10,000 times per second. When an application is complete, the recorded date can be dumped to the host PC as a gmon.,out file which can be processed by arm-none-eabi-gprof into useful date.

s histogram of PCs and tally of function caller/callees can take a significant amount of RAM, from 100KB to 10000KB depending on the size of the application. As such, while the RP2040 may be able to profile small applications, this is only really recommended on the RP2350 with external PSRAM. The profiler will automatically use PSRAM when available. Call rp2040.getProfileMemoryUsage() to get the memory allocated at runtime.

Profiling also adds processing overhead in terms of the periodic sampling and the function preambles. In most cases there is no reason to enable (and many reasons to disable) profiling when an application is deployed to the field.

To transfer the GMON.OUT data from the Pico to the host HP can be done by having the application write it out to an SD card or a LittleFS filesystem which is then manually dumped, but for ease of use semihosting can be used to allow the Pico (under the control of OpenOCD and GDB) to write the gmon.out file directly on the host PC, ready for use.

NOTE Semihosting only works when connected to an OpenOCD + GDB debug session. Running an application compiled for Semihosting without the debugger will cause a panic and hang the chip.

As of now, only ARM has support for Semihosting or GPROF.

Enabling Profiling in an Application

The Tools->Profiling->Enabled menu needs to be selected to enable profiling support in GCC. This will add the necessary preamble to every function compiled (Note that the libpico and libc will not be instrumented because they are pre-built so calls from them will not be fully instrumented. However, PC data will still be grabbed and decoded from them at runtime.)

The application will automatically start collecting profiling data even before setup starts in this mode. It will continue collecting data until you stop and write out the profiling data using rp2040.writeProfiling() to dump to the host, a file, serial port, etc.

For example, an application which does all its processing in setup() might look like:

#include <SemiFS.h>
void setup() {
    SerialSemi.printf("BEGIN\n");
    do_some_work_that_takes_a_long_time_with_many_function_calls();
    // Do lots of other work...
    // Now all done...
    SerialSemi.printf("Writing GMON.OUT\n");
    SemiFS.begin();
    File gmon = SemiFS.open("gmon.out", "w");
    rp2040.writeProfiling(&gmon);
    gmon.close();
    SerialSemi.printf("END\n");
}
void loop() {}

Collecting and Analyzing Profile Data

Running this application under semihosting GDB and OpenOCD generates a gmon.out file in the OpenOCD current working directory. This file, combined with the ELF binary build in the IDE and loaded through GDB, can produce profiler output using

$ /path/to/arm-none-eabi/bin/arm-none-eabi-gprof /path/to/sketch.ino.elf /path/to/gmon.out

See the rp2040/Profiling.ino example for more details.