aboutsummaryrefslogtreecommitdiff
path: root/docs/project/benchmarking.md
diff options
context:
space:
mode:
Diffstat (limited to 'docs/project/benchmarking.md')
-rw-r--r--docs/project/benchmarking.md202
1 files changed, 202 insertions, 0 deletions
diff --git a/docs/project/benchmarking.md b/docs/project/benchmarking.md
new file mode 100644
index 000000000..0e3578237
--- /dev/null
+++ b/docs/project/benchmarking.md
@@ -0,0 +1,202 @@
+Bun is designed for speed. Hot paths are extensively profiled and benchmarked. The source code for all of Bun's public benchmarks can be found in the [`/bench`](https://github.com/oven-sh/bun/tree/main/bench) directory of the Bun repo.
+
+## Measuring time
+
+To precisely measure time, Bun offers two runtime APIs functions:
+
+1. The Web-standard [`performance.now()`](https://developer.mozilla.org/en-US/docs/Web/API/Performance/now) function
+2. `Bun.nanoseconds()` which is similar to `performance.now()` except it returns the current time since the application started in nanoseconds. You can use `performance.timeOrigin` to convert this to a Unix timestamp.
+
+## Benchmarking tools
+
+When writing your own benchmarks, it's important to choose the right tool.
+
+- For microbenchmarks, a great general-purpose tool is [`mitata`](https://github.com/evanwashere/mitata).
+- For load testing, you *must use* an HTTP benchmarking tool that is at least as fast as `Bun.serve()`, or your results will be skewed. Some popular Node.js-based benchmarking tools like [`autocannon`](https://github.com/mcollina/autocannon) are not fast enough. We recommend one of the following:
+ - [`bombardier`](https://github.com/codesenberg/bombardier)
+ - [`oha`](https://github.com/hatoo/oha)
+ - [`http_load_test`](https://github.com/uNetworking/uSockets/blob/master/examples/http_load_test.c)
+- For benchmarking scripts or CLI commands, we recommend [`hyperfine`](https://github.com/sharkdp/hyperfine). It's an easy way to compare
+
+Recommended HTTP clients:
+
+
+## Measuring memory usage
+
+Bun has two heaps. One heap is for the JavaScript runtime and the other heap is for everything else.
+
+### JavaScript heap stats
+
+The `bun:jsc` module exposes a few functions for measuring memory usage:
+
+```ts
+import { heapStats } from "bun:jsc";
+console.log(heapStats());
+```
+{% details summary="View example statistics" %}
+```ts
+{
+ heapSize: 1657575,
+ heapCapacity: 2872775,
+ extraMemorySize: 598199,
+ objectCount: 13790,
+ protectedObjectCount: 62,
+ globalObjectCount: 1,
+ protectedGlobalObjectCount: 1,
+ // A count of every object type in the heap
+ objectTypeCounts: {
+ CallbackObject: 25,
+ FunctionExecutable: 2078,
+ AsyncGeneratorFunction: 2,
+ 'RegExp String Iterator': 1,
+ FunctionCodeBlock: 188,
+ ModuleProgramExecutable: 13,
+ String: 1,
+ UnlinkedModuleProgramCodeBlock: 13,
+ JSON: 1,
+ AsyncGenerator: 1,
+ Symbol: 1,
+ GetterSetter: 68,
+ ImportMeta: 10,
+ DOMAttributeGetterSetter: 1,
+ UnlinkedFunctionCodeBlock: 174,
+ RegExp: 52,
+ ModuleLoader: 1,
+ Intl: 1,
+ WeakMap: 4,
+ Generator: 2,
+ PropertyTable: 95,
+ 'Array Iterator': 1,
+ JSLexicalEnvironment: 75,
+ UnlinkedFunctionExecutable: 2067,
+ WeakSet: 1,
+ console: 1,
+ Map: 23,
+ SparseArrayValueMap: 14,
+ StructureChain: 19,
+ Set: 18,
+ 'String Iterator': 1,
+ FunctionRareData: 3,
+ JSGlobalLexicalEnvironment: 1,
+ Object: 481,
+ BigInt: 2,
+ StructureRareData: 55,
+ Array: 179,
+ AbortController: 2,
+ ModuleNamespaceObject: 11,
+ ShadowRealm: 1,
+ 'Immutable Butterfly': 103,
+ Primordials: 1,
+ 'Set Iterator': 1,
+ JSProxy: 1,
+ AsyncFromSyncIterator: 1,
+ ModuleRecord: 13,
+ FinalizationRegistry: 1,
+ AsyncIterator: 1,
+ InternalPromise: 22,
+ Iterator: 1,
+ CustomGetterSetter: 65,
+ Promise: 19,
+ WeakRef: 1,
+ InternalPromisePrototype: 1,
+ Function: 2381,
+ AsyncFunction: 2,
+ GlobalObject: 1,
+ ArrayBuffer: 2,
+ Boolean: 1,
+ Math: 1,
+ CallbackConstructor: 1,
+ Error: 2,
+ JSModuleEnvironment: 13,
+ WebAssembly: 1,
+ HashMapBucket: 300,
+ Callee: 3,
+ symbol: 37,
+ string: 2484,
+ Performance: 1,
+ ModuleProgramCodeBlock: 12,
+ JSSourceCode: 13,
+ JSPropertyNameEnumerator: 3,
+ NativeExecutable: 290,
+ Number: 1,
+ Structure: 1550,
+ SymbolTable: 108,
+ GeneratorFunction: 2,
+ 'Map Iterator': 1
+ },
+ protectedObjectTypeCounts: {
+ CallbackConstructor: 1,
+ BigInt: 1,
+ RegExp: 2,
+ GlobalObject: 1,
+ UnlinkedModuleProgramCodeBlock: 13,
+ HashMapBucket: 2,
+ Structure: 41,
+ JSPropertyNameEnumerator: 1
+ }
+}
+```
+{% /details %}
+
+JavaScript is a garbage-collected language, not reference counted. It's normal and correct for objects to not be freed immediately in all cases, though it's not normal for objects to never be freed.
+
+Tp force garbage collection to run manually:
+
+```js
+Bun.gc(true); // synchronous
+Bun.gc(false); // asynchronous
+```
+
+Heap snapshots let you inspect what objects are not being freed. You can use the `bun:jsc` module to take a heap snapshot and then view it with Safari or WebKit GTK developer tools. To generate a heap snapshot:
+
+```ts
+import { generateHeapSnapshot } from "bun";
+
+const snapshot = generateHeapSnapshot();
+await Bun.write("heap.json", JSON.stringify(snapshot, null, 2));
+```
+
+To view the snapshot, open the `heap.json` file in Safari's Developer Tools (or WebKit GTK)
+
+1. Open the Developer Tools
+2. Click "Timeline"
+3. Click "JavaScript Allocations" in the menu on the left. It might not be visible until you click the pencil icon to show all the timelines
+4. Click "Import" and select your heap snapshot JSON
+
+
+{% image alt="Import heap json" src="https://user-images.githubusercontent.com/709451/204428943-ba999e8f-8984-4f23-97cb-b4e3e280363e.png" caption="Importing a heap snapshot" /%}
+
+Once imported, you should see something like this:
+
+
+{% image alt="Viewing heap snapshot in Safari" src="https://user-images.githubusercontent.com/709451/204429337-b0d8935f-3509-4071-b991-217794d1fb27.png" caption="Viewing heap snapshot in Safari Dev Tools" /%}
+
+
+### Native heap stats
+
+Bun uses mimalloc for the other heap. To report a summary of non-JavaScript memory usage, set the `MIMALLOC_SHOW_STATS=1` environment variable. and stats will print on exit.
+
+```js
+MIMALLOC_SHOW_STATS=1 bun script.js
+
+# will show something like this:
+heap stats: peak total freed current unit count
+ reserved: 64.0 MiB 64.0 MiB 0 64.0 MiB not all freed!
+ committed: 64.0 MiB 64.0 MiB 0 64.0 MiB not all freed!
+ reset: 0 0 0 0 ok
+ touched: 128.5 KiB 128.5 KiB 5.4 MiB -5.3 MiB ok
+ segments: 1 1 0 1 not all freed!
+-abandoned: 0 0 0 0 ok
+ -cached: 0 0 0 0 ok
+ pages: 0 0 53 -53 ok
+-abandoned: 0 0 0 0 ok
+ -extended: 0
+ -noretire: 0
+ mmaps: 0
+ commits: 0
+ threads: 0 0 0 0 ok
+ searches: 0.0 avg
+numa nodes: 1
+ elapsed: 0.068 s
+ process: user: 0.061 s, system: 0.014 s, faults: 0, rss: 57.4 MiB, commit: 64.0 MiB
+```