Skip to content

Commit 0061d3f

Browse files
Enable gprof onboard profiling (#2669)
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.
1 parent 48bc91a commit 0061d3f

File tree

17 files changed

+1259
-28
lines changed

17 files changed

+1259
-28
lines changed

.github/workflows/pull-request.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ jobs:
2020
uses: codespell-project/actions-codespell@v2
2121
with:
2222
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
23-
ignore_words_list: ser,dout,shiftIn,acount
23+
ignore_words_list: ser,dout,shiftIn,acount,froms
2424
- name: Get submodules for following tests
2525
run: git submodule update --init
2626
- name: Check package references

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,8 @@ Read the [Contributing Guide](https://github.com/earlephilhower/arduino-pico/blo
137137
* printf (i.e. debug) output over USB serial
138138
* Transparent use of PSRAM globals and heap (RP2350 only)
139139
* ARM or RISC-V (Hazard3) support for the RP2350
140+
* Semihosted serial and file system access
141+
* GPROF profiling support
140142

141143
The RP2040 PIO state machines (SMs) are used to generate jitter-free:
142144
* Servos

boards.txt

Lines changed: 457 additions & 0 deletions
Large diffs are not rendered by default.

cores/rp2040/RP2040Support.cpp

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,11 @@
1818
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
1919
*/
2020

21+
#include <Arduino.h>
22+
#include <pico/runtime.h>
23+
2124
#ifdef PICO_RP2040
2225

23-
#include <Arduino.h>
2426
#include <hardware/structs/psm.h>
2527

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

3739
#endif
40+
41+
#ifdef __PROFILE
42+
Stream *__profileFile;
43+
int __writeProfileCB(const void *data, int len) {
44+
return __profileFile->write((const char *)data, len);
45+
}
46+
47+
#ifdef __PROFILE
48+
extern "C" void runtime_init_setup_profiling();
49+
#define PICO_RUNTIME_INIT_PROFILING "11011" // Towards the end, after PSRAM
50+
PICO_RUNTIME_INIT_FUNC_RUNTIME(runtime_init_setup_profiling, PICO_RUNTIME_INIT_PROFILING);
51+
#endif
52+
53+
#endif

cores/rp2040/RP2040Support.h

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
1919
*/
2020

21+
#pragma once
22+
2123
#include <hardware/clocks.h>
2224
#include <hardware/irq.h>
2325
#include <hardware/pio.h>
@@ -45,6 +47,13 @@
4547

4648
extern "C" volatile bool __otherCoreIdled;
4749

50+
extern "C" {
51+
#ifdef __PROFILE
52+
typedef int (*profileWriteCB)(const void *data, int len);
53+
extern void _writeProfile(profileWriteCB writeCB);
54+
#endif
55+
}
56+
4857
class _MFIFO {
4958
public:
5059
_MFIFO() { /* noop */ };
@@ -180,7 +189,7 @@ class RP2040 {
180189

181190
void begin() {
182191
_epoch = 0;
183-
#if !defined(__riscv)
192+
#if !defined(__riscv) && !defined(__PROFILE)
184193
if (!__isFreeRTOS) {
185194
// Enable SYSTICK exception
186195
exception_set_exclusive_handler(SYSTICK_EXCEPTION, _SystickHandler);
@@ -193,7 +202,7 @@ class RP2040 {
193202
_ccountPgm->prepare(&_pio, &_sm, &off);
194203
ccount_program_init(_pio, _sm, off);
195204
pio_sm_set_enabled(_pio, _sm, true);
196-
#if !defined(__riscv)
205+
#if !defined(__riscv) && !defined(__PROFILE)
197206
}
198207
#endif
199208
}
@@ -217,7 +226,7 @@ class RP2040 {
217226
// Get CPU cycle count. Needs to do magic to extens 24b HW to something longer
218227
volatile uint64_t _epoch = 0;
219228
inline uint32_t getCycleCount() {
220-
#if !defined(__riscv)
229+
#if !defined(__riscv) && !defined(__PROFILE)
221230
if (!__isFreeRTOS) {
222231
uint32_t epoch;
223232
uint32_t ctr;
@@ -229,13 +238,13 @@ class RP2040 {
229238
} else {
230239
#endif
231240
return ccount_read(_pio, _sm);
232-
#if !defined(__riscv)
241+
#if !defined(__riscv) && !defined(__PROFILE)
233242
}
234243
#endif
235244
}
236245

237246
inline uint64_t getCycleCount64() {
238-
#if !defined(__riscv)
247+
#if !defined(__riscv) && !defined(__PROFILE)
239248
if (!__isFreeRTOS) {
240249
uint64_t epoch;
241250
uint64_t ctr;
@@ -247,7 +256,7 @@ class RP2040 {
247256
} else {
248257
#endif
249258
return ccount_read(_pio, _sm);
250-
#if !defined(__riscv)
259+
#if !defined(__riscv) && !defined(__PROFILE)
251260
}
252261
#endif
253262
}
@@ -473,6 +482,21 @@ class RP2040 {
473482
#endif
474483
}
475484

485+
#ifdef __PROFILE
486+
void writeProfiling(Stream *f) {
487+
extern Stream *__profileFile;
488+
extern int __writeProfileCB(const void *data, int len);
489+
__profileFile = f;
490+
_writeProfile(__writeProfileCB);
491+
}
492+
493+
size_t getProfileMemoryUsage() {
494+
extern int __profileMemSize;
495+
return (size_t) __profileMemSize;
496+
}
497+
#endif
498+
499+
476500

477501
private:
478502
static void _SystickHandler() {

cores/rp2040/_freertos.h

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -30,32 +30,36 @@ extern bool __isFreeRTOS;
3030
// FreeRTOS has been set up
3131
extern volatile bool __freeRTOSinitted;
3232

33+
#ifdef __cplusplus
3334
extern "C" {
34-
struct QueueDefinition; /* Using old naming convention so as not to break kernel aware debuggers. */
35-
typedef struct QueueDefinition * QueueHandle_t;
36-
typedef QueueHandle_t SemaphoreHandle_t;
37-
typedef int32_t BaseType_t;
35+
#endif // __cplusplus
36+
struct QueueDefinition; /* Using old naming convention so as not to break kernel aware debuggers. */
37+
typedef struct QueueDefinition * QueueHandle_t;
38+
typedef QueueHandle_t SemaphoreHandle_t;
39+
typedef int32_t BaseType_t;
3840

39-
extern bool __freertos_check_if_in_isr() __attribute__((weak));
41+
extern bool __freertos_check_if_in_isr() __attribute__((weak));
4042

41-
extern SemaphoreHandle_t __freertos_mutex_create() __attribute__((weak));
42-
extern SemaphoreHandle_t _freertos_recursive_mutex_create() __attribute__((weak));
43+
extern SemaphoreHandle_t __freertos_mutex_create() __attribute__((weak));
44+
extern SemaphoreHandle_t _freertos_recursive_mutex_create() __attribute__((weak));
4345

44-
extern void __freertos_mutex_take(SemaphoreHandle_t mtx) __attribute__((weak));
46+
extern void __freertos_mutex_take(SemaphoreHandle_t mtx) __attribute__((weak));
4547

46-
extern int __freertos_mutex_take_from_isr(SemaphoreHandle_t mtx, BaseType_t* pxHigherPriorityTaskWoken) __attribute__((weak));
47-
extern int __freertos_mutex_try_take(SemaphoreHandle_t mtx) __attribute__((weak));
48-
extern void __freertos_mutex_give(SemaphoreHandle_t mtx) __attribute__((weak));
49-
extern void __freertos_mutex_give_from_isr(SemaphoreHandle_t mtx, BaseType_t* pxHigherPriorityTaskWoken) __attribute__((weak));
48+
extern int __freertos_mutex_take_from_isr(SemaphoreHandle_t mtx, BaseType_t* pxHigherPriorityTaskWoken) __attribute__((weak));
49+
extern int __freertos_mutex_try_take(SemaphoreHandle_t mtx) __attribute__((weak));
50+
extern void __freertos_mutex_give(SemaphoreHandle_t mtx) __attribute__((weak));
51+
extern void __freertos_mutex_give_from_isr(SemaphoreHandle_t mtx, BaseType_t* pxHigherPriorityTaskWoken) __attribute__((weak));
5052

51-
extern void __freertos_recursive_mutex_take(SemaphoreHandle_t mtx) __attribute__((weak));
52-
extern int __freertos_recursive_mutex_try_take(SemaphoreHandle_t mtx) __attribute__((weak));
53-
extern void __freertos_recursive_mutex_give(SemaphoreHandle_t mtx) __attribute__((weak));
53+
extern void __freertos_recursive_mutex_take(SemaphoreHandle_t mtx) __attribute__((weak));
54+
extern int __freertos_recursive_mutex_try_take(SemaphoreHandle_t mtx) __attribute__((weak));
55+
extern void __freertos_recursive_mutex_give(SemaphoreHandle_t mtx) __attribute__((weak));
5456

55-
extern void __freertos_idle_other_core() __attribute__((weak));
56-
extern void __freertos_resume_other_core() __attribute__((weak));
57+
extern void __freertos_idle_other_core() __attribute__((weak));
58+
extern void __freertos_resume_other_core() __attribute__((weak));
5759

58-
extern void __freertos_task_exit_critical() __attribute__((weak));
59-
extern void __freertos_task_enter_critical() __attribute__((weak));
60+
extern void __freertos_task_exit_critical() __attribute__((weak));
61+
extern void __freertos_task_enter_critical() __attribute__((weak));
62+
#ifdef __cplusplus
6063
}
6164
extern SemaphoreHandle_t __get_freertos_mutex_for_ptr(mutex_t *m, bool recursive = false);
65+
#endif // __cplusplus

0 commit comments

Comments
 (0)