mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2026-07-30 10:32:56 +00:00
large jsondocs in PSRAM
This commit is contained in:
106
src/core/psram_json_allocator.h
Normal file
106
src/core/psram_json_allocator.h
Normal file
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* EMS-ESP - https://github.com/emsesp/EMS-ESP
|
||||
* Copyright 2020-2025 emsesp.org
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef EMSESP_PSRAM_JSON_ALLOCATOR_H
|
||||
#define EMSESP_PSRAM_JSON_ALLOCATOR_H
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
#ifndef EMSESP_STANDALONE
|
||||
#include <esp_heap_caps.h>
|
||||
#endif
|
||||
|
||||
namespace emsesp {
|
||||
|
||||
// PSRAM-backed ArduinoJson allocator with internal-heap fallback.
|
||||
//
|
||||
// Rationale: by default ArduinoJson allocates with malloc(), which on the
|
||||
// ESP32 lands in internal DRAM. Large transient JsonDocuments (full MQTT
|
||||
// payload, HA discovery configs, Web API responses, settings load/save)
|
||||
// were eating multiple KB of the same internal heap that LwIP, mbedTLS and
|
||||
// AsyncTCP also need. Routing them through SPIRAM via heap_caps_malloc
|
||||
// keeps internal heap available for the network stack, at the cost of a
|
||||
// small latency penalty on PSRAM reads/writes (a few cycles per access,
|
||||
// negligible for JSON build-up which is dominated by string formatting).
|
||||
//
|
||||
// On the standalone (Linux) build, PSRAM doesn't exist; the allocator
|
||||
// silently falls through to plain malloc/free/realloc.
|
||||
//
|
||||
// Usage:
|
||||
// JsonDocument doc(emsesp::PsramJsonAllocator::instance());
|
||||
// or with the convenience macro:
|
||||
// JsonDocument doc(PSRAM_DOC);
|
||||
class PsramJsonAllocator : public ArduinoJson::Allocator {
|
||||
public:
|
||||
void * allocate(size_t size) override {
|
||||
#ifdef EMSESP_STANDALONE
|
||||
return malloc(size);
|
||||
#else
|
||||
// Try SPIRAM first; fall back to internal heap so we never fail
|
||||
// on boards without PSRAM or when PSRAM is full.
|
||||
void * p = heap_caps_malloc(size, MALLOC_CAP_SPIRAM);
|
||||
if (p == nullptr) {
|
||||
p = malloc(size);
|
||||
}
|
||||
return p;
|
||||
#endif
|
||||
}
|
||||
|
||||
void deallocate(void * ptr) override {
|
||||
#ifdef EMSESP_STANDALONE
|
||||
free(ptr);
|
||||
#else
|
||||
// heap_caps_free handles both PSRAM- and internal-heap pointers.
|
||||
heap_caps_free(ptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
void * reallocate(void * ptr, size_t new_size) override {
|
||||
#ifdef EMSESP_STANDALONE
|
||||
return realloc(ptr, new_size);
|
||||
#else
|
||||
// Prefer keeping the block in PSRAM; heap_caps_realloc will move
|
||||
// the data if the original region can't be grown in-place.
|
||||
void * p = heap_caps_realloc(ptr, new_size, MALLOC_CAP_SPIRAM);
|
||||
if (p == nullptr) {
|
||||
p = realloc(ptr, new_size);
|
||||
}
|
||||
return p;
|
||||
#endif
|
||||
}
|
||||
|
||||
static ArduinoJson::Allocator * instance() {
|
||||
static PsramJsonAllocator inst;
|
||||
return &inst;
|
||||
}
|
||||
|
||||
private:
|
||||
PsramJsonAllocator() = default;
|
||||
~PsramJsonAllocator() = default;
|
||||
};
|
||||
|
||||
} // namespace emsesp
|
||||
|
||||
// Convenience shorthand. Use only for *large* or *transient* JsonDocuments
|
||||
// (MQTT publish payloads, HA discovery, full API responses, big settings
|
||||
// load/save). For small hot-path docs (single-command output, parse of a
|
||||
// short HTTP body), keep the default allocator: PSRAM has higher access
|
||||
// latency than internal SRAM, so tiny docs are faster on the regular heap.
|
||||
#define PSRAM_DOC emsesp::PsramJsonAllocator::instance()
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user