Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions src/DebugConfiguration.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#define MESHTASTIC_LOG_LEVEL_ERROR "ERROR"
#define MESHTASTIC_LOG_LEVEL_CRIT "CRIT "
#define MESHTASTIC_LOG_LEVEL_TRACE "TRACE"
#define MESHTASTIC_LOG_LEVEL_HEAP "HEAP"

#include "SerialConsole.h"

Expand Down Expand Up @@ -62,6 +63,12 @@
#endif
#endif

#if defined(DEBUG_HEAP)
#define LOG_HEAP(...) DEBUG_PORT.log(MESHTASTIC_LOG_LEVEL_HEAP, __VA_ARGS__)
#else
#define LOG_HEAP(...)
#endif

/// A C wrapper for LOG_DEBUG that can be used from arduino C libs that don't know about C++ or meshtastic
extern "C" void logLegacy(const char *level, const char *fmt, ...);

Expand Down
6 changes: 3 additions & 3 deletions src/Power.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -851,9 +851,9 @@ void Power::readPowerStatus()
running++;
}
}
LOG_DEBUG(threadlist);
LOG_DEBUG("Heap status: %d/%d bytes free (%d), running %d/%d threads", memGet.getFreeHeap(), memGet.getHeapSize(),
memGet.getFreeHeap() - lastheap, running, concurrency::mainController.size(false));
LOG_HEAP(threadlist);
LOG_HEAP("Heap status: %d/%d bytes free (%d), running %d/%d threads", memGet.getFreeHeap(), memGet.getHeapSize(),
memGet.getFreeHeap() - lastheap, running, concurrency::mainController.size(false));
lastheap = memGet.getFreeHeap();
}
#ifdef DEBUG_HEAP_MQTT
Expand Down
4 changes: 2 additions & 2 deletions src/concurrency/OSThread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,9 @@ void OSThread::run()
#ifdef DEBUG_HEAP
auto newHeap = memGet.getFreeHeap();
if (newHeap < heap)
LOG_DEBUG("------ Thread %s leaked heap %d -> %d (%d) ------", ThreadName.c_str(), heap, newHeap, newHeap - heap);
LOG_HEAP("------ Thread %s leaked heap %d -> %d (%d) ------", ThreadName.c_str(), heap, newHeap, newHeap - heap);
if (heap < newHeap)
LOG_DEBUG("++++++ Thread %s freed heap %d -> %d (%d) ++++++", ThreadName.c_str(), heap, newHeap, newHeap - heap);
LOG_HEAP("++++++ Thread %s freed heap %d -> %d (%d) ++++++", ThreadName.c_str(), heap, newHeap, newHeap - heap);
#endif

runned();
Expand Down
2 changes: 2 additions & 0 deletions src/mesh/MemoryPool.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ template <class T> class MemoryDynamic : public Allocator<T>
virtual void release(T *p) override
{
assert(p);
LOG_HEAP("Freeing 0x%x", p);

free(p);
}

Expand Down
13 changes: 11 additions & 2 deletions src/mesh/MeshService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -193,8 +193,12 @@ void MeshService::handleToRadio(meshtastic_MeshPacket &p)
// (so we update our nodedb for the local node)

// Send the packet into the mesh
auto heapBefore = memGet.getFreeHeap();

@mverch67 mverch67 Sep 10, 2025

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should go into a #ifdef DEBUG_HEAP as these look like costly operations. Not sure if the compiler will optimize these away when not used (they are not declared const).

@mverch67 mverch67 Sep 10, 2025

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also saw crashes on esp32 when I used these in MUI periodically. So I switched the heap icon off by default.

auto a = packetPool.allocCopy(p);
auto heapAfter = memGet.getFreeHeap();
LOG_HEAP("Alloc in MeshService::handleToRadio() pointer 0x%x, size: %u, free: %u", a, heapBefore - heapAfter, heapAfter);

sendToMesh(packetPool.allocCopy(p), RX_SRC_USER);
sendToMesh(a, RX_SRC_USER);

bool loopback = false; // if true send any packet the phone sends back itself (for testing)
if (loopback) {
Expand Down Expand Up @@ -250,7 +254,12 @@ void MeshService::sendToMesh(meshtastic_MeshPacket *p, RxSource src, bool ccToPh
}

if ((res == ERRNO_OK || res == ERRNO_SHOULD_RELEASE) && ccToPhone) { // Check if p is not released in case it couldn't be sent
sendToPhone(packetPool.allocCopy(*p));
auto heapBefore = memGet.getFreeHeap();
auto a = packetPool.allocCopy(*p);
auto heapAfter = memGet.getFreeHeap();
LOG_HEAP("Alloc in MeshService::sendToMesh() pointer 0x%x, size: %u, free: %u", a, heapBefore - heapAfter, heapAfter);

sendToPhone(a);
}

// Router may ask us to release the packet if it wasn't sent
Expand Down
6 changes: 5 additions & 1 deletion src/mesh/ReliableRouter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include "Default.h"
#include "MeshTypes.h"
#include "configuration.h"
#include "memGet.h"
#include "mesh-pb-constants.h"
#include "modules/NodeInfoModule.h"
#include "modules/RoutingModule.h"
Expand All @@ -21,8 +22,11 @@ ErrorCode ReliableRouter::send(meshtastic_MeshPacket *p)
if (p->hop_limit == 0) {
p->hop_limit = Default::getConfiguredOrDefaultHopLimit(config.lora.hop_limit);
}

auto heapBefore = memGet.getFreeHeap();
auto copy = packetPool.allocCopy(*p);
auto heapAfter = memGet.getFreeHeap();
LOG_HEAP("Alloc in ReliableRouter::send() pointer 0x%x, size: %u, free: %u", copy, heapBefore - heapAfter, heapAfter);

startRetransmission(copy, NUM_RELIABLE_RETX);
}

Expand Down
8 changes: 8 additions & 0 deletions src/mesh/Router.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,12 @@ ErrorCode Router::send(meshtastic_MeshPacket *p)
// If the packet is not yet encrypted, do so now
if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) {
ChannelIndex chIndex = p->channel; // keep as a local because we are about to change it

auto heapBefore = memGet.getFreeHeap();
meshtastic_MeshPacket *p_decoded = packetPool.allocCopy(*p);
auto heapAfter = memGet.getFreeHeap();

LOG_HEAP("Alloc in Router::send pointer 0x%x, size: %u, free: %u", p_decoded, heapBefore - heapAfter, heapAfter);

auto encodeResult = perhapsEncode(p);
if (encodeResult != meshtastic_Routing_Error_NONE) {
Expand Down Expand Up @@ -608,7 +613,10 @@ void Router::handleReceived(meshtastic_MeshPacket *p, RxSource src)
// Also, we should set the time from the ISR and it should have msec level resolution
p->rx_time = getValidTime(RTCQualityFromNet); // store the arrival timestamp for the phone
// Store a copy of encrypted packet for MQTT
auto heapBefore = memGet.getFreeHeap();
meshtastic_MeshPacket *p_encrypted = packetPool.allocCopy(*p);
auto heapAfter = memGet.getFreeHeap();
LOG_HEAP("Alloc in Router::handleReceived pointer 0x%x, size: %u, free: %u", p_encrypted, heapBefore - heapAfter, heapAfter);

// Take those raw bytes and convert them back into a well structured protobuf we can understand
auto decodedState = perhapsDecode(p);
Expand Down
4 changes: 4 additions & 0 deletions src/modules/NodeInfoModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,11 @@ void NodeInfoModule::sendOurNodeInfo(NodeNum dest, bool wantReplies, uint8_t cha
if (prevPacketId) // if we wrap around to zero, we'll simply fail to cancel in that rare case (no big deal)
service->cancelSending(prevPacketId);
shorterTimeout = _shorterTimeout;
auto heapBefore = memGet.getFreeHeap();
meshtastic_MeshPacket *p = allocReply();
auto heapAfter = memGet.getFreeHeap();

LOG_HEAP("Alloc in NodeInfoModule::sendOurNodeInfo pointer 0x%x, size: %u, free: %u", p, heapBefore - heapAfter, heapAfter);
if (p) { // Check whether we didn't ignore it
p->to = dest;
p->decoded.want_response = (config.device.role != meshtastic_Config_DeviceConfig_Role_TRACKER &&
Expand Down
5 changes: 5 additions & 0 deletions src/modules/Telemetry/DeviceTelemetry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,12 @@ bool DeviceTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly)
telemetry.variant.device_metrics.battery_level, telemetry.variant.device_metrics.voltage,
telemetry.variant.device_metrics.uptime_seconds);

auto heapBefore = memGet.getFreeHeap();
meshtastic_MeshPacket *p = allocDataProtobuf(telemetry);
auto heapAfter = memGet.getFreeHeap();
LOG_HEAP("Alloc in DeviceTelemetryModule::sendTelemetry() pointer 0x%x, size: %u, free: %u", p, heapBefore - heapAfter,
heapAfter);

p->to = dest;
p->decoded.want_response = false;
p->priority = meshtastic_MeshPacket_Priority_BACKGROUND;
Expand Down
Loading