A fork of https://github.com/crosspoint-reader/crosspoint-reader
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: Add maxAlloc to memory information (#1152)

## Summary

* **What is the goal of this PR?** During debugging of #1092 i
desperately needed to monitor the biggest allocatable block of memory on
the heap
* **What changes are included?** Added informaqtion to debug output,
amended monitor utility to pick it up

## Additional Context

---

---

### AI Usage

While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.

Did you use AI tools to help write this code? _**NO**_

authored by

jpirnay and committed by
GitHub
7d97687a d6d0cc86

+42 -38
+40 -36
scripts/debugging_monitor.py
··· 78 78 time_data: deque[str] = deque(maxlen=MAX_POINTS) 79 79 free_mem_data: deque[float] = deque(maxlen=MAX_POINTS) 80 80 total_mem_data: deque[float] = deque(maxlen=MAX_POINTS) 81 + max_alloc_data: deque[float] = deque(maxlen=MAX_POINTS) 81 82 data_lock: threading.Lock = threading.Lock() # Prevent reading while writing 82 83 83 84 # Global shutdown flag ··· 172 173 return Fore.WHITE 173 174 174 175 175 - def parse_memory_line(line: str) -> tuple[int | None, int | None]: 176 + def parse_memory_line(line: str) -> tuple[int | None, int | None, int | None]: 176 177 """ 177 - Extracts Free and Total bytes from the specific log line. 178 - Format: [MEM] Free: 196344 bytes, Total: 226412 bytes, Min Free: 112620 bytes 178 + Extracts memory stats from MEM log lines. 179 + Format: Free: N bytes, Total: N bytes, Min Free: N bytes, MaxAlloc: N bytes 180 + Returns: (free_bytes, total_bytes, max_alloc_bytes) 179 181 """ 180 - # Regex to find 'Free: <digits>' and 'Total: <digits>' 181 - match = re.search(r"Free:\s*(\d+).*Total:\s*(\d+)", line) 182 - if match: 183 - try: 184 - free_bytes = int(match.group(1)) 185 - total_bytes = int(match.group(2)) 186 - return free_bytes, total_bytes 187 - except ValueError: 188 - return None, None 189 - return None, None 182 + def _find(pattern: str) -> int | None: 183 + m = re.search(pattern, line) 184 + if m: 185 + try: 186 + return int(m.group(1)) 187 + except ValueError: 188 + pass 189 + return None 190 + 191 + return ( 192 + _find(r"\bFree:\s*(\d+)"), 193 + _find(r"\bTotal:\s*(\d+)"), 194 + _find(r"\bMaxAlloc:\s*(\d+)"), 195 + ) 190 196 191 197 192 198 def serial_worker(ser, kwargs: dict[str, str]) -> None: ··· 265 271 266 272 # Check for Memory Line 267 273 if "[MEM]" in formatted_line: 268 - free_val, total_val = parse_memory_line(formatted_line) 274 + free_val, total_val, max_alloc_val = parse_memory_line(formatted_line) 269 275 if free_val is not None and total_val is not None: 270 276 with data_lock: 271 277 time_data.append(pc_time) 272 - free_mem_data.append(free_val / 1024) # Convert to KB 273 - total_mem_data.append(total_val / 1024) # Convert to KB 278 + free_mem_data.append(free_val / 1024) 279 + total_mem_data.append(total_val / 1024) 280 + max_alloc_data.append((max_alloc_val or 0) / 1024) 274 281 # Apply filters 275 282 if filter_keyword and filter_keyword not in formatted_line.lower(): 276 283 continue ··· 309 316 """ 310 317 Called by Matplotlib animation to redraw the memory usage chart. 311 318 Monitors the global shutdown event and closes the plot when shutdown is requested. 319 + Shows DRAM metrics (free, total, max contiguous alloc) and an optional PSRAM subplot. 312 320 """ 313 321 if shutdown_event.is_set(): 314 322 plt.close("all") ··· 318 326 if not time_data: 319 327 return [] 320 328 321 - # Convert deques to lists for plotting 322 329 x = list(time_data) 323 330 y_free = list(free_mem_data) 324 331 y_total = list(total_mem_data) 332 + y_max_alloc = list(max_alloc_data) 325 333 326 - plt.cla() # Clear axis 334 + fig = plt.gcf() 335 + fig.clf() 336 + ax1 = fig.add_subplot(111) 327 337 328 - # Plot Total RAM 329 - plt.plot(x, y_total, label="Total RAM (KB)", color="red", linestyle="--") 338 + ax1.plot(x, y_total, label="Total RAM (KB)", color="red", linestyle="--") 339 + ax1.plot(x, y_free, label="Free RAM (KB)", color="green", marker="o", markersize=3) 340 + if any(v > 0 for v in y_max_alloc): 341 + ax1.plot(x, y_max_alloc, label="Max Alloc (KB)", color="orange", linestyle="-.") 342 + ax1.fill_between(x, y_free, color="green", alpha=0.1) 343 + ax1.set_title("ESP32 Memory Monitor") 344 + ax1.set_ylabel("Memory (KB)") 345 + ax1.set_xlabel("Time") 346 + ax1.legend(loc="upper left") 347 + ax1.grid(True, linestyle=":", alpha=0.6) 348 + plt.setp(ax1.get_xticklabels(), rotation=45, ha="right") 330 349 331 - # Plot Free RAM 332 - plt.plot(x, y_free, label="Free RAM (KB)", color="green", marker="o") 333 - 334 - # Fill area under Free RAM 335 - plt.fill_between(x, y_free, color="green", alpha=0.1) 336 - 337 - plt.title("ESP32 Memory Monitor") 338 - plt.ylabel("Memory (KB)") 339 - plt.xlabel("Time") 340 - plt.legend(loc="upper left") 341 - plt.grid(True, linestyle=":", alpha=0.6) 342 - 343 - # Rotate date labels 344 - plt.xticks(rotation=45, ha="right") 345 - plt.tight_layout() 346 - 350 + fig.tight_layout() 347 351 return [] 348 352 349 353
+2 -2
src/main.cpp
··· 378 378 renderer.setFadingFix(SETTINGS.fadingFix); 379 379 380 380 if (Serial && millis() - lastMemPrint >= 10000) { 381 - LOG_INF("MEM", "Free: %d bytes, Total: %d bytes, Min Free: %d bytes", ESP.getFreeHeap(), ESP.getHeapSize(), 382 - ESP.getMinFreeHeap()); 381 + LOG_INF("MEM", "Free: %d bytes, Total: %d bytes, Min Free: %d bytes, MaxAlloc: %d bytes", ESP.getFreeHeap(), 382 + ESP.getHeapSize(), ESP.getMinFreeHeap(), ESP.getMaxAllocHeap()); 383 383 lastMemPrint = millis(); 384 384 } 385 385