From 5e52a9e200aa89d8f1920b895288401c9af99a60 Mon Sep 17 00:00:00 2001 From: Johny Mattsson Date: Thu, 16 Sep 2021 13:54:55 +1000 Subject: [PATCH] Added heaptrace module. --- components/modules/CMakeLists.txt | 1 + components/modules/Kconfig | 9 +++ components/modules/heaptrace.c | 84 +++++++++++++++++++++++ docs/modules/heaptrace.md | 106 ++++++++++++++++++++++++++++++ mkdocs.yml | 1 + 5 files changed, 201 insertions(+) create mode 100644 components/modules/heaptrace.c create mode 100644 docs/modules/heaptrace.md diff --git a/components/modules/CMakeLists.txt b/components/modules/CMakeLists.txt index 4aaf296e..5d96d497 100644 --- a/components/modules/CMakeLists.txt +++ b/components/modules/CMakeLists.txt @@ -9,6 +9,7 @@ set(module_srcs "encoder.c" "file.c" "gpio.c" + "heaptrace.c" "http.c" "i2c.c" "i2c_hw_master.c" diff --git a/components/modules/Kconfig b/components/modules/Kconfig index 1d0098d4..749e0155 100644 --- a/components/modules/Kconfig +++ b/components/modules/Kconfig @@ -74,6 +74,15 @@ menu "NodeMCU modules" help Includes the GPIO module (recommended). + config NODEMCU_CMODULE_HEAPTRACE + bool "Heap trace debug module" + default "n" + depends on HEAP_TRACING_STANDALONE + help + Includes the heap tracing module. This provides an interface to + the IDF's heap tracing API, allowing interactive tracing + sessions via the Lua command line. + config NODEMCU_CMODULE_HTTP bool "HTTP module" default "y" diff --git a/components/modules/heaptrace.c b/components/modules/heaptrace.c new file mode 100644 index 00000000..8a5966f4 --- /dev/null +++ b/components/modules/heaptrace.c @@ -0,0 +1,84 @@ +#include "module.h" +#include "lauxlib.h" + +#include "esp_heap_trace.h" + +static heap_trace_record_t *buffer = NULL; + +static int lht_init(lua_State *L) +{ + int records = luaL_checkint(L, 1); + if (records <= 0) + return luaL_error(L, "invalid trace buffer size"); + + heap_trace_stop(); + free(buffer); + buffer = calloc(sizeof(heap_trace_record_t), records); + if (!buffer) + return luaL_error(L, "out of memory"); + + esp_err_t err = heap_trace_init_standalone(buffer, records); + if (err != ESP_OK) + return luaL_error(L, "failed to init heap tracing; code %d", err); + + return 0; +} + + +static int lht_start(lua_State *L) +{ + esp_err_t err; + switch(luaL_checkint(L, 1)) + { + case HEAP_TRACE_ALL: err = heap_trace_start(HEAP_TRACE_ALL); break; + case HEAP_TRACE_LEAKS: err = heap_trace_start(HEAP_TRACE_LEAKS); break; + default: return luaL_error(L, "invalid trace mode"); + } + + if (err != ESP_OK) + return luaL_error(L, "failed to start heap tracing; code %d", err); + + return 0; +} + + +static int lht_stop(lua_State *L) +{ + esp_err_t err = heap_trace_stop(); + if (err != ESP_OK) + return luaL_error(L, "failed to stop heap tracing; code %d", err); + + return 0; +} + + +static int lht_resume(lua_State *L) +{ + esp_err_t err = heap_trace_resume(); + if (err != ESP_OK) + return luaL_error(L, "failed to resume heap tracing; code %d", err); + + return 0; +} + + +static int lht_dump(lua_State *L) +{ + (void)L; + heap_trace_dump(); + return 0; +} + + +LROT_BEGIN(heaptrace, NULL, 0) + LROT_FUNCENTRY( init, lht_init ) + LROT_FUNCENTRY( start, lht_start ) + LROT_FUNCENTRY( stop, lht_stop ) + LROT_FUNCENTRY( resume, lht_resume ) + LROT_FUNCENTRY( dump, lht_dump ) + + LROT_NUMENTRY( TRACE_ALL, HEAP_TRACE_ALL ) + LROT_NUMENTRY( TRACE_LEAKS, HEAP_TRACE_LEAKS ) +LROT_END(heaptrace, NULL, 0) + +NODEMCU_MODULE(HEAPTRACE, "heaptrace", heaptrace, NULL); diff --git a/docs/modules/heaptrace.md b/docs/modules/heaptrace.md new file mode 100644 index 00000000..578d4e56 --- /dev/null +++ b/docs/modules/heaptrace.md @@ -0,0 +1,106 @@ +# Heaptrace Module +| Since | Origin / Contributor | Maintainer | Source | +| :----- | :-------------------- | :---------- | :------ | +| 2021-09-16 | [Johny Mattsson](https://github.com/jmattsson) |[Johny Mattsson](https://github.com/jmattsson) | [heaptrace.c](../../components/modules/heaptrace.c)| + +The heaptrace module is a debug aid for diagnosing heap allocations and +leaks thereof. It provides an interface to the [built-in heap tracing +support in the IDF](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/heap_debug.html), enabling interactive heap tracing +from the Lua command line. + +To use this module, "standalone" heap tracing must be enabled in Kconfig +first. This setting is found (at the time of writing) under +"Component config" > "Heap memory debugging" > "Heap tracing". The depth +of the call chain to capture can also be configured there. It can be very +beneficial to set that to its max, but it comes at significantly increased +memory requirements in turn. + +A typical sequence of commands for a heap tracing session will be: +```lua +heaptrace.init(200) -- your needed buffer size will depend on your use case +collectgarbage() -- start with as clean a slate as possible +heaptrace.start(heaptrace.TRACE_LEAKS) -- start in leak tracing mode +heaptrace.dump() -- dump the current state of allocations +... -- do the thing that is leaking memory +collectgarbage() -- free things that can be freed, to avoid false positives +heaptrace.stop() -- optional, but provides higher quality output next +heaptrace.dump() -- dump the current state of allocations, hopefully showing the leaked entries and where they got allocated from +-- heaptrace.resume() -- optionally resume the tracing, if stopped previously +``` + +## heaptrace.init +Allocates and registers the heap tracing buffer. + +#### Syntax +```lua +heaptrace.init(bufsz) +``` + +#### Parameters +- `bufsz` the size of the heap tracing buffer, expressed as number of heap tracing records. The actual size depends on the call chain depth configured in Kconfig. + +#### Returns +`nil` + + +## heaptrace.start +Starts the heap tracing. All allocations and frees will be recorded in the +heap tracing buffer, subject to availability within the buffer. + +#### Syntax +```lua +heaptrace.start(mode) +``` + +#### Parameters +- `mode` the heap tracing mode to use. One of: + - `heaptrace.TRACE_LEAKS` + - `heaptrace.TRACE_ALL` + +#### Returns +`nil` + + +## heaptrace.stop +Stops the heap tracing session. A stopped session may be resumed later. + +#### Syntax +```lua +heaptrace.stop() +``` + +#### Parameters +None. + +#### Returns +`nil` + + +## heaptrace.resume +Resumes a previously stopped heap tracing session. + +#### Syntax +```lua +heaptrace.resume() +``` + +#### Parameters +None. + +#### Returns +`nil` + + +## heaptrace.dump +Dumps the heap trace buffer to the console. + +#### Syntax +```lua +heaptrace.dump() +``` + +#### Parameters +None. + +#### Returns +`nil` diff --git a/mkdocs.yml b/mkdocs.yml index 9a69550c..89e349e1 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -51,6 +51,7 @@ pages: - 'eth': 'modules/eth.md' - 'file': 'modules/file.md' - 'gpio': 'modules/gpio.md' + - 'heaptrace': 'modules/heaptrace.md' - 'http': 'modules/http.md' - 'i2c': 'modules/i2c.md' - 'i2s': 'modules/i2s.md'