mirror of
				https://github.com/meshtastic/firmware.git
				synced 2025-10-28 23:34:03 +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__) | ||||
| #else | ||||
| #if defined(DEBUG_PORT) && !defined(DEBUG_MUTE) | ||||
| #define LOG_DEBUG(...) DEBUG_PORT.log(MESHTASTIC_LOG_LEVEL_DEBUG, __VA_ARGS__) | ||||
| #define LOG_INFO(...) DEBUG_PORT.log(MESHTASTIC_LOG_LEVEL_INFO, __VA_ARGS__) | ||||
| #define LOG_WARN(...) DEBUG_PORT.log(MESHTASTIC_LOG_LEVEL_WARN, __VA_ARGS__) | ||||
| #define LOG_ERROR(...) DEBUG_PORT.log(MESHTASTIC_LOG_LEVEL_ERROR, __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__) | ||||
| #define LOG_DEBUG(...)                                                                                                           \ | ||||
|     do {                                                                                                                         \ | ||||
|         if (console) {                                                                                                           \ | ||||
|             console->log(MESHTASTIC_LOG_LEVEL_DEBUG, __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 | ||||
| #define LOG_DEBUG(...) | ||||
| #define LOG_INFO(...) | ||||
| @ -70,7 +100,12 @@ extern MemGet memGet; | ||||
| #endif | ||||
| 
 | ||||
| #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
 | ||||
| #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)); | ||||
| } | ||||
| #ifndef PIO_UNIT_TESTING | ||||
| #if !defined(PIO_UNIT_TESTING) || !(PIO_UNIT_TESTING) | ||||
| void setup() | ||||
| { | ||||
| 
 | ||||
| @ -1580,7 +1580,7 @@ void scannerToSensorsMap(const std::unique_ptr<ScanI2CTwoWire> &i2cScanner, Scan | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| #ifndef PIO_UNIT_TESTING | ||||
| #if !defined(PIO_UNIT_TESTING) || !(PIO_UNIT_TESTING) | ||||
| void loop() | ||||
| { | ||||
|     runASAP = false; | ||||
|  | ||||
| @ -38,6 +38,12 @@ | ||||
| #include <Preferences.h> | ||||
| #include <esp_efuse.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 <soc/efuse_reg.h> | ||||
| #include <soc/soc.h> | ||||
| @ -68,19 +74,60 @@ meshtastic_DeviceUIConfig uiconfig{.screen_brightness = 153, .screen_timeout = 3 | ||||
| meshtastic_LocalModuleConfig moduleConfig; | ||||
| meshtastic_ChannelFile channelFile; | ||||
| 
 | ||||
| #if defined(CONFIG_IDF_TARGET_ESP32S3) | ||||
| //------------------------------------------------------------------------------
 | ||||
| // Runtime instrumentation helpers
 | ||||
| //------------------------------------------------------------------------------
 | ||||
| 
 | ||||
| // Hot/cold storage helpers -------------------------------------------------
 | ||||
| // 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.
 | ||||
| namespace | ||||
| { | ||||
| 
 | ||||
| // 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() | ||||
| { | ||||
|     // 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); | ||||
|     hotNodes.resize(MAX_NUM_NODES); | ||||
|     hotDirty.assign(MAX_NUM_NODES, true); | ||||
|     meshNodes = &psramMeshNodes; | ||||
|     logPsramAllocationOnce(psramMeshNodes.data(), psramMeshNodes.capacity()); | ||||
| } | ||||
| 
 | ||||
| void NodeDB::refreshHotCache() | ||||
| @ -2263,6 +2310,7 @@ meshtastic_NodeInfoLite *NodeDB::getOrCreateMeshNode(NodeNum n) | ||||
|         syncHotFromCold(index); | ||||
|         lite = &psramMeshNodes[index]; | ||||
|         LOG_INFO("Adding node to database with %i nodes and %u bytes free!", numMeshNodes, memGet.getFreeHeap()); | ||||
|         logNodeInsertStats(numMeshNodes, "PSRAM"); | ||||
|     } | ||||
| 
 | ||||
|     markHotDirty(lite); | ||||
| @ -2314,6 +2362,7 @@ meshtastic_NodeInfoLite *NodeDB::getOrCreateMeshNode(NodeNum n) | ||||
|         memset(lite, 0, sizeof(*lite)); | ||||
|         lite->num = n; | ||||
|         LOG_INFO("Adding node to database with %i nodes and %u bytes free!", numMeshNodes, memGet.getFreeHeap()); | ||||
|         logNodeInsertStats(numMeshNodes, "Heap"); | ||||
|     } | ||||
| 
 | ||||
|     return lite; | ||||
|  | ||||
| @ -43,7 +43,7 @@ Allocator<meshtastic_MeshPacket> &packetPool = dynamicPool; | ||||
|     (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)
 | ||||
| 
 | ||||
| #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
 | ||||
| // heap allocation so the radio stays functional (at the cost of fewer packets).
 | ||||
| static PsramMemoryPool<meshtastic_MeshPacket, MAX_PACKETS_STATIC> psramPool; | ||||
| @ -51,6 +51,9 @@ static MemoryDynamic<meshtastic_MeshPacket> fallbackPool; | ||||
| Allocator<meshtastic_MeshPacket> &packetPool = psramPool.isValid() | ||||
|                                                    ? static_cast<Allocator<meshtastic_MeshPacket> &>(psramPool) | ||||
|                                                    : 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 | ||||
| static MemoryPool<meshtastic_MeshPacket, MAX_PACKETS_STATIC> 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) | ||||
| { | ||||
| #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
 | ||||
| 
 | ||||
|     /* 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() | ||||
| { | ||||
| #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) | ||||
|     return 8; | ||||
| #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]))
 | ||||
| #ifndef MAX_RX_TOPHONE | ||||
| #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; | ||||
| #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) | ||||
| #define MAX_RX_TOPHONE 8 | ||||
| #else | ||||
| @ -80,13 +92,14 @@ static_assert(sizeof(meshtastic_NodeInfoLite) <= 200, "NodeInfoLite size increas | ||||
| #elif defined(ARCH_NRF52) | ||||
| #define MAX_NUM_NODES 80 | ||||
| #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" | ||||
| 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
 | ||||
|     if (flash_size >= 15) { | ||||
|         return 250; | ||||
| @ -96,6 +109,7 @@ static inline int get_max_num_nodes() | ||||
|     return 100; | ||||
| } | ||||
| #define MAX_NUM_NODES get_max_num_nodes() | ||||
| #endif | ||||
| #else | ||||
| #define MAX_NUM_NODES 100 | ||||
| #endif | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Clive Blackledge
						Clive Blackledge