Skip to content

Commit 58571d8

Browse files
adds a peak heap usage stat, max bucket limiter, and update to account for padding size when creating a new bucket size
1 parent 5e8cf97 commit 58571d8

1 file changed

Lines changed: 116 additions & 7 deletions

File tree

staticmemory/memory-bucket-optimizer/optimizer/memory_bucket_optimizer.c

Lines changed: 116 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,15 @@
3131
#define MAX_ALLOC_SIZES 1000
3232
#define MAX_LINE_LENGTH 1024
3333
#define MAX_BUCKETS 16
34+
#define MAX_UNIQUE_BUCKETS 9 /* Maximum number of unique bucket sizes to create */
3435
#define MAX_ALLOCATIONS 10000
3536

37+
/* Configuration notes:
38+
* - MAX_UNIQUE_BUCKETS: Limits the total number of unique bucket sizes
39+
* This helps control memory overhead and bucket management complexity
40+
* Default: 9 buckets (can be adjusted based on memory constraints)
41+
*/
42+
3643
/* Memory overhead constants - these should match wolfSSL's actual values */
3744
#define WOLFSSL_HEAP_SIZE 64 /* Approximate size of WOLFSSL_HEAP structure */
3845
#define WOLFSSL_HEAP_HINT_SIZE 32 /* Approximate size of WOLFSSL_HEAP_HINT structure */
@@ -75,7 +82,7 @@ int calculate_total_overhead(int num_buckets) {
7582
}
7683

7784
/* Function to parse memory allocation logs with concurrent usage tracking */
78-
int parse_memory_logs(const char* filename, AllocSize* alloc_sizes, int* num_sizes) {
85+
int parse_memory_logs(const char* filename, AllocSize* alloc_sizes, int* num_sizes, int* peak_heap_usage) {
7986
FILE* file = fopen(filename, "r");
8087
if (!file) {
8188
printf("Error: Could not open file %s\n", filename);
@@ -87,6 +94,7 @@ int parse_memory_logs(const char* filename, AllocSize* alloc_sizes, int* num_siz
8794
AllocationEvent events[MAX_ALLOCATIONS];
8895
int num_events = 0;
8996
int timestamp = 0;
97+
*peak_heap_usage = 0; /* Initialize peak heap usage */
9098

9199
while (fgets(line, sizeof(line), file) && num_events < MAX_ALLOCATIONS) {
92100
/* Look for lines containing "Alloc:" or "Free:" */
@@ -184,6 +192,32 @@ int parse_memory_logs(const char* filename, AllocSize* alloc_sizes, int* num_siz
184192
}
185193
}
186194

195+
/* Calculate peak heap usage by simulating the allocation timeline */
196+
/* This tracks the maximum total memory that was allocated concurrently */
197+
int current_heap_usage = 0;
198+
int max_heap_usage = 0;
199+
200+
/* Create a timeline of heap usage changes */
201+
for (int i = 0; i < num_events; i++) {
202+
if (events[i].active) {
203+
/* Allocation - add to current heap usage */
204+
current_heap_usage += events[i].size;
205+
} else {
206+
/* Free - subtract from current heap usage */
207+
current_heap_usage -= events[i].size;
208+
if (current_heap_usage < 0) {
209+
current_heap_usage = 0; /* Handle mismatched free/alloc */
210+
}
211+
}
212+
213+
/* Track peak usage */
214+
if (current_heap_usage > max_heap_usage) {
215+
max_heap_usage = current_heap_usage;
216+
}
217+
}
218+
219+
*peak_heap_usage = max_heap_usage;
220+
187221
return 0;
188222
}
189223

@@ -198,6 +232,14 @@ int compare_alloc_counts(const void* a, const void* b) {
198232
}
199233

200234
/* Function to optimize bucket sizes */
235+
/*
236+
* Optimization heuristic:
237+
* - Always include the largest allocation size
238+
* - For other sizes, only create a new bucket if the waste from using
239+
* existing buckets is >= padding size per bucket
240+
* - This reduces bucket management overhead when waste is minimal
241+
* - Limited to MAX_UNIQUE_BUCKETS total unique bucket sizes
242+
*/
201243
void optimize_buckets(AllocSize* alloc_sizes, int num_sizes, int* buckets,
202244
int* dist, int* num_buckets)
203245
{
@@ -260,8 +302,8 @@ void optimize_buckets(AllocSize* alloc_sizes, int num_sizes, int* buckets,
260302
dist[*num_buckets] = (largest_concurrent > 0) ? largest_concurrent : 1;
261303
(*num_buckets)++;
262304

263-
/* Add significant allocation sizes, avoiding duplicates */
264-
for (i = 0; i < num_significant && *num_buckets < MAX_BUCKETS; i++) {
305+
/* Add significant allocation sizes, considering padding overhead */
306+
for (i = 0; i < num_significant && *num_buckets < MAX_UNIQUE_BUCKETS; i++) {
265307
int size = significant_sizes[i];
266308

267309
/* Skip if this size is already included (like the largest size) */
@@ -276,6 +318,32 @@ void optimize_buckets(AllocSize* alloc_sizes, int num_sizes, int* buckets,
276318
}
277319

278320
if (!already_included) {
321+
/* Check if this size can be efficiently handled by existing buckets */
322+
int best_existing_bucket = -1;
323+
int min_waste = INT_MAX;
324+
int padding_size = calculate_padding_size();
325+
326+
/* Find the best existing bucket for this size */
327+
for (j = 0; j < *num_buckets; j++) {
328+
int bucket_data_size = buckets[j] - padding_size;
329+
if (bucket_data_size >= size) {
330+
int waste = bucket_data_size - size;
331+
if (waste < min_waste) {
332+
min_waste = waste;
333+
best_existing_bucket = j;
334+
}
335+
}
336+
}
337+
338+
/* Only create a new bucket if the waste from existing buckets is significant */
339+
/* If waste is less than padding size, it's better to use existing bucket */
340+
if (best_existing_bucket >= 0 && min_waste < padding_size) {
341+
/* Use existing bucket - don't create a new one */
342+
/* This size will be handled by the existing bucket */
343+
continue;
344+
}
345+
346+
/* Create new bucket for this size */
279347
buckets[*num_buckets] = calculate_bucket_size_with_padding(size);
280348

281349
/* Calculate distribution based on concurrent usage and frequency */
@@ -313,8 +381,8 @@ void optimize_buckets(AllocSize* alloc_sizes, int num_sizes, int* buckets,
313381
}
314382

315383
/* If we still have space, add some medium-frequency sizes */
316-
if (*num_buckets < MAX_BUCKETS) {
317-
for (i = 0; i < num_sizes && *num_buckets < MAX_BUCKETS; i++) {
384+
if (*num_buckets < MAX_UNIQUE_BUCKETS) {
385+
for (i = 0; i < num_sizes && *num_buckets < MAX_UNIQUE_BUCKETS; i++) {
318386
int size = alloc_sizes_by_freq[i].size;
319387

320388
/* Skip if already included */
@@ -329,6 +397,32 @@ void optimize_buckets(AllocSize* alloc_sizes, int num_sizes, int* buckets,
329397
}
330398

331399
if (!already_included && alloc_sizes_by_freq[i].count >= 3) {
400+
/* Check if this size can be efficiently handled by existing buckets */
401+
int best_existing_bucket = -1;
402+
int min_waste = INT_MAX;
403+
int padding_size = calculate_padding_size();
404+
405+
/* Find the best existing bucket for this size */
406+
for (j = 0; j < *num_buckets; j++) {
407+
int bucket_data_size = buckets[j] - padding_size;
408+
if (bucket_data_size >= size) {
409+
int waste = bucket_data_size - size;
410+
if (waste < min_waste) {
411+
min_waste = waste;
412+
best_existing_bucket = j;
413+
}
414+
}
415+
}
416+
417+
/* Only create a new bucket if the waste from existing buckets is significant */
418+
/* If waste is less than padding size, it's better to use existing bucket */
419+
if (best_existing_bucket >= 0 && min_waste < padding_size) {
420+
/* Use existing bucket - don't create a new one */
421+
/* This size will be handled by the existing bucket */
422+
continue;
423+
}
424+
425+
/* Create new bucket for this size */
332426
buckets[*num_buckets] = calculate_bucket_size_with_padding(size);
333427
dist[*num_buckets] = 2; /* Default to 2 buckets for medium frequency */
334428
(*num_buckets)++;
@@ -354,6 +448,17 @@ void optimize_buckets(AllocSize* alloc_sizes, int num_sizes, int* buckets,
354448
}
355449

356450
free(alloc_sizes_by_freq);
451+
452+
/* Print optimization summary */
453+
printf("Optimization Summary:\n");
454+
printf("Padding size per bucket: %d bytes\n", calculate_padding_size());
455+
printf("Maximum unique buckets allowed: %d\n", MAX_UNIQUE_BUCKETS);
456+
printf("Total buckets created: %d\n", *num_buckets);
457+
if (*num_buckets >= MAX_UNIQUE_BUCKETS) {
458+
printf("Note: Reached maximum bucket limit (%d). Some allocations may use larger buckets.\n", MAX_UNIQUE_BUCKETS);
459+
}
460+
printf("Note: Allocations with waste < padding size use existing buckets to reduce overhead\n");
461+
printf("Note: Bucket limit helps balance memory efficiency vs. management overhead\n\n");
357462
}
358463

359464
/* Function to calculate memory efficiency metrics */
@@ -364,8 +469,10 @@ void calculate_memory_efficiency(AllocSize* alloc_sizes, int num_sizes,
364469
float total_waste = 0.0;
365470
int total_allocations = 0;
366471
int allocations_handled = 0;
472+
int padding_size = calculate_padding_size();
367473

368474
printf("Memory Efficiency Analysis:\n");
475+
printf("Note: Allocations with waste < %d bytes (padding size) use existing buckets\n", padding_size);
369476
printf("Size Count Concurrent Bucket Waste Coverage\n");
370477
printf("---- ----- ---------- ------ ----- --------\n");
371478

@@ -479,13 +586,15 @@ int main(int argc, char** argv)
479586

480587
AllocSize alloc_sizes[MAX_ALLOC_SIZES];
481588
int num_sizes = 0;
589+
int peak_heap_usage = 0;
482590

483591
/* Parse memory allocation logs */
484-
if (parse_memory_logs(argv[1], alloc_sizes, &num_sizes) != 0) {
592+
if (parse_memory_logs(argv[1], alloc_sizes, &num_sizes, &peak_heap_usage) != 0) {
485593
return 1;
486594
}
487595

488-
printf("Found %d unique allocation sizes\n\n", num_sizes);
596+
printf("Found %d unique allocation sizes\n", num_sizes);
597+
printf("Peak heap usage: %d bytes (maximum concurrent memory usage)\n\n", peak_heap_usage);
489598

490599
/* Sort allocation sizes */
491600
qsort(alloc_sizes, num_sizes, sizeof(AllocSize), compare_alloc_sizes);

0 commit comments

Comments
 (0)