1515_BARE_NOISE_PREFIXES = (
1616 "_Py" ,
1717 "Py_" ,
18- "Py" ,
18+ "PyEval_" ,
19+ "PyObject_" ,
20+ "PyRun_" ,
1921 "pyrun" ,
2022 "pymain" ,
2123 "run_mod" ,
22- "slot_" ,
23- "method_" ,
24+ "slot_tp_" ,
2425 "cfunction_" ,
2526 "vectorcall" ,
26- "_call" ,
2727 "__libc_" ,
2828 "_start" ,
2929)
@@ -325,6 +325,8 @@ def generate_memory_html(
325325 padding: 12px 24px;
326326 border-bottom: 1px solid var(--border);
327327 flex-shrink: 0;
328+ position: relative;
329+ z-index: 60;
328330 }
329331
330332 #header h1 { font-size: 14px; font-weight: 500; font-family: var(--mono); letter-spacing: 0.03em; text-transform: uppercase; flex-shrink: 0; }
@@ -372,6 +374,45 @@ def generate_memory_html(
372374
373375 #help-trigger:hover #help-dropdown { display: block; }
374376
377+ #settings-trigger {
378+ cursor: pointer;
379+ position: relative;
380+ font-size: 14px;
381+ opacity: 0.6;
382+ transition: opacity 0.15s;
383+ user-select: none;
384+ }
385+ #settings-trigger:hover { opacity: 1; }
386+ #settings-dropdown {
387+ display: none;
388+ position: absolute;
389+ top: 100%;
390+ right: 0;
391+ margin-top: 6px;
392+ background: var(--tooltip-bg);
393+ border: 1px solid var(--border);
394+ border-radius: 4px;
395+ padding: 8px 12px;
396+ white-space: nowrap;
397+ z-index: 50;
398+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.6);
399+ font-family: var(--mono);
400+ font-size: 11px;
401+ color: var(--text-muted);
402+ }
403+ #settings-trigger.open #settings-dropdown { display: block; }
404+ #settings-dropdown label { display: flex; align-items: center; gap: 6px; }
405+ #settings-dropdown select {
406+ background: var(--bg);
407+ color: var(--text);
408+ border: 1px solid var(--border);
409+ border-radius: 3px;
410+ padding: 2px 4px;
411+ font-size: 11px;
412+ font-family: var(--mono);
413+ cursor: pointer;
414+ }
415+
375416 #controls {
376417 display: flex;
377418 gap: 12px;
@@ -873,6 +914,16 @@ def generate_memory_html(
873914 <input type="checkbox" id="dim-persistent-toggle">
874915 Hide never-freed
875916 </label>
917+ <span id="settings-trigger" title="Settings">⚙
918+ <div id="settings-dropdown">
919+ <label>Color by
920+ <select id="color-mode">
921+ <option value="stack">stack</option>
922+ <option value="size">size</option>
923+ </select>
924+ </label>
925+ </div>
926+ </span>
876927 </div>
877928</div>
878929<div id="main">
@@ -948,8 +999,38 @@ def generate_memory_html(
948999 return PALETTE[stackIdx % PALETTE.length];
9491000}
9501001
951- const PERSISTENT_COLOR = '#8A8F98';
952- const PERSISTENT_ALPHAS = [0.18, 0.24, 0.3];
1002+ const SIZE_PALETTE = [
1003+ '#2E7DB5', '#3E93CC', '#5BA8D9', '#78BBE3',
1004+ '#3ECCC1', '#49C963', '#6DD883', '#8DE49D',
1005+ '#C9CC3E', '#D9DB5B', '#E0C05B', '#CC6B3E',
1006+ '#E08A5B', '#bd93f9', '#a06eed', '#F0A478',
1007+ ];
1008+
1009+ const allocSizes = ALLOCS.map(a => a.s);
1010+ const sortedSizes = [...new Set(allocSizes)].sort((a, b) => a - b);
1011+ const sizeToColorIdx = new Map();
1012+ sortedSizes.forEach((s, i) => sizeToColorIdx.set(s, i % SIZE_PALETTE.length));
1013+
1014+ function getSizeColor(allocIdx) {
1015+ return SIZE_PALETTE[sizeToColorIdx.get(ALLOCS[allocIdx].s)];
1016+ }
1017+
1018+ let colorMode = 'stack';
1019+
1020+ function recolorAllocs() {
1021+ let pIdx = 0;
1022+ for (let i = 0; i < ALLOCS.length; i++) {
1023+ const isPersistent = allocPersistent[i];
1024+ allocColors[i] = colorMode === 'size'
1025+ ? getSizeColor(i)
1026+ : getColor(ALLOCS[i].si);
1027+ allocAlphas[i] = isPersistent
1028+ ? PERSISTENT_ALPHAS[pIdx++ % PERSISTENT_ALPHAS.length]
1029+ : 0.85;
1030+ }
1031+ }
1032+
1033+ const PERSISTENT_ALPHAS = [0.55, 0.62, 0.70];
9531034
9541035const tooltipEl = document.getElementById('tooltip');
9551036const detailBody = document.getElementById('detail-body');
@@ -1146,17 +1227,10 @@ def generate_memory_html(
11461227const allocPersistent = new Uint8Array(ALLOCS.length);
11471228const allocColors = new Array(ALLOCS.length);
11481229const allocAlphas = new Float64Array(ALLOCS.length);
1149- let persistentAlphaIdx = 0;
11501230for (let i = 0; i < ALLOCS.length; i++) {
1151- const isPersistent = allocEnds[i] >= META.max_timestep;
1152- allocPersistent[i] = isPersistent ? 1 : 0;
1153- allocColors[i] = isPersistent
1154- ? PERSISTENT_COLOR
1155- : getColor(ALLOCS[i].si);
1156- allocAlphas[i] = isPersistent
1157- ? PERSISTENT_ALPHAS[persistentAlphaIdx++ % PERSISTENT_ALPHAS.length]
1158- : 0.85;
1231+ allocPersistent[i] = allocEnds[i] >= META.max_timestep ? 1 : 0;
11591232}
1233+ recolorAllocs();
11601234let dimPersistent = false;
11611235
11621236// Bucket index for O(bucket_size) hit testing instead of O(n)
@@ -1532,6 +1606,12 @@ def generate_memory_html(
15321606 activeKeys.delete(event.key.toLowerCase());
15331607});
15341608
1609+ const settingsTrigger = document.getElementById('settings-trigger');
1610+ settingsTrigger.addEventListener('click', function(e) {
1611+ if (e.target.closest('#settings-dropdown')) return;
1612+ this.classList.toggle('open');
1613+ });
1614+
15351615document.getElementById('hwm-toggle').onchange = function() {
15361616 hwmG.style('display', this.checked ? null : 'none');
15371617};
@@ -1548,6 +1628,12 @@ def generate_memory_html(
15481628 updateChart(currentTransform);
15491629};
15501630
1631+ document.getElementById('color-mode').onchange = function() {
1632+ colorMode = this.value;
1633+ recolorAllocs();
1634+ drawCanvas();
1635+ };
1636+
15511637// --- Feature 1: Search & Filter ---
15521638const searchInput = document.getElementById('search-input');
15531639const regexToggle = document.getElementById('regex-toggle');
0 commit comments