Major Features: - Debug counter infrastructure for Refill Stage tracking - Free Pipeline counters (ss_local, ss_remote, tls_sll) - Diagnostic counters for early return analysis - Unified larson.sh benchmark runner with profiles - Phase 6-3 regression analysis documentation Bug Fixes: - Fix SuperSlab disabled by default (HAKMEM_TINY_USE_SUPERSLAB) - Fix profile variable naming consistency - Add .gitignore patterns for large files Performance: - Phase 6-3: 4.79 M ops/s (has OOM risk) - With SuperSlab: 3.13 M ops/s (+19% improvement) This is a clean repository without large log files. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
149 lines
5.4 KiB
C
149 lines
5.4 KiB
C
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
|
||
// Phase 8: Detailed smaps breakdown
|
||
// Parse every memory region to find the 5.6 MB overhead
|
||
|
||
typedef struct {
|
||
char name[128];
|
||
unsigned long rss;
|
||
unsigned long pss;
|
||
unsigned long anon;
|
||
unsigned long size;
|
||
} MemRegion;
|
||
|
||
void print_smaps_detailed(const char* label) {
|
||
printf("\n╔═══════════════════════════════════════════════╗\n");
|
||
printf("║ %s\n", label);
|
||
printf("╚═══════════════════════════════════════════════╝\n");
|
||
|
||
FILE* f = fopen("/proc/self/smaps", "r");
|
||
if (!f) {
|
||
printf("Cannot open /proc/self/smaps\n");
|
||
return;
|
||
}
|
||
|
||
char line[512];
|
||
MemRegion regions[1000];
|
||
int region_count = 0;
|
||
MemRegion* current = NULL;
|
||
|
||
unsigned long total_rss = 0;
|
||
unsigned long total_anon = 0;
|
||
|
||
while (fgets(line, sizeof(line), f)) {
|
||
// New region starts with address range
|
||
if (strchr(line, '-') && strchr(line, ' ')) {
|
||
if (region_count < 1000) {
|
||
current = ®ions[region_count++];
|
||
memset(current, 0, sizeof(MemRegion));
|
||
|
||
// Extract region name (last part of line)
|
||
char* p = strchr(line, '/');
|
||
if (p) {
|
||
char* end = strchr(p, '\n');
|
||
if (end) *end = '\0';
|
||
snprintf(current->name, sizeof(current->name), "%s", p);
|
||
} else if (strstr(line, "[heap]")) {
|
||
snprintf(current->name, sizeof(current->name), "[heap]");
|
||
} else if (strstr(line, "[stack]")) {
|
||
snprintf(current->name, sizeof(current->name), "[stack]");
|
||
} else if (strstr(line, "[vdso]")) {
|
||
snprintf(current->name, sizeof(current->name), "[vdso]");
|
||
} else if (strstr(line, "[vvar]")) {
|
||
snprintf(current->name, sizeof(current->name), "[vvar]");
|
||
} else {
|
||
snprintf(current->name, sizeof(current->name), "[anon]");
|
||
}
|
||
}
|
||
} else if (current) {
|
||
unsigned long val;
|
||
if (sscanf(line, "Size: %lu kB", &val) == 1) {
|
||
current->size = val;
|
||
}
|
||
if (sscanf(line, "Rss: %lu kB", &val) == 1) {
|
||
current->rss = val;
|
||
total_rss += val;
|
||
}
|
||
if (sscanf(line, "Pss: %lu kB", &val) == 1) {
|
||
current->pss = val;
|
||
}
|
||
if (sscanf(line, "Anonymous: %lu kB", &val) == 1) {
|
||
current->anon = val;
|
||
total_anon += val;
|
||
}
|
||
}
|
||
}
|
||
|
||
fclose(f);
|
||
|
||
// Print regions sorted by RSS (largest first)
|
||
printf("\nTop memory regions by RSS:\n");
|
||
printf("%-50s %10s %10s %10s\n", "Region", "Size", "RSS", "Anon");
|
||
printf("────────────────────────────────────────────────────────────────────────────\n");
|
||
|
||
// Simple bubble sort by RSS
|
||
for (int i = 0; i < region_count - 1; i++) {
|
||
for (int j = i + 1; j < region_count; j++) {
|
||
if (regions[j].rss > regions[i].rss) {
|
||
MemRegion tmp = regions[i];
|
||
regions[i] = regions[j];
|
||
regions[j] = tmp;
|
||
}
|
||
}
|
||
}
|
||
|
||
// Print top 30 regions
|
||
for (int i = 0; i < region_count && i < 30; i++) {
|
||
if (regions[i].rss > 0) {
|
||
printf("%-50s %7lu KB %7lu KB %7lu KB\n",
|
||
regions[i].name,
|
||
regions[i].size,
|
||
regions[i].rss,
|
||
regions[i].anon);
|
||
}
|
||
}
|
||
|
||
printf("────────────────────────────────────────────────────────────────────────────\n");
|
||
printf("TOTAL: %7lu KB %7lu KB\n",
|
||
total_rss, total_anon);
|
||
printf(" %.1f MB %.1f MB\n",
|
||
total_rss / 1024.0, total_anon / 1024.0);
|
||
}
|
||
|
||
int main() {
|
||
printf("╔═══════════════════════════════════════════════╗\n");
|
||
printf("║ Detailed smaps Analysis ║\n");
|
||
printf("╚═══════════════════════════════════════════════╝\n");
|
||
|
||
print_smaps_detailed("Baseline (program start)");
|
||
|
||
// Allocate 1M × 16B
|
||
int n = 1000000;
|
||
void** ptrs = malloc(n * sizeof(void*));
|
||
|
||
for (int i = 0; i < n; i++) {
|
||
ptrs[i] = malloc(16);
|
||
}
|
||
|
||
print_smaps_detailed("After 1M × 16B allocation");
|
||
|
||
// Free all
|
||
for (int i = 0; i < n; i++) {
|
||
free(ptrs[i]);
|
||
}
|
||
|
||
// Flush Magazine
|
||
extern void hak_tiny_magazine_flush_all(void) __attribute__((weak));
|
||
if (hak_tiny_magazine_flush_all) {
|
||
hak_tiny_magazine_flush_all();
|
||
}
|
||
|
||
print_smaps_detailed("After free + flush");
|
||
|
||
free(ptrs);
|
||
|
||
return 0;
|
||
}
|