Feature: add heap details to system info and prometheus (#595)

this change adds the values of ESP.gteMaxAllocHeap() and
ESP.getMinFreeHead() to the prometheus metrics and the system
information object. the web UI uses these values to diplay the size of
the largest free contiguous block, calculate a rough estimate for the
level of fragmentation, and the maximum usage of heap memory since boot
in absolute and relative amounts.
This commit is contained in:
Bernhard Kirchen 2024-01-05 21:46:31 +01:00 committed by GitHub
parent 3c8b8d4427
commit 377406f10c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 92 additions and 0 deletions

View File

@ -54,6 +54,14 @@ void WebApiPrometheusClass::onPrometheusMetricsGet(AsyncWebServerRequest* reques
stream->print("# TYPE opendtu_free_heap_size gauge\n");
stream->printf("opendtu_free_heap_size %zu\n", ESP.getFreeHeap());
stream->print("# HELP opendtu_biggest_heap_block Biggest free heap block\n");
stream->print("# TYPE opendtu_biggest_heap_block gauge\n");
stream->printf("opendtu_biggest_heap_block %zu\n", ESP.getMaxAllocHeap());
stream->print("# HELP opendtu_heap_min_free Minimum free memory since boot\n");
stream->print("# TYPE opendtu_heap_min_free gauge\n");
stream->printf("opendtu_heap_min_free %zu\n", ESP.getMinFreeHeap());
stream->print("# HELP wifi_rssi WiFi RSSI\n");
stream->print("# TYPE wifi_rssi gauge\n");
stream->printf("wifi_rssi %d\n", WiFi.RSSI());

View File

@ -49,6 +49,8 @@ void WebApiSysstatusClass::onSystemStatus(AsyncWebServerRequest* request)
root["heap_total"] = ESP.getHeapSize();
root["heap_used"] = ESP.getHeapSize() - ESP.getFreeHeap();
root["heap_max_block"] = ESP.getMaxAllocHeap();
root["heap_min_free"] = ESP.getMinFreeHeap();
root["sketch_total"] = ESP.getFreeSketchSpace();
root["sketch_used"] = ESP.getSketchSize();
root["littlefs_total"] = LittleFS.totalBytes();

View File

@ -0,0 +1,55 @@
<template>
<CardElement :text="$t('heapdetails.HeapDetails')" textVariant="text-bg-primary">
<div class="table-responsive">
<table class="table table-hover table-condensed">
<tbody>
<tr>
<th>{{ $t('heapdetails.TotalFree') }}</th>
<td>{{ $n(Math.round(getFreeHeap() / 1024), 'kilobyte') }}</td>
</tr>
<tr>
<th>{{ $t('heapdetails.LargestFreeBlock') }}</th>
<td>{{ $n(Math.round(systemStatus.heap_max_block / 1024), 'kilobyte') }}</td>
</tr>
<tr>
<th>{{ $t('heapdetails.Fragmentation') }}</th>
<td>{{ $n(getFragmentation(), 'percent') }}</td>
</tr>
<tr>
<th>{{ $t('heapdetails.MaxUsage') }}</th>
<td>{{ $n(Math.round(getMaxUsageAbs() / 1024), 'kilobyte') }} ({{ $n(getMaxUsageRel(), 'percent') }})</td>
</tr>
</tbody>
</table>
</div>
</CardElement>
</template>
<script lang="ts">
import CardElement from '@/components/CardElement.vue';
import type { SystemStatus } from '@/types/SystemStatus';
import { defineComponent, type PropType } from 'vue';
export default defineComponent({
components: {
CardElement,
},
props: {
systemStatus: { type: Object as PropType<SystemStatus>, required: true },
},
methods: {
getFreeHeap() {
return this.systemStatus.heap_total - this.systemStatus.heap_used;
},
getMaxUsageAbs() {
return this.systemStatus.heap_total - this.systemStatus.heap_min_free;
},
getMaxUsageRel() {
return this.getMaxUsageAbs() / this.systemStatus.heap_total;
},
getFragmentation() {
return 1 - (this.systemStatus.heap_max_block / this.getFreeHeap());
},
},
});
</script>

View File

@ -248,6 +248,13 @@
"LittleFs": "LittleFs",
"Sketch": "Sketch"
},
"heapdetails": {
"HeapDetails": "Detailinformationen zum Heap",
"TotalFree": "Insgesamt frei",
"LargestFreeBlock": "Größter zusammenhängender freier Block",
"MaxUsage": "Maximale Speichernutzung seit Start",
"Fragmentation": "Grad der Fragmentierung"
},
"radioinfo": {
"RadioInformation": "Funkmodulinformationen",
"Status": "{module} Status",

View File

@ -249,6 +249,13 @@
"LittleFs": "LittleFs",
"Sketch": "Sketch"
},
"heapdetails": {
"HeapDetails": "Heap Details",
"TotalFree": "Total free",
"LargestFreeBlock": "Biggest contiguous free block",
"MaxUsage": "Maximum usage since start",
"Fragmentation": "Level of fragmentation"
},
"radioinfo": {
"RadioInformation": "Radio Information",
"Status": "{module} Status",

View File

@ -248,6 +248,13 @@
"LittleFs": "LittleFs",
"Sketch": "Sketch"
},
"heapdetails": {
"HeapDetails": "Heap Details",
"TotalFree": "Total free",
"LargestFreeBlock": "Biggest contiguous free block",
"MaxUsage": "Maximum usage since start",
"Fragmentation": "Level of fragmentation"
},
"radioinfo": {
"RadioInformation": "Informations sur la radio",
"Status": "{module} Statut",

View File

@ -22,6 +22,8 @@ export interface SystemStatus {
// MemoryInfo
heap_total: number;
heap_used: number;
heap_max_block: number;
heap_min_free: number;
littlefs_total: number;
littlefs_used: number;
sketch_total: number;

View File

@ -6,6 +6,8 @@
<div class="mt-5"></div>
<MemoryInfo :systemStatus="systemDataList" />
<div class="mt-5"></div>
<HeapDetails :systemStatus="systemDataList" />
<div class="mt-5"></div>
<RadioInfo :systemStatus="systemDataList" />
<div class="mt-5"></div>
</BasePage>
@ -16,6 +18,7 @@ import BasePage from '@/components/BasePage.vue';
import FirmwareInfo from "@/components/FirmwareInfo.vue";
import HardwareInfo from "@/components/HardwareInfo.vue";
import MemoryInfo from "@/components/MemoryInfo.vue";
import HeapDetails from "@/components/HeapDetails.vue";
import RadioInfo from "@/components/RadioInfo.vue";
import type { SystemStatus } from '@/types/SystemStatus';
import { authHeader, handleResponse } from '@/utils/authentication';
@ -27,6 +30,7 @@ export default defineComponent({
FirmwareInfo,
HardwareInfo,
MemoryInfo,
HeapDetails,
RadioInfo,
},
data() {