1
0
mirror of https://github.com/esphome/esphome.git synced 2025-09-23 05:32:22 +01:00

[esp32] Optimize NVS preferences memory usage by replacing vector with unique_ptr (#10729)

This commit is contained in:
J. Nick Koston
2025-09-18 05:24:50 -05:00
committed by GitHub
parent 37d526f003
commit 6781da45cb

View File

@@ -17,7 +17,14 @@ static const char *const TAG = "esp32.preferences";
struct NVSData { struct NVSData {
std::string key; std::string key;
std::vector<uint8_t> data; std::unique_ptr<uint8_t[]> data;
size_t len;
void set_data(const uint8_t *src, size_t size) {
data = std::make_unique<uint8_t[]>(size);
memcpy(data.get(), src, size);
len = size;
}
}; };
static std::vector<NVSData> s_pending_save; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) static std::vector<NVSData> s_pending_save; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
@@ -30,26 +37,26 @@ class ESP32PreferenceBackend : public ESPPreferenceBackend {
// try find in pending saves and update that // try find in pending saves and update that
for (auto &obj : s_pending_save) { for (auto &obj : s_pending_save) {
if (obj.key == key) { if (obj.key == key) {
obj.data.assign(data, data + len); obj.set_data(data, len);
return true; return true;
} }
} }
NVSData save{}; NVSData save{};
save.key = key; save.key = key;
save.data.assign(data, data + len); save.set_data(data, len);
s_pending_save.emplace_back(save); s_pending_save.emplace_back(std::move(save));
ESP_LOGVV(TAG, "s_pending_save: key: %s, len: %d", key.c_str(), len); ESP_LOGVV(TAG, "s_pending_save: key: %s, len: %zu", key.c_str(), len);
return true; return true;
} }
bool load(uint8_t *data, size_t len) override { bool load(uint8_t *data, size_t len) override {
// try find in pending saves and load from that // try find in pending saves and load from that
for (auto &obj : s_pending_save) { for (auto &obj : s_pending_save) {
if (obj.key == key) { if (obj.key == key) {
if (obj.data.size() != len) { if (obj.len != len) {
// size mismatch // size mismatch
return false; return false;
} }
memcpy(data, obj.data.data(), len); memcpy(data, obj.data.get(), len);
return true; return true;
} }
} }
@@ -61,7 +68,7 @@ class ESP32PreferenceBackend : public ESPPreferenceBackend {
return false; return false;
} }
if (actual_len != len) { if (actual_len != len) {
ESP_LOGVV(TAG, "NVS length does not match (%u!=%u)", actual_len, len); ESP_LOGVV(TAG, "NVS length does not match (%zu!=%zu)", actual_len, len);
return false; return false;
} }
err = nvs_get_blob(nvs_handle, key.c_str(), data, &len); err = nvs_get_blob(nvs_handle, key.c_str(), data, &len);
@@ -69,7 +76,7 @@ class ESP32PreferenceBackend : public ESPPreferenceBackend {
ESP_LOGV(TAG, "nvs_get_blob('%s') failed: %s", key.c_str(), esp_err_to_name(err)); ESP_LOGV(TAG, "nvs_get_blob('%s') failed: %s", key.c_str(), esp_err_to_name(err));
return false; return false;
} else { } else {
ESP_LOGVV(TAG, "nvs_get_blob: key: %s, len: %d", key.c_str(), len); ESP_LOGVV(TAG, "nvs_get_blob: key: %s, len: %zu", key.c_str(), len);
} }
return true; return true;
} }
@@ -112,7 +119,7 @@ class ESP32Preferences : public ESPPreferences {
if (s_pending_save.empty()) if (s_pending_save.empty())
return true; return true;
ESP_LOGV(TAG, "Saving %d items...", s_pending_save.size()); ESP_LOGV(TAG, "Saving %zu items...", s_pending_save.size());
// goal try write all pending saves even if one fails // goal try write all pending saves even if one fails
int cached = 0, written = 0, failed = 0; int cached = 0, written = 0, failed = 0;
esp_err_t last_err = ESP_OK; esp_err_t last_err = ESP_OK;
@@ -123,11 +130,10 @@ class ESP32Preferences : public ESPPreferences {
const auto &save = s_pending_save[i]; const auto &save = s_pending_save[i];
ESP_LOGVV(TAG, "Checking if NVS data %s has changed", save.key.c_str()); ESP_LOGVV(TAG, "Checking if NVS data %s has changed", save.key.c_str());
if (is_changed(nvs_handle, save)) { if (is_changed(nvs_handle, save)) {
esp_err_t err = nvs_set_blob(nvs_handle, save.key.c_str(), save.data.data(), save.data.size()); esp_err_t err = nvs_set_blob(nvs_handle, save.key.c_str(), save.data.get(), save.len);
ESP_LOGV(TAG, "sync: key: %s, len: %d", save.key.c_str(), save.data.size()); ESP_LOGV(TAG, "sync: key: %s, len: %zu", save.key.c_str(), save.len);
if (err != 0) { if (err != 0) {
ESP_LOGV(TAG, "nvs_set_blob('%s', len=%u) failed: %s", save.key.c_str(), save.data.size(), ESP_LOGV(TAG, "nvs_set_blob('%s', len=%zu) failed: %s", save.key.c_str(), save.len, esp_err_to_name(err));
esp_err_to_name(err));
failed++; failed++;
last_err = err; last_err = err;
last_key = save.key; last_key = save.key;
@@ -135,7 +141,7 @@ class ESP32Preferences : public ESPPreferences {
} }
written++; written++;
} else { } else {
ESP_LOGV(TAG, "NVS data not changed skipping %s len=%u", save.key.c_str(), save.data.size()); ESP_LOGV(TAG, "NVS data not changed skipping %s len=%zu", save.key.c_str(), save.len);
cached++; cached++;
} }
s_pending_save.erase(s_pending_save.begin() + i); s_pending_save.erase(s_pending_save.begin() + i);
@@ -164,7 +170,7 @@ class ESP32Preferences : public ESPPreferences {
return true; return true;
} }
// Check size first before allocating memory // Check size first before allocating memory
if (actual_len != to_save.data.size()) { if (actual_len != to_save.len) {
return true; return true;
} }
auto stored_data = std::make_unique<uint8_t[]>(actual_len); auto stored_data = std::make_unique<uint8_t[]>(actual_len);
@@ -173,7 +179,7 @@ class ESP32Preferences : public ESPPreferences {
ESP_LOGV(TAG, "nvs_get_blob('%s') failed: %s", to_save.key.c_str(), esp_err_to_name(err)); ESP_LOGV(TAG, "nvs_get_blob('%s') failed: %s", to_save.key.c_str(), esp_err_to_name(err));
return true; return true;
} }
return memcmp(to_save.data.data(), stored_data.get(), to_save.data.size()) != 0; return memcmp(to_save.data.get(), stored_data.get(), to_save.len) != 0;
} }
bool reset() override { bool reset() override {