Skip to content

Commit

Permalink
Make write chunked
Browse files Browse the repository at this point in the history
  • Loading branch information
runspired committed Jul 30, 2023
1 parent 7436813 commit 1b74cbd
Show file tree
Hide file tree
Showing 5 changed files with 120 additions and 11 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ This project cleans weak retainer paths from heap snapshots of even the largest

✨ Leaving Your Memory Leak Debugging

![Demo of CLI Tool](demo.png)

## Usage

To use:
Expand Down
Binary file modified cleanheap
Binary file not shown.
Binary file added demo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "cleanheap",
"version": "0.0.2",
"version": "0.0.3",
"description": "A tool for scrubbing Weak retainer paths from a heap snapshot",
"main": "src/index.ts",
"scripts": {
Expand Down
127 changes: 117 additions & 10 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,48 @@
import chalk from 'chalk';
import pkg from '../package.json';
import { heapStats } from "bun:jsc";
import { HeapSnapshot } from './-types';
import type { BunFile } from 'bun';
import { log } from 'console';

function formatBytes(bytes: number) {
if (bytes < 1024) {
return `${bytes}B`;
} else if (bytes < 1024 * 1024) {
return `${(bytes / 1024).toFixed(2)}KB`;
} else if (bytes < 1024 * 1024 * 1024) {
return `${(bytes / 1024 / 1024).toFixed(2)}MB`;
} else {
return `${(bytes / 1024 / 1024 / 1024).toFixed(2)}GB`;
}
}

function logCompletion(str: string) {
function logMemory() {
const {
heapSize,
heapCapacity,
extraMemorySize,
objectCount
} = heapStats();

console.log(chalk.grey(`\t${chalk.white('·')}\t\tMemory: ${chalk.cyan(formatBytes(heapSize))} / ${chalk.cyan(formatBytes(heapCapacity))} (${chalk.cyan(formatBytes(extraMemorySize))} extra) - ${chalk.cyan(objectCount)} objects`));
}

function clearLine() {
// @ts-expect-error not typed properly
process.stdout.clearLine(0);
// @ts-expect-error not typed properly
process.stdout.cursorTo(0);
}

function logUpdate(str: string) {
clearLine();

process.stdout.write(str);
}

function logCompletion(str: string) {
clearLine();

console.log(str);
}
Expand All @@ -33,7 +69,7 @@ async function getOutputFile(filePath: string) {
const exists = await fileHandle.exists();

if (exists) {
console.log(chalk.yellow(`\t⚠️ Overwritting existing file ${chalk.white(filePath)}!\n`));
console.log(chalk.yellow(`\t⚠️ Overwriting existing file ${chalk.white(filePath)}!\n`));
}

return fileHandle;
Expand Down Expand Up @@ -157,9 +193,81 @@ function iterateBySlice(
callback: (start: number, end: number) => void,
) {
for (let i = start; i < end; i += sliceSize) {
callback(i, i + sliceSize);
callback(i, i + sliceSize);
}
}
}

async function writeOutput(outputFile: BunFile, data: HeapSnapshot) {
const writer = outputFile.writer();

// write the header
process.stdout.write(chalk.grey(`\t${chalk.white('·')}\t\t🔸 ...writing Snapshot header`));
let content = JSON.stringify(data.snapshot);
data.snapshot = null as unknown as any;
writer.write(`{ "meta": ${content},`);
writer.flush();
content = ''; // free up memory
Bun.gc(true);
logCompletion(chalk.grey(`\t${chalk.white('·')}\t\t${chalk.green('▶')} Snapshot Headers`));
logMemory();

// write the nodes
process.stdout.write(chalk.grey(`\t${chalk.white('·')}\t\t🔸 ...writing Snapshot nodes`));
content = JSON.stringify(data.nodes);
data.nodes = null as unknown as any;
writer.write(`"nodes": ${content},`);
writer.flush();
content = ''; // free up memory
Bun.gc(true);
logCompletion(chalk.grey(`\t${chalk.white('·')}\t\t${chalk.green('▶')} Snapshot nodes`));
logMemory();

// write the edges
process.stdout.write(chalk.grey(`\t${chalk.white('·')}\t\t🔸 ...writing Snapshot edges`));
content = JSON.stringify(data.edges);
data.edges = null as unknown as any;
writer.write(`"edges": ${content}}`);
writer.flush();
content = ''; // free up memory
Bun.gc(true);
logCompletion(chalk.grey(`\t${chalk.white('·')}\t\t${chalk.green('▶')} Snapshot edges`));
logMemory();

// write the strings
process.stdout.write(chalk.grey(`\t${chalk.white('·')}\t\t🔸 ...writing Snapshot strings`));
content = JSON.stringify(data.strings);
data.strings = null as unknown as any;
writer.write(`"strings": ${content}}`);
writer.flush();
content = ''; // free up memory
Bun.gc(true);
logCompletion(chalk.grey(`\t${chalk.white('·')}\t\t${chalk.green('▶')} Snapshot strings`));
logMemory();

// write everything else
process.stdout.write(chalk.grey(`\t${chalk.white('·')}\t\t🔸 ...writing Snapshot Infos`));
for (const key in data) {
if (key === 'snapshot' || key === 'nodes' || key === 'edges' || key === 'strings') {
continue;
}
content = JSON.stringify(data[key]);
data[key] = null as unknown as any;
writer.write(`"${key}": ${content},`);
writer.flush();
content = ''; // free up memory
Bun.gc(true);
}
logCompletion(chalk.grey(`\t${chalk.white('·')}\t\t${chalk.green('▶')} Snapshot Infos`));
logMemory();

// close the file
writer.end();
console.log(chalk.grey(`\t${chalk.white('·')}\t${chalk.green('▶')} Snapshot written`));
logMemory();

// we're done!
console.log(chalk.magenta(`\n\t✨ Sparkling Clean\n\n`));
}



Expand All @@ -176,27 +284,26 @@ async function main() {

const writeHandler = await getOutputFile(outputFilePath);
const data = await getInput(inputFilePath);
logMemory();

process.stdout.write(chalk.grey(`\t${chalk.white('·')}\t🔸 ...parsing Snapshot`));
const snapshot = new Snapshot(data);
logCompletion(chalk.grey(`\t${chalk.white('·')}\t${chalk.green('▶')} Snapshot parsed`));
logMemory();

process.stdout.write(chalk.grey(`\t${chalk.white('·')}\t🔸 ...cleaning Snapshot`));
const isDirty = snapshot.clean();

if (!isDirty) {
logCompletion(chalk.grey(`\t${chalk.white('·')}\t${chalk.green('▶')} Snapshot Was Already Clean`));
console.log(chalk.magenta(`\n\t✨ Sparkling Clean\n\n`));
} else {
logCompletion(chalk.grey(`\t${chalk.white('·')}\t${chalk.green('▶')} Snapshot cleaned`));
logMemory();

process.stdout.write(chalk.grey(`\t${chalk.white('·')}\t🔸 ...writing Snapshot`));
await Bun.write(writeHandler, JSON.stringify(snapshot.data));
logCompletion(chalk.grey(`\t${chalk.white('·')}\t${chalk.green('▶')} Snapshot written`));
return await writeOutput(writeHandler, snapshot.data);
}



console.log(chalk.magenta(`\n\t✨ Sparkling Clean\n\n`));
}

await main();

0 comments on commit 1b74cbd

Please sign in to comment.