Skip to content

Commit

Permalink
Enable gprof onboard profiling (#2669)
Browse files Browse the repository at this point in the history
Adds a menu item to enable onboard profiling.  This requires significant
RAM and really only makes sense on devices with PSRAM to store the state.

When the menu item is selected, allocates RAM and tracks function calls and
periodically samples the PC to generate a histogram of application usage.
The onboard gmon.out file can be written over Semihosting or
some other way to transfer to a PC for analysis.

Adds a profiling example with command lines.
  • Loading branch information
earlephilhower authored Dec 6, 2024
1 parent 48bc91a commit 0061d3f
Show file tree
Hide file tree
Showing 17 changed files with 1,259 additions and 28 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/pull-request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
uses: codespell-project/actions-codespell@v2
with:
skip: ./ArduinoCore-API,./libraries/ESP8266SdFat,./libraries/Adafruit_TinyUSB_Arduino,./libraries/LittleFS/lib,./tools/pyserial,./pico-sdk,./.github,./docs/i2s.rst,./cores/rp2040/api,./libraries/FreeRTOS,./tools/libbearssl/bearssl,./include,./libraries/WiFi/examples/BearSSL_Server,./ota/uzlib,./libraries/http-parser/lib,./libraries/WebServer/examples/HelloServerBearSSL/HelloServerBearSSL.ino,./libraries/HTTPUpdateServer/examples/SecureBearSSLUpdater/SecureBearSSLUpdater.ino,./.git,./libraries/FatFS/lib/fatfs,./libraries/FatFS/src/diskio.h,./libraries/FatFS/src/ff.cpp,./libraries/FatFS/src/ffconf.h,./libraries/FatFS/src/ffsystem.cpp,./libraries/FatFS/src/ff.h,./libraries/lwIP_WINC1500/src/driver,./libraries/lwIP_WINC1500/src/common,./libraries/lwIP_WINC1500/src/bus_wrapper,./libraries/lwIP_WINC1500/src/spi_flash
ignore_words_list: ser,dout,shiftIn,acount
ignore_words_list: ser,dout,shiftIn,acount,froms
- name: Get submodules for following tests
run: git submodule update --init
- name: Check package references
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,8 @@ Read the [Contributing Guide](https://github.com/earlephilhower/arduino-pico/blo
* printf (i.e. debug) output over USB serial
* Transparent use of PSRAM globals and heap (RP2350 only)
* ARM or RISC-V (Hazard3) support for the RP2350
* Semihosted serial and file system access
* GPROF profiling support

The RP2040 PIO state machines (SMs) are used to generate jitter-free:
* Servos
Expand Down
457 changes: 457 additions & 0 deletions boards.txt

Large diffs are not rendered by default.

18 changes: 17 additions & 1 deletion cores/rp2040/RP2040Support.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include <Arduino.h>
#include <pico/runtime.h>

#ifdef PICO_RP2040

#include <Arduino.h>
#include <hardware/structs/psm.h>

extern "C" void boot_double_tap_check();
Expand All @@ -35,3 +37,17 @@ void RP2040::enableDoubleResetBootloader() {
}

#endif

#ifdef __PROFILE
Stream *__profileFile;
int __writeProfileCB(const void *data, int len) {
return __profileFile->write((const char *)data, len);
}

#ifdef __PROFILE
extern "C" void runtime_init_setup_profiling();
#define PICO_RUNTIME_INIT_PROFILING "11011" // Towards the end, after PSRAM
PICO_RUNTIME_INIT_FUNC_RUNTIME(runtime_init_setup_profiling, PICO_RUNTIME_INIT_PROFILING);
#endif

#endif
36 changes: 30 additions & 6 deletions cores/rp2040/RP2040Support.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/

#pragma once

#include <hardware/clocks.h>
#include <hardware/irq.h>
#include <hardware/pio.h>
Expand Down Expand Up @@ -45,6 +47,13 @@

extern "C" volatile bool __otherCoreIdled;

extern "C" {
#ifdef __PROFILE
typedef int (*profileWriteCB)(const void *data, int len);
extern void _writeProfile(profileWriteCB writeCB);
#endif
}

class _MFIFO {
public:
_MFIFO() { /* noop */ };
Expand Down Expand Up @@ -180,7 +189,7 @@ class RP2040 {

void begin() {
_epoch = 0;
#if !defined(__riscv)
#if !defined(__riscv) && !defined(__PROFILE)
if (!__isFreeRTOS) {
// Enable SYSTICK exception
exception_set_exclusive_handler(SYSTICK_EXCEPTION, _SystickHandler);
Expand All @@ -193,7 +202,7 @@ class RP2040 {
_ccountPgm->prepare(&_pio, &_sm, &off);
ccount_program_init(_pio, _sm, off);
pio_sm_set_enabled(_pio, _sm, true);
#if !defined(__riscv)
#if !defined(__riscv) && !defined(__PROFILE)
}
#endif
}
Expand All @@ -217,7 +226,7 @@ class RP2040 {
// Get CPU cycle count. Needs to do magic to extens 24b HW to something longer
volatile uint64_t _epoch = 0;
inline uint32_t getCycleCount() {
#if !defined(__riscv)
#if !defined(__riscv) && !defined(__PROFILE)
if (!__isFreeRTOS) {
uint32_t epoch;
uint32_t ctr;
Expand All @@ -229,13 +238,13 @@ class RP2040 {
} else {
#endif
return ccount_read(_pio, _sm);
#if !defined(__riscv)
#if !defined(__riscv) && !defined(__PROFILE)
}
#endif
}

inline uint64_t getCycleCount64() {
#if !defined(__riscv)
#if !defined(__riscv) && !defined(__PROFILE)
if (!__isFreeRTOS) {
uint64_t epoch;
uint64_t ctr;
Expand All @@ -247,7 +256,7 @@ class RP2040 {
} else {
#endif
return ccount_read(_pio, _sm);
#if !defined(__riscv)
#if !defined(__riscv) && !defined(__PROFILE)
}
#endif
}
Expand Down Expand Up @@ -473,6 +482,21 @@ class RP2040 {
#endif
}

#ifdef __PROFILE
void writeProfiling(Stream *f) {
extern Stream *__profileFile;
extern int __writeProfileCB(const void *data, int len);
__profileFile = f;
_writeProfile(__writeProfileCB);
}

size_t getProfileMemoryUsage() {
extern int __profileMemSize;
return (size_t) __profileMemSize;
}
#endif



private:
static void _SystickHandler() {
Expand Down
42 changes: 23 additions & 19 deletions cores/rp2040/_freertos.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,32 +30,36 @@ extern bool __isFreeRTOS;
// FreeRTOS has been set up
extern volatile bool __freeRTOSinitted;

#ifdef __cplusplus
extern "C" {
struct QueueDefinition; /* Using old naming convention so as not to break kernel aware debuggers. */
typedef struct QueueDefinition * QueueHandle_t;
typedef QueueHandle_t SemaphoreHandle_t;
typedef int32_t BaseType_t;
#endif // __cplusplus
struct QueueDefinition; /* Using old naming convention so as not to break kernel aware debuggers. */
typedef struct QueueDefinition * QueueHandle_t;
typedef QueueHandle_t SemaphoreHandle_t;
typedef int32_t BaseType_t;

extern bool __freertos_check_if_in_isr() __attribute__((weak));
extern bool __freertos_check_if_in_isr() __attribute__((weak));

extern SemaphoreHandle_t __freertos_mutex_create() __attribute__((weak));
extern SemaphoreHandle_t _freertos_recursive_mutex_create() __attribute__((weak));
extern SemaphoreHandle_t __freertos_mutex_create() __attribute__((weak));
extern SemaphoreHandle_t _freertos_recursive_mutex_create() __attribute__((weak));

extern void __freertos_mutex_take(SemaphoreHandle_t mtx) __attribute__((weak));
extern void __freertos_mutex_take(SemaphoreHandle_t mtx) __attribute__((weak));

extern int __freertos_mutex_take_from_isr(SemaphoreHandle_t mtx, BaseType_t* pxHigherPriorityTaskWoken) __attribute__((weak));
extern int __freertos_mutex_try_take(SemaphoreHandle_t mtx) __attribute__((weak));
extern void __freertos_mutex_give(SemaphoreHandle_t mtx) __attribute__((weak));
extern void __freertos_mutex_give_from_isr(SemaphoreHandle_t mtx, BaseType_t* pxHigherPriorityTaskWoken) __attribute__((weak));
extern int __freertos_mutex_take_from_isr(SemaphoreHandle_t mtx, BaseType_t* pxHigherPriorityTaskWoken) __attribute__((weak));
extern int __freertos_mutex_try_take(SemaphoreHandle_t mtx) __attribute__((weak));
extern void __freertos_mutex_give(SemaphoreHandle_t mtx) __attribute__((weak));
extern void __freertos_mutex_give_from_isr(SemaphoreHandle_t mtx, BaseType_t* pxHigherPriorityTaskWoken) __attribute__((weak));

extern void __freertos_recursive_mutex_take(SemaphoreHandle_t mtx) __attribute__((weak));
extern int __freertos_recursive_mutex_try_take(SemaphoreHandle_t mtx) __attribute__((weak));
extern void __freertos_recursive_mutex_give(SemaphoreHandle_t mtx) __attribute__((weak));
extern void __freertos_recursive_mutex_take(SemaphoreHandle_t mtx) __attribute__((weak));
extern int __freertos_recursive_mutex_try_take(SemaphoreHandle_t mtx) __attribute__((weak));
extern void __freertos_recursive_mutex_give(SemaphoreHandle_t mtx) __attribute__((weak));

extern void __freertos_idle_other_core() __attribute__((weak));
extern void __freertos_resume_other_core() __attribute__((weak));
extern void __freertos_idle_other_core() __attribute__((weak));
extern void __freertos_resume_other_core() __attribute__((weak));

extern void __freertos_task_exit_critical() __attribute__((weak));
extern void __freertos_task_enter_critical() __attribute__((weak));
extern void __freertos_task_exit_critical() __attribute__((weak));
extern void __freertos_task_enter_critical() __attribute__((weak));
#ifdef __cplusplus
}
extern SemaphoreHandle_t __get_freertos_mutex_for_ptr(mutex_t *m, bool recursive = false);
#endif // __cplusplus
Loading

0 comments on commit 0061d3f

Please sign in to comment.