-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbuffer_manager.cpp
More file actions
446 lines (362 loc) · 16 KB
/
buffer_manager.cpp
File metadata and controls
446 lines (362 loc) · 16 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
#include "buffer_manager.h"
#include <esp_heap_caps.h>
// ===== CONSTRUCTOR & DESTRUCTOR =====
BufferManager::BufferManager()
: downloadBufferSize(0), writeBufferSize(0),
activeDownloadBuffer(0), activeWriteBuffer(0),
buffersAllocated(false), doubleBufferingEnabled(false) {
// Initialize buffer arrays
for (int i = 0; i < DOUBLE_BUFFER_COUNT; i++) {
downloadBuffers[i] = nullptr;
writeBuffers[i] = nullptr;
}
}
BufferManager::~BufferManager() {
deallocateBuffers();
}
// ===== HIGH-PERFORMANCE BUFFER ALLOCATION METHODS =====
bool BufferManager::allocateBuffers() {
return allocateSmartScalingBuffers();
}
bool BufferManager::allocateSmartScalingBuffers() {
if (buffersAllocated) {
Serial.println("Buffers already allocated");
return true;
}
Serial.println("=== SMART SCALING BUFFER ALLOCATION ===");
// Calculate smart buffer sizes based on available memory
size_t smartDownloadSize = getSmartDownloadBufferSize();
size_t smartWriteSize = getSmartWriteBufferSize();
Serial.println("Smart Download Buffer: " + String(smartDownloadSize / 1024) + " KB");
Serial.println("Smart Write Buffer: " + String(smartWriteSize / 1024) + " KB");
// Try to enable double buffering if enough memory
bool doubleBuffering = canEnableDoubleBuffering();
Serial.println("Double Buffering: " + String(doubleBuffering ? "ENABLED" : "DISABLED"));
if (doubleBuffering) {
doubleBufferingEnabled = true;
}
return allocateBuffers(smartDownloadSize, smartWriteSize);
}
bool BufferManager::allocateHighPerformanceBuffers() {
if (buffersAllocated) {
deallocateBuffers();
}
Serial.println("=== HIGH-PERFORMANCE BUFFER ALLOCATION ===");
// Use maximum performance buffer sizes
size_t downloadSize = LARGE_DOWNLOAD_BUFFER_SIZE; // 128KB
size_t writeSize = LARGE_WRITE_BUFFER_SIZE; // 64KB
// Check if we can use extra large buffers
size_t freeHeap = getAvailableHeap();
if (freeHeap > 600000) { // > 600KB free
downloadSize = XLARGE_DOWNLOAD_BUFFER_SIZE; // 256KB
Serial.println("Using EXTRA LARGE buffers (256KB download)");
}
doubleBufferingEnabled = canEnableDoubleBuffering();
Serial.println("Max Performance Download Buffer: " + String(downloadSize / 1024) + " KB");
Serial.println("Max Performance Write Buffer: " + String(writeSize / 1024) + " KB");
Serial.println("Double Buffering: " + String(doubleBufferingEnabled ? "ENABLED" : "DISABLED"));
return allocateBuffers(downloadSize, writeSize);
}
bool BufferManager::allocateBuffers(size_t downloadSize, size_t writeSize) {
if (buffersAllocated) {
deallocateBuffers(); // Clean up existing buffers first
}
// Calculate total required memory (including double buffering)
size_t buffersNeeded = doubleBufferingEnabled ? DOUBLE_BUFFER_COUNT : 1;
size_t totalRequired = (downloadSize + writeSize) * buffersNeeded;
if (!hasEnoughMemory(totalRequired)) {
Serial.println("Error: Insufficient memory for buffers");
Serial.println("Required: " + String(totalRequired) + " bytes");
Serial.println("Available: " + String(getAvailableHeap()) + " bytes");
// Try to fallback to single buffering
if (doubleBufferingEnabled) {
Serial.println("Trying fallback to single buffering...");
doubleBufferingEnabled = false;
buffersNeeded = 1;
totalRequired = downloadSize + writeSize;
if (!hasEnoughMemory(totalRequired)) {
Serial.println("Error: Even single buffering requires too much memory");
return false;
}
} else {
return false;
}
}
// Allocate buffers
for (int i = 0; i < buffersNeeded; i++) {
// Allocate download buffer
downloadBuffers[i] = (uint8_t*)malloc(downloadSize);
if (!downloadBuffers[i]) {
Serial.println("Error: Failed to allocate download buffer " + String(i));
deallocateBuffers();
return false;
}
// Allocate write buffer
writeBuffers[i] = (uint8_t*)malloc(writeSize);
if (!writeBuffers[i]) {
Serial.println("Error: Failed to allocate write buffer " + String(i));
deallocateBuffers();
return false;
}
}
downloadBufferSize = downloadSize;
writeBufferSize = writeSize;
activeDownloadBuffer = 0;
activeWriteBuffer = 0;
buffersAllocated = true;
Serial.println("=== HIGH-PERFORMANCE BUFFER ALLOCATION SUCCESS ===");
Serial.println("Buffer Mode: " + String(doubleBufferingEnabled ? "DOUBLE BUFFERING" : "SINGLE BUFFERING"));
Serial.println("Download buffer: " + String(downloadBufferSize / 1024) + " KB x" + String(buffersNeeded));
Serial.println("Write buffer: " + String(writeBufferSize / 1024) + " KB x" + String(buffersNeeded));
Serial.println("Total allocated: " + String(totalRequired / 1024) + " KB");
printMemoryStatus();
Serial.println("=====================================================");
return true;
}
bool BufferManager::enableDoubleBuffering() {
if (buffersAllocated && !doubleBufferingEnabled) {
Serial.println("Cannot enable double buffering after allocation. Deallocate first.");
return false;
}
if (canEnableDoubleBuffering()) {
doubleBufferingEnabled = true;
Serial.println("Double buffering enabled");
return true;
} else {
Serial.println("Insufficient memory for double buffering");
return false;
}
}
void BufferManager::deallocateBuffers() {
for (int i = 0; i < DOUBLE_BUFFER_COUNT; i++) {
if (downloadBuffers[i]) {
free(downloadBuffers[i]);
downloadBuffers[i] = nullptr;
}
if (writeBuffers[i]) {
free(writeBuffers[i]);
writeBuffers[i] = nullptr;
}
}
downloadBufferSize = 0;
writeBufferSize = 0;
activeDownloadBuffer = 0;
activeWriteBuffer = 0;
buffersAllocated = false;
doubleBufferingEnabled = false;
Serial.println("High-performance buffers deallocated");
}
// ===== ENHANCED BUFFER ACCESS METHODS =====
uint8_t* BufferManager::getDownloadBuffer(int index) const {
if (index == -1) {
index = activeDownloadBuffer;
}
if (index < 0 || index >= DOUBLE_BUFFER_COUNT || !downloadBuffers[index]) {
return nullptr;
}
return downloadBuffers[index];
}
uint8_t* BufferManager::getWriteBuffer(int index) const {
if (index == -1) {
index = activeWriteBuffer;
}
if (index < 0 || index >= DOUBLE_BUFFER_COUNT || !writeBuffers[index]) {
return nullptr;
}
return writeBuffers[index];
}
// ===== DOUBLE BUFFERING CONTROL =====
void BufferManager::swapDownloadBuffers() {
if (doubleBufferingEnabled && buffersAllocated) {
activeDownloadBuffer = (activeDownloadBuffer + 1) % DOUBLE_BUFFER_COUNT;
Serial.println("Swapped to download buffer " + String(activeDownloadBuffer));
}
}
void BufferManager::swapWriteBuffers() {
if (doubleBufferingEnabled && buffersAllocated) {
activeWriteBuffer = (activeWriteBuffer + 1) % DOUBLE_BUFFER_COUNT;
Serial.println("Swapped to write buffer " + String(activeWriteBuffer));
}
}
// ===== MEMORY MANAGEMENT =====
bool BufferManager::hasEnoughMemory(size_t requiredBytes) const {
size_t freeHeap = getAvailableHeap();
size_t safetyBuffer = (size_t)(freeHeap * HEAP_SAFETY_MARGIN);
size_t usableMemory = freeHeap - min(safetyBuffer, MIN_FREE_HEAP_REQUIRED);
return requiredBytes <= usableMemory;
}
size_t BufferManager::calculateOptimalBufferSize() const {
size_t freeHeap = getAvailableHeap();
// Reserve safety margin
size_t safetyBuffer = max((size_t)(freeHeap * HEAP_SAFETY_MARGIN), MIN_FREE_HEAP_REQUIRED);
size_t usableMemory = freeHeap - safetyBuffer;
// Allocate 60% for download buffer, 40% for write buffer
size_t totalBufferMemory = usableMemory * 0.8; // Use 80% of usable memory for buffers
return totalBufferMemory;
}
void BufferManager::printMemoryStatus() const {
size_t freeHeap = getAvailableHeap();
size_t totalHeap = ESP.getHeapSize();
size_t minFreeHeap = ESP.getMinFreeHeap();
Serial.println("--- High-Performance Memory Status ---");
Serial.println("Total Heap: " + String(totalHeap) + " bytes");
Serial.println("Free Heap: " + String(freeHeap) + " bytes");
Serial.println("Min Free Heap: " + String(minFreeHeap) + " bytes");
Serial.println("Heap Usage: " + String(((totalHeap - freeHeap) * 100) / totalHeap) + "%");
if (buffersAllocated) {
int bufferCount = doubleBufferingEnabled ? DOUBLE_BUFFER_COUNT : 1;
Serial.println("Download Buffers: " + String(downloadBufferSize / 1024) + " KB x" + String(bufferCount));
Serial.println("Write Buffers: " + String(writeBufferSize / 1024) + " KB x" + String(bufferCount));
Serial.println("Total Buffer Memory: " + String((downloadBufferSize + writeBufferSize) * bufferCount / 1024) + " KB");
Serial.println("Buffer Mode: " + String(doubleBufferingEnabled ? "DOUBLE BUFFERING" : "SINGLE BUFFERING"));
}
Serial.println("--------------------------------------");
}
bool BufferManager::isMemorySafe() const {
size_t freeHeap = getAvailableHeap();
return freeHeap > MIN_FREE_HEAP_REQUIRED;
}
// ===== BUFFER OPERATIONS =====
void BufferManager::clearBuffers() {
for (int i = 0; i < DOUBLE_BUFFER_COUNT; i++) {
if (downloadBuffers[i] && downloadBufferSize > 0) {
memset(downloadBuffers[i], 0, downloadBufferSize);
}
if (writeBuffers[i] && writeBufferSize > 0) {
memset(writeBuffers[i], 0, writeBufferSize);
}
}
}
bool BufferManager::validateBuffers() const {
if (!buffersAllocated) {
return false;
}
// Check if at least one set of buffers is allocated
if (!downloadBuffers[0] || downloadBufferSize == 0) {
return false;
}
if (!writeBuffers[0] || writeBufferSize == 0) {
return false;
}
// If double buffering is enabled, check second buffer set
if (doubleBufferingEnabled) {
if (!downloadBuffers[1] || !writeBuffers[1]) {
return false;
}
}
return true;
}
// ===== ENHANCED STATIC UTILITY METHODS =====
size_t BufferManager::getAvailableHeap() {
return ESP.getFreeHeap();
}
size_t BufferManager::getSmartDownloadBufferSize() {
size_t freeHeap = getAvailableHeap();
// Smart scaling algorithm based on available memory
if (freeHeap > 500000) { // > 500KB free - use XLARGE
return XLARGE_DOWNLOAD_BUFFER_SIZE; // 256KB
} else if (freeHeap > 350000) { // > 350KB free - use LARGE
return LARGE_DOWNLOAD_BUFFER_SIZE; // 128KB
} else if (freeHeap > 200000) { // > 200KB free - use DEFAULT
return DEFAULT_DOWNLOAD_BUFFER_SIZE; // 64KB
} else if (freeHeap > 120000) { // > 120KB free - use SMALL
return SMALL_DOWNLOAD_BUFFER_SIZE; // 32KB
} else {
return 16384; // 16KB fallback minimum
}
}
size_t BufferManager::getSmartWriteBufferSize() {
size_t freeHeap = getAvailableHeap();
// Write buffer is typically smaller than download buffer
if (freeHeap > 500000) { // > 500KB free
return LARGE_WRITE_BUFFER_SIZE; // 64KB
} else if (freeHeap > 300000) { // > 300KB free
return DEFAULT_WRITE_BUFFER_SIZE; // 32KB
} else if (freeHeap > 150000) { // > 150KB free
return SMALL_WRITE_BUFFER_SIZE; // 16KB
} else {
return 8192; // 8KB fallback minimum
}
}
// Legacy compatibility methods
size_t BufferManager::getOptimalDownloadBufferSize() {
return getSmartDownloadBufferSize();
}
size_t BufferManager::getOptimalWriteBufferSize() {
return getSmartWriteBufferSize();
}
bool BufferManager::canEnableDoubleBuffering() {
size_t freeHeap = getAvailableHeap();
// Calculate memory needed for double buffering with smart buffer sizes
size_t downloadSize = getSmartDownloadBufferSize();
size_t writeSize = getSmartWriteBufferSize();
size_t totalForDoubleBuffering = (downloadSize + writeSize) * 2;
// Add safety margin
size_t safetyBuffer = (size_t)(freeHeap * HEAP_SAFETY_MARGIN);
size_t usableMemory = freeHeap - max(safetyBuffer, MIN_FREE_HEAP_REQUIRED);
return totalForDoubleBuffering <= usableMemory;
}
bool BufferManager::checkMemoryHealth() {
size_t freeHeap = getAvailableHeap();
size_t minFreeHeap = ESP.getMinFreeHeap();
bool healthy = true;
if (freeHeap < MIN_FREE_HEAP_REQUIRED) {
Serial.println("WARNING: Low free heap memory");
healthy = false;
}
if (minFreeHeap < (MIN_FREE_HEAP_REQUIRED / 2)) {
Serial.println("WARNING: Critically low minimum heap recorded");
healthy = false;
}
return healthy;
}
void BufferManager::printMemoryDiagnostics() {
Serial.println("=== HIGH-PERFORMANCE MEMORY DIAGNOSTICS ===");
Serial.println("ESP.getHeapSize(): " + String(ESP.getHeapSize()));
Serial.println("ESP.getFreeHeap(): " + String(ESP.getFreeHeap()));
Serial.println("ESP.getMinFreeHeap(): " + String(ESP.getMinFreeHeap()));
Serial.println("ESP.getMaxAllocHeap(): " + String(ESP.getMaxAllocHeap()));
// PSRAM info if available
if (ESP.getPsramSize() > 0) {
Serial.println("ESP.getPsramSize(): " + String(ESP.getPsramSize()));
Serial.println("ESP.getFreePsram(): " + String(ESP.getFreePsram()));
} else {
Serial.println("PSRAM: Not available");
}
Serial.println("Memory Health: " + String(checkMemoryHealth() ? "EXCELLENT" : "POOR"));
Serial.println("Double Buffering Capable: " + String(canEnableDoubleBuffering() ? "YES" : "NO"));
Serial.println("Smart Download Buffer Size: " + String(getSmartDownloadBufferSize() / 1024) + " KB");
Serial.println("Smart Write Buffer Size: " + String(getSmartWriteBufferSize() / 1024) + " KB");
Serial.println("===========================================");
}
void BufferManager::printHighPerformanceSettings() {
Serial.println("=== HIGH-PERFORMANCE BUFFER SETTINGS ===");
Serial.println("Available Buffer Sizes:");
Serial.println(" SMALL: Download=" + String(SMALL_DOWNLOAD_BUFFER_SIZE / 1024) + "KB, Write=" + String(SMALL_WRITE_BUFFER_SIZE / 1024) + "KB");
Serial.println(" DEFAULT: Download=" + String(DEFAULT_DOWNLOAD_BUFFER_SIZE / 1024) + "KB, Write=" + String(DEFAULT_WRITE_BUFFER_SIZE / 1024) + "KB");
Serial.println(" LARGE: Download=" + String(LARGE_DOWNLOAD_BUFFER_SIZE / 1024) + "KB, Write=" + String(LARGE_WRITE_BUFFER_SIZE / 1024) + "KB");
Serial.println(" XLARGE: Download=" + String(XLARGE_DOWNLOAD_BUFFER_SIZE / 1024) + "KB");
Serial.println("Double Buffering Support: ENABLED");
Serial.println("Heap Safety Margin: " + String(HEAP_SAFETY_MARGIN * 100) + "%");
Serial.println("Minimum Free Heap: " + String(MIN_FREE_HEAP_REQUIRED / 1024) + " KB");
Serial.println("==========================================");
}
// ===== C-STYLE FUNCTIONS =====
MemoryStatus getMemoryStatus() {
MemoryStatus status;
status.totalHeap = ESP.getHeapSize();
status.freeHeap = ESP.getFreeHeap();
status.minFreeHeap = ESP.getMinFreeHeap();
status.maxAllocatable = ESP.getMaxAllocHeap();
status.memoryHealthy = BufferManager::checkMemoryHealth();
status.statusMessage = "Free: " + String(status.freeHeap / 1024) + " KB" +
", Min: " + String(status.minFreeHeap / 1024) + " KB" +
", Double Buffering: " + String(BufferManager::canEnableDoubleBuffering() ? "YES" : "NO");
return status;
}
bool initializeMemoryManager() {
Serial.println("Initializing HIGH-PERFORMANCE memory manager...");
BufferManager::printHighPerformanceSettings();
BufferManager::printMemoryDiagnostics();
return BufferManager::checkMemoryHealth();
}