mirror of
https://github.com/meshtastic/firmware.git
synced 2025-10-29 07:36:46 +00:00
Update when and how memory is allocated.
This commit is contained in:
parent
b206a69570
commit
ba72308d0c
@ -53,12 +53,42 @@ extern MemGet memGet;
|
|||||||
#define LOG_TRACE(...) SEGGER_RTT_printf(0, __VA_ARGS__)
|
#define LOG_TRACE(...) SEGGER_RTT_printf(0, __VA_ARGS__)
|
||||||
#else
|
#else
|
||||||
#if defined(DEBUG_PORT) && !defined(DEBUG_MUTE)
|
#if defined(DEBUG_PORT) && !defined(DEBUG_MUTE)
|
||||||
#define LOG_DEBUG(...) DEBUG_PORT.log(MESHTASTIC_LOG_LEVEL_DEBUG, __VA_ARGS__)
|
#define LOG_DEBUG(...) \
|
||||||
#define LOG_INFO(...) DEBUG_PORT.log(MESHTASTIC_LOG_LEVEL_INFO, __VA_ARGS__)
|
do { \
|
||||||
#define LOG_WARN(...) DEBUG_PORT.log(MESHTASTIC_LOG_LEVEL_WARN, __VA_ARGS__)
|
if (console) { \
|
||||||
#define LOG_ERROR(...) DEBUG_PORT.log(MESHTASTIC_LOG_LEVEL_ERROR, __VA_ARGS__)
|
console->log(MESHTASTIC_LOG_LEVEL_DEBUG, __VA_ARGS__); \
|
||||||
#define LOG_CRIT(...) DEBUG_PORT.log(MESHTASTIC_LOG_LEVEL_CRIT, __VA_ARGS__)
|
} \
|
||||||
#define LOG_TRACE(...) DEBUG_PORT.log(MESHTASTIC_LOG_LEVEL_TRACE, __VA_ARGS__)
|
} while (0)
|
||||||
|
#define LOG_INFO(...) \
|
||||||
|
do { \
|
||||||
|
if (console) { \
|
||||||
|
console->log(MESHTASTIC_LOG_LEVEL_INFO, __VA_ARGS__); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
#define LOG_WARN(...) \
|
||||||
|
do { \
|
||||||
|
if (console) { \
|
||||||
|
console->log(MESHTASTIC_LOG_LEVEL_WARN, __VA_ARGS__); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
#define LOG_ERROR(...) \
|
||||||
|
do { \
|
||||||
|
if (console) { \
|
||||||
|
console->log(MESHTASTIC_LOG_LEVEL_ERROR, __VA_ARGS__); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
#define LOG_CRIT(...) \
|
||||||
|
do { \
|
||||||
|
if (console) { \
|
||||||
|
console->log(MESHTASTIC_LOG_LEVEL_CRIT, __VA_ARGS__); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
#define LOG_TRACE(...) \
|
||||||
|
do { \
|
||||||
|
if (console) { \
|
||||||
|
console->log(MESHTASTIC_LOG_LEVEL_TRACE, __VA_ARGS__); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
#else
|
#else
|
||||||
#define LOG_DEBUG(...)
|
#define LOG_DEBUG(...)
|
||||||
#define LOG_INFO(...)
|
#define LOG_INFO(...)
|
||||||
@ -70,7 +100,12 @@ extern MemGet memGet;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(DEBUG_HEAP)
|
#if defined(DEBUG_HEAP)
|
||||||
#define LOG_HEAP(...) DEBUG_PORT.log(MESHTASTIC_LOG_LEVEL_HEAP, __VA_ARGS__)
|
#define LOG_HEAP(...) \
|
||||||
|
do { \
|
||||||
|
if (console) { \
|
||||||
|
console->log(MESHTASTIC_LOG_LEVEL_HEAP, __VA_ARGS__); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
// Macro-based heap debugging
|
// Macro-based heap debugging
|
||||||
#define DEBUG_HEAP_BEFORE auto heapBefore = memGet.getFreeHeap();
|
#define DEBUG_HEAP_BEFORE auto heapBefore = memGet.getFreeHeap();
|
||||||
|
|||||||
@ -294,7 +294,7 @@ void printInfo()
|
|||||||
{
|
{
|
||||||
LOG_INFO("S:B:%d,%s,%s,%s", HW_VENDOR, optstr(APP_VERSION), optstr(APP_ENV), optstr(APP_REPO));
|
LOG_INFO("S:B:%d,%s,%s,%s", HW_VENDOR, optstr(APP_VERSION), optstr(APP_ENV), optstr(APP_REPO));
|
||||||
}
|
}
|
||||||
#ifndef PIO_UNIT_TESTING
|
#if !defined(PIO_UNIT_TESTING) || !(PIO_UNIT_TESTING)
|
||||||
void setup()
|
void setup()
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -1580,7 +1580,7 @@ void scannerToSensorsMap(const std::unique_ptr<ScanI2CTwoWire> &i2cScanner, Scan
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef PIO_UNIT_TESTING
|
#if !defined(PIO_UNIT_TESTING) || !(PIO_UNIT_TESTING)
|
||||||
void loop()
|
void loop()
|
||||||
{
|
{
|
||||||
runASAP = false;
|
runASAP = false;
|
||||||
|
|||||||
@ -38,6 +38,12 @@
|
|||||||
#include <Preferences.h>
|
#include <Preferences.h>
|
||||||
#include <esp_efuse.h>
|
#include <esp_efuse.h>
|
||||||
#include <esp_efuse_table.h>
|
#include <esp_efuse_table.h>
|
||||||
|
#if __has_include(<esp_ptr.h>)
|
||||||
|
#include <esp_ptr.h>
|
||||||
|
#define NODEDB_HAS_ESP_PTR 1
|
||||||
|
#else
|
||||||
|
#define NODEDB_HAS_ESP_PTR 0
|
||||||
|
#endif
|
||||||
#include <nvs_flash.h>
|
#include <nvs_flash.h>
|
||||||
#include <soc/efuse_reg.h>
|
#include <soc/efuse_reg.h>
|
||||||
#include <soc/soc.h>
|
#include <soc/soc.h>
|
||||||
@ -68,19 +74,60 @@ meshtastic_DeviceUIConfig uiconfig{.screen_brightness = 153, .screen_timeout = 3
|
|||||||
meshtastic_LocalModuleConfig moduleConfig;
|
meshtastic_LocalModuleConfig moduleConfig;
|
||||||
meshtastic_ChannelFile channelFile;
|
meshtastic_ChannelFile channelFile;
|
||||||
|
|
||||||
#if defined(CONFIG_IDF_TARGET_ESP32S3)
|
//------------------------------------------------------------------------------
|
||||||
|
// Runtime instrumentation helpers
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
// Hot/cold storage helpers -------------------------------------------------
|
namespace
|
||||||
// ESP32-S3 targets (Station G2 and similar) keep the heavy NodeInfoLite payloads
|
{
|
||||||
// in PSRAM while mirroring routing/UI critical fields in a compact DRAM cache.
|
|
||||||
// The helpers below keep both views in sync.
|
// Log the pool headroom every 100 inserts (and when we hit MAX) so field logs
|
||||||
|
// capture how close we are to exhausting heap/PSRAM on real hardware.
|
||||||
|
|
||||||
|
void logNodeInsertStats(size_t count, const char *poolLabel)
|
||||||
|
{
|
||||||
|
if (count == 0)
|
||||||
|
return;
|
||||||
|
if ((count % 100) != 0 && count != MAX_NUM_NODES)
|
||||||
|
return;
|
||||||
|
|
||||||
|
LOG_INFO("NodeDB %s pool usage %u/%u nodes, heap free %u, psram free %u", poolLabel, static_cast<unsigned>(count),
|
||||||
|
static_cast<unsigned>(MAX_NUM_NODES), memGet.getFreeHeap(), memGet.getFreePsram());
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(CONFIG_IDF_TARGET_ESP32S3)
|
||||||
|
bool logPsramAllocationOnce(void *ptr, size_t capacity)
|
||||||
|
{
|
||||||
|
static bool logged = false;
|
||||||
|
if (logged || !ptr)
|
||||||
|
return logged;
|
||||||
|
|
||||||
|
#if NODEDB_HAS_ESP_PTR
|
||||||
|
bool inPsram = esp_ptr_external_ram(ptr);
|
||||||
|
#else
|
||||||
|
bool inPsram = false;
|
||||||
|
#endif
|
||||||
|
LOG_INFO("NodeDB PSRAM backing at %p (%s) capacity %u entries (~%u bytes)", ptr, inPsram ? "PSRAM" : "DRAM",
|
||||||
|
static_cast<unsigned>(capacity), static_cast<unsigned>(capacity * sizeof(meshtastic_NodeInfoLite)));
|
||||||
|
logged = true;
|
||||||
|
return logged;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
#if defined(CONFIG_IDF_TARGET_ESP32S3)
|
||||||
|
|
||||||
void NodeDB::initHotCache()
|
void NodeDB::initHotCache()
|
||||||
{
|
{
|
||||||
|
// Pre-reserve the full cold store in PSRAM during boot so the high watermark
|
||||||
|
// shows up immediately in PSRAM usage logs and we avoid fragmented
|
||||||
|
// allocations later in the mission.
|
||||||
psramMeshNodes.resize(MAX_NUM_NODES);
|
psramMeshNodes.resize(MAX_NUM_NODES);
|
||||||
hotNodes.resize(MAX_NUM_NODES);
|
hotNodes.resize(MAX_NUM_NODES);
|
||||||
hotDirty.assign(MAX_NUM_NODES, true);
|
hotDirty.assign(MAX_NUM_NODES, true);
|
||||||
meshNodes = &psramMeshNodes;
|
meshNodes = &psramMeshNodes;
|
||||||
|
logPsramAllocationOnce(psramMeshNodes.data(), psramMeshNodes.capacity());
|
||||||
}
|
}
|
||||||
|
|
||||||
void NodeDB::refreshHotCache()
|
void NodeDB::refreshHotCache()
|
||||||
@ -2263,6 +2310,7 @@ meshtastic_NodeInfoLite *NodeDB::getOrCreateMeshNode(NodeNum n)
|
|||||||
syncHotFromCold(index);
|
syncHotFromCold(index);
|
||||||
lite = &psramMeshNodes[index];
|
lite = &psramMeshNodes[index];
|
||||||
LOG_INFO("Adding node to database with %i nodes and %u bytes free!", numMeshNodes, memGet.getFreeHeap());
|
LOG_INFO("Adding node to database with %i nodes and %u bytes free!", numMeshNodes, memGet.getFreeHeap());
|
||||||
|
logNodeInsertStats(numMeshNodes, "PSRAM");
|
||||||
}
|
}
|
||||||
|
|
||||||
markHotDirty(lite);
|
markHotDirty(lite);
|
||||||
@ -2314,6 +2362,7 @@ meshtastic_NodeInfoLite *NodeDB::getOrCreateMeshNode(NodeNum n)
|
|||||||
memset(lite, 0, sizeof(*lite));
|
memset(lite, 0, sizeof(*lite));
|
||||||
lite->num = n;
|
lite->num = n;
|
||||||
LOG_INFO("Adding node to database with %i nodes and %u bytes free!", numMeshNodes, memGet.getFreeHeap());
|
LOG_INFO("Adding node to database with %i nodes and %u bytes free!", numMeshNodes, memGet.getFreeHeap());
|
||||||
|
logNodeInsertStats(numMeshNodes, "Heap");
|
||||||
}
|
}
|
||||||
|
|
||||||
return lite;
|
return lite;
|
||||||
|
|||||||
@ -43,7 +43,7 @@ Allocator<meshtastic_MeshPacket> &packetPool = dynamicPool;
|
|||||||
(MAX_RX_TOPHONE + MAX_RX_FROMRADIO + 2 * MAX_TX_QUEUE + \
|
(MAX_RX_TOPHONE + MAX_RX_FROMRADIO + 2 * MAX_TX_QUEUE + \
|
||||||
2) // max number of packets which can be in flight (either queued from reception or queued for sending)
|
2) // max number of packets which can be in flight (either queued from reception or queued for sending)
|
||||||
|
|
||||||
#if defined(CONFIG_IDF_TARGET_ESP32S3)
|
#if defined(CONFIG_IDF_TARGET_ESP32S3) && defined(BOARD_HAS_PSRAM)
|
||||||
// Try to put the heavy MeshPacket pool into PSRAM. If that fails we fall back to
|
// Try to put the heavy MeshPacket pool into PSRAM. If that fails we fall back to
|
||||||
// heap allocation so the radio stays functional (at the cost of fewer packets).
|
// heap allocation so the radio stays functional (at the cost of fewer packets).
|
||||||
static PsramMemoryPool<meshtastic_MeshPacket, MAX_PACKETS_STATIC> psramPool;
|
static PsramMemoryPool<meshtastic_MeshPacket, MAX_PACKETS_STATIC> psramPool;
|
||||||
@ -51,6 +51,9 @@ static MemoryDynamic<meshtastic_MeshPacket> fallbackPool;
|
|||||||
Allocator<meshtastic_MeshPacket> &packetPool = psramPool.isValid()
|
Allocator<meshtastic_MeshPacket> &packetPool = psramPool.isValid()
|
||||||
? static_cast<Allocator<meshtastic_MeshPacket> &>(psramPool)
|
? static_cast<Allocator<meshtastic_MeshPacket> &>(psramPool)
|
||||||
: static_cast<Allocator<meshtastic_MeshPacket> &>(fallbackPool);
|
: static_cast<Allocator<meshtastic_MeshPacket> &>(fallbackPool);
|
||||||
|
#elif defined(CONFIG_IDF_TARGET_ESP32S3)
|
||||||
|
static MemoryPool<meshtastic_MeshPacket, MAX_PACKETS_STATIC> staticPool;
|
||||||
|
Allocator<meshtastic_MeshPacket> &packetPool = staticPool;
|
||||||
#else
|
#else
|
||||||
static MemoryPool<meshtastic_MeshPacket, MAX_PACKETS_STATIC> staticPool;
|
static MemoryPool<meshtastic_MeshPacket, MAX_PACKETS_STATIC> staticPool;
|
||||||
Allocator<meshtastic_MeshPacket> &packetPool = staticPool;
|
Allocator<meshtastic_MeshPacket> &packetPool = staticPool;
|
||||||
@ -66,14 +69,6 @@ static uint8_t bytes[MAX_LORA_PAYLOAD_LEN + 1] __attribute__((__aligned__));
|
|||||||
*/
|
*/
|
||||||
Router::Router() : concurrency::OSThread("Router"), fromRadioQueue(MAX_RX_FROMRADIO)
|
Router::Router() : concurrency::OSThread("Router"), fromRadioQueue(MAX_RX_FROMRADIO)
|
||||||
{
|
{
|
||||||
#if defined(CONFIG_IDF_TARGET_ESP32S3)
|
|
||||||
if (!psramPool.isValid()) {
|
|
||||||
LOG_WARN("PSRAM packet pool unavailable, falling back to heap allocations");
|
|
||||||
}
|
|
||||||
if (!has_psram() && MAX_RX_TOPHONE > get_rx_tophone_limit()) {
|
|
||||||
LOG_WARN("Detected <2MB PSRAM, limiting phone queue to %d packets", get_rx_tophone_limit());
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
// This is called pre main(), don't touch anything here, the following code is not safe
|
// This is called pre main(), don't touch anything here, the following code is not safe
|
||||||
|
|
||||||
/* LOG_DEBUG("Size of NodeInfo %d", sizeof(NodeInfo));
|
/* LOG_DEBUG("Size of NodeInfo %d", sizeof(NodeInfo));
|
||||||
|
|||||||
@ -32,7 +32,13 @@ inline bool has_psram(size_t minimumBytes = PSRAM_LARGE_THRESHOLD_BYTES)
|
|||||||
inline int get_rx_tophone_limit()
|
inline int get_rx_tophone_limit()
|
||||||
{
|
{
|
||||||
#if defined(CONFIG_IDF_TARGET_ESP32S3)
|
#if defined(CONFIG_IDF_TARGET_ESP32S3)
|
||||||
return has_psram() ? 400 : 32;
|
#if defined(BOARD_MAX_RX_TOPHONE)
|
||||||
|
return BOARD_MAX_RX_TOPHONE;
|
||||||
|
#elif defined(BOARD_HAS_PSRAM)
|
||||||
|
return 800;
|
||||||
|
#else
|
||||||
|
return 32;
|
||||||
|
#endif
|
||||||
#elif defined(ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
#elif defined(ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||||
return 8;
|
return 8;
|
||||||
#else
|
#else
|
||||||
@ -45,8 +51,14 @@ inline int get_rx_tophone_limit()
|
|||||||
// RAM #define MAX_RX_TOPHONE (member_size(DeviceState, receive_queue) / member_size(DeviceState, receive_queue[0]))
|
// RAM #define MAX_RX_TOPHONE (member_size(DeviceState, receive_queue) / member_size(DeviceState, receive_queue[0]))
|
||||||
#ifndef MAX_RX_TOPHONE
|
#ifndef MAX_RX_TOPHONE
|
||||||
#if defined(CONFIG_IDF_TARGET_ESP32S3)
|
#if defined(CONFIG_IDF_TARGET_ESP32S3)
|
||||||
|
#if defined(BOARD_MAX_RX_TOPHONE)
|
||||||
|
#define MAX_RX_TOPHONE BOARD_MAX_RX_TOPHONE
|
||||||
|
#elif defined(BOARD_HAS_PSRAM)
|
||||||
static constexpr int MAX_RX_TOPHONE_WITH_PSRAM = 800;
|
static constexpr int MAX_RX_TOPHONE_WITH_PSRAM = 800;
|
||||||
#define MAX_RX_TOPHONE MAX_RX_TOPHONE_WITH_PSRAM
|
#define MAX_RX_TOPHONE MAX_RX_TOPHONE_WITH_PSRAM
|
||||||
|
#else
|
||||||
|
#define MAX_RX_TOPHONE 32
|
||||||
|
#endif
|
||||||
#elif defined(ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
#elif defined(ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||||
#define MAX_RX_TOPHONE 8
|
#define MAX_RX_TOPHONE 8
|
||||||
#else
|
#else
|
||||||
@ -80,13 +92,14 @@ static_assert(sizeof(meshtastic_NodeInfoLite) <= 200, "NodeInfoLite size increas
|
|||||||
#elif defined(ARCH_NRF52)
|
#elif defined(ARCH_NRF52)
|
||||||
#define MAX_NUM_NODES 80
|
#define MAX_NUM_NODES 80
|
||||||
#elif defined(CONFIG_IDF_TARGET_ESP32S3)
|
#elif defined(CONFIG_IDF_TARGET_ESP32S3)
|
||||||
|
#if defined(BOARD_MAX_NUM_NODES)
|
||||||
|
#define MAX_NUM_NODES BOARD_MAX_NUM_NODES
|
||||||
|
#elif defined(BOARD_HAS_PSRAM)
|
||||||
|
#define MAX_NUM_NODES 3000
|
||||||
|
#else
|
||||||
#include "Esp.h"
|
#include "Esp.h"
|
||||||
static inline int get_max_num_nodes()
|
static inline int get_max_num_nodes()
|
||||||
{
|
{
|
||||||
if (has_psram()) {
|
|
||||||
return 5000;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t flash_size = ESP.getFlashChipSize() / (1024 * 1024); // Fallback based on flash size
|
uint32_t flash_size = ESP.getFlashChipSize() / (1024 * 1024); // Fallback based on flash size
|
||||||
if (flash_size >= 15) {
|
if (flash_size >= 15) {
|
||||||
return 250;
|
return 250;
|
||||||
@ -96,6 +109,7 @@ static inline int get_max_num_nodes()
|
|||||||
return 100;
|
return 100;
|
||||||
}
|
}
|
||||||
#define MAX_NUM_NODES get_max_num_nodes()
|
#define MAX_NUM_NODES get_max_num_nodes()
|
||||||
|
#endif
|
||||||
#else
|
#else
|
||||||
#define MAX_NUM_NODES 100
|
#define MAX_NUM_NODES 100
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user