bumparena 0.0.7 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,8 +1,29 @@
1
- # BumpArena
1
+ # 🚀 BumpArena: High-Performance Memory Management for Bun/TS
2
2
 
3
- **4x faster than standard arrays and uses only ~40% of the RAM!** 🚀💾
3
+ [![npm version](https://img.shields.io/npm/v/bumparena.svg?style=flat-square)](https://www.npmjs.com/package/bumparena)
4
+ [![license](https://img.shields.io/npm/l/bumparena.svg?style=flat-square)](https://github.com/dein-nutzername/bumparena/blob/main/LICENSE)
4
5
 
5
- BumpArena is a high-performance memory arena for JavaScript and TypeScript. It provides contiguous memory allocation, fast pointer-based access, and minimal garbage collection overhead, making it ideal for handling large datasets efficiently.
6
+ **4.2x faster than standard arrays while using ~60% less RAM!** 💾⚡
7
+
8
+ BumpArena is a high-performance memory arena designed for JavaScript and TypeScript (optimized for Bun). It provides contiguous memory allocation, fast pointer-based access, and minimal Garbage Collection (GC) overhead, making it the ideal choice for handling industrial-scale datasets and real-time telemetry.
9
+
10
+ ---
11
+
12
+ ## 📊 Performance Benchmark (50M Objects)
13
+
14
+ I compared the **BumpArena** implementation against a standard **Array-based** approach by processing a dataset of 50 million records.
15
+
16
+ | Metric | Standard Array | **BumpArena** | Improvement |
17
+ | :--- | :--- | :--- | :--- |
18
+ | **Total Time** | 765.9s (12.7 min) | **183.1s (3.05 min)** | **4.2x Faster** 🚀 |
19
+ | **Throughput** | ~652k lines/s | **~2.73M lines/s** | **+318% Speed** |
20
+ | **RAM Usage (RSS)** | 28.04 GB | **11.24 GB** | **16.8 GB Saved** 📉 |
21
+ | **Heap Efficiency** | 11.22 GB | **4.82 GB** | **2.3x Lower Usage** |
22
+
23
+ ### 🛠 Why it's faster:
24
+ * **Zero GC Pressure:** By using a pre-allocated buffer, we bypass the costly JavaScript Garbage Collector.
25
+ * **Cache Locality:** Contiguous memory layout ensures the CPU stays fast and avoids cache misses.
26
+ * **Industrial Scale:** Designed to handle 50M+ data points without breaking the heap.
6
27
 
7
28
  ---
8
29
 
@@ -34,25 +55,30 @@ yarn add bumparena
34
55
 
35
56
  ```ts
36
57
  import { Arena } from "bumparena";
58
+ import fs from "node:fs";
59
+
60
+ // 1. Initialize (e.g., 1GB Arena)
61
+ const arena = new Arena({ initalSize: 1024 * 1024 * 1024 });
37
62
 
38
- // Create a new arena with default settings
39
- const arena = new Arena();
63
+ // 2. Map data instantly (Zero-Copy)
64
+ const data = new Uint8Array([10, 20, 30, 40]);
65
+ const ptr = arena.alloc(data);
40
66
 
41
- // Allocate some data
42
- const data = new Uint8Array([1, 2, 3, 4, 5]);
43
- const ptr = arena.alloc(data);
67
+ // 3. Retrieve (O(1) access)
68
+ const view = arena.read(ptr);
44
69
 
45
- // Read the data back
46
- const readData = arena.read(ptr);
47
- console.log(readData); // Uint8Array [1,2,3,4,5]
70
+ // 4. Persistence "From Nothing"
71
+ // Save the entire memory state 1:1 as a binary image
72
+ fs.writeFileSync("database.bin", arena.getBuffer());
48
73
 
49
- // Free the allocation
50
- arena.free(ptr);
74
+ // 5. Reload (Zero Parsing Time)
75
+ // Simply load the bytes back into a new Arena buffer
76
+ const savedData = fs.readFileSync("database.bin");
77
+ const restoredArena = new Arena({ initalSize: savedData.byteLength });
78
+ restoredArena.putBytes(savedData); // Structure is restored instantly
51
79
 
52
- // Reserve a block for manual writes
53
- const reserved = arena.reserve(10);
54
- reserved.set(new Uint8Array([10, 20, 30]));
55
- console.log(reserved);
80
+ //Clear your Arena, if you want a restart
81
+ arena.clear()
56
82
  ```
57
83
 
58
84
  ---
@@ -66,6 +92,99 @@ console.log(reserved);
66
92
 
67
93
  ---
68
94
 
95
+ ## Binary Header Specification
96
+
97
+ BumpArena uses a fixed 16-byte packed header. Alignment is applied to the entire block, ensuring that every new Header starts at a memory address divisible by your chosen alignment (e.g., 8, 16, 32 bytes).
98
+
99
+ ### Memory Layout & Alignment
100
+
101
+ The total_length field does not just represent the sum of the header and data; it includes the padding required to align the next block in the Arena.
102
+
103
+ | Offset (Byte) | Field | Type | Description |
104
+ | :--- | :--- | :--- | :--- |
105
+ | `0x00` | `total_length` | `uint32` | Header + Payload + Alignment Padding |
106
+ | `0x04` | `payload_length` | `uint32` | Exact size of the user data |
107
+ | `0x08` | `generation` | `uint32` | Validation counter (prevents ABA/stale pointer issues) |
108
+ | `0x0C` | `deleted` | `uint8` | Status flag (`0x01` = deleted, `0x00` = active) |
109
+ | `0x0D` | `user_header0` | `uint8` | Custom metadata slot 1 |
110
+ | `0x0E` | `user_header1` | `uint8` | Custom metadata slot 2 |
111
+ | `0x0F` | `user_header2` | `uint8` | Custom metadata slot 3 |
112
+ | `0x10` | **Payload** | `u8[]` | User data starts here (Fixed Offset) |
113
+ | `...` | **Padding** | `u8[N]` | Internal padding to align the next Block |
114
+
115
+ ### Implementation Examples
116
+
117
+ Typescript
118
+
119
+ ```ts
120
+ // Example: How BumpArena maps the header internally
121
+ const view = new DataView(arena.getBuffer().buffer);
122
+ const ptr = 0x1234; // Current allocation pointer
123
+
124
+ const header = {
125
+ totalLength: view.getUint32(ptr + 0, true), // Little-endian
126
+ payloadLength: view.getUint32(ptr + 4, true),
127
+ generation: view.getUint32(ptr + 8, true),
128
+ deleted: view.getUint8(ptr + 12),
129
+ userHeader: new Uint8Array(arena.getBuffer().buffer, ptr + 13, 3)
130
+ };
131
+
132
+ // The actual payload starts at ptr + 16
133
+ const payload = new Uint8Array(arena.getBuffer().buffer, ptr + 16, header.payloadLength);
134
+ ```
135
+
136
+ C/++
137
+
138
+ ```c
139
+ typedef struct __attribute__((packed)) {
140
+ uint32_t total_length; // Jump to next header: current_ptr + total_length
141
+ uint32_t payload_length;
142
+ uint32_t generation;
143
+ uint8_t deleted;
144
+ uint8_t user_header0;
145
+ uint8_t user_header1;
146
+ uint8_t user_header2;uint8_t payload[]; // Data starts at offset 16 (0x10)
147
+ } ArenaData;
148
+ ```
149
+
150
+ Rust
151
+
152
+ ```rust
153
+ #[repr(C, packed)]
154
+ pub struct ArenaData {
155
+ pub total_length: u32, // Jump to next header: current_ptr + total_length
156
+ pub payload_length: u32,
157
+ pub generation: u32,
158
+ pub deleted: u8,
159
+ pub user_header0: u8,
160
+ pub user_header1: u8,
161
+ pub user_header2: u8,
162
+ // Payload follows immediately at offset 16
163
+ }
164
+ ```
165
+
166
+ go
167
+
168
+ ```go
169
+ type ArenaData struct {
170
+ TotalLength uint32 // Jump to next header: current_ptr + total_length
171
+ PayloadLength uint32 // the length of the Payload itself
172
+ Generation uint32 // The Generation bits
173
+ Deleted uint8 // 0x1=true,0x0=false
174
+ UserHeader [3]uint8 // User Metadata
175
+ // Payload follows immediately at offset 16
176
+ }
177
+ ```
178
+
179
+ Key Advantages
180
+ Zero-Copy: Directly cast your binary data to these structures in any language.
181
+
182
+ Stale Pointer Protection: The generation field allows you to verify if a pointer still refers to the original data or if the memory has been reused.
183
+
184
+ Alignment: 16-byte boundaries are a "sweet spot" for modern hardware architectures,.
185
+
186
+ ---
187
+
69
188
  ## Benchmarks
70
189
 
71
190
  | Implementation | Time | Heap Used | Notes |
@@ -0,0 +1,64 @@
1
+ export type ArenaLocation = bigint & {
2
+ readonly __data_pointer: unique symbol;
3
+ };
4
+ export interface ArenaOptions {
5
+ initalSize?: number;
6
+ littleEndian?: boolean;
7
+ allignment?: 8 | 16 | 32 | 64;
8
+ bucketOffsets?: number[];
9
+ bucketCapacities?: number[];
10
+ }
11
+ export interface ArenaCustomHeaders {
12
+ header0: number;
13
+ header1: number;
14
+ header2: number;
15
+ }
16
+ export interface ArenaHeaders {
17
+ totalLength: number;
18
+ payloadlength: number;
19
+ deleted: boolean;
20
+ header0: number;
21
+ header1: number;
22
+ header2: number;
23
+ }
24
+ export declare class Arena {
25
+ private HEADER_SIZE_BYTES;
26
+ private _buffer;
27
+ private _view8;
28
+ private _view32;
29
+ private _offset;
30
+ private _emptySpots;
31
+ private _allignMask;
32
+ private _allignShift;
33
+ private _bucketOffsets;
34
+ private _bucketCapacities;
35
+ private _bucketcount;
36
+ constructor(options?: ArenaOptions);
37
+ private _u;
38
+ private _idx32;
39
+ private _makePtr;
40
+ private _getOffset;
41
+ private _getBucketCount;
42
+ private _setBucketCount;
43
+ private _getBucketOffset;
44
+ private _setBucketOffset;
45
+ private _initBlock;
46
+ alloc(data: Uint8Array, headers?: ArenaCustomHeaders): ArenaLocation;
47
+ read(location: ArenaLocation): Uint8Array | null;
48
+ free(location: ArenaLocation): ArenaLocation;
49
+ private _checkForSpace;
50
+ private _resize;
51
+ size(): number;
52
+ getBuffer(): Uint8Array;
53
+ reserve(size: number): Uint8Array;
54
+ translate(ptr: ArenaLocation): {
55
+ start: number;
56
+ generation: bigint;
57
+ };
58
+ readWithHeaders(ptr: ArenaLocation): Uint8Array | null;
59
+ label(): Array<ArenaLocation>;
60
+ getHeaders(ptr: ArenaLocation): ArenaHeaders;
61
+ estimate(size: number, amnt: number): number;
62
+ directAlloc(source: Uint8Array, startn: number, endn: number): ArenaLocation;
63
+ clear(): void;
64
+ }
package/interface.d.ts ADDED
@@ -0,0 +1,48 @@
1
+ export type ArenaLocation = bigint & { readonly __data_pointer: unique symbol };
2
+ export interface ArenaOptions {
3
+ initalSize?: number
4
+ littleEndian?: boolean
5
+ allignment?: 8 | 16 | 32 | 64
6
+ bucketOffsets?: number[];
7
+ bucketCapacities?: number[];
8
+ }
9
+ export interface ArenaCustomHeaders {
10
+ header0: number,
11
+ header1: number,
12
+ header2: number
13
+ }
14
+ export interface InspectStruct {
15
+ offset: number;
16
+ generation_ptr: number;
17
+ generation: number;
18
+ isSafe: boolean;
19
+ totalLength: number;
20
+ payloadLength: number;
21
+ isDeleted: boolean;
22
+ UserMetaData0: number;
23
+ UserMetaData1: number;
24
+ UserMetaData2: number;
25
+ payload?: Uint8Array;
26
+ }
27
+ export interface ArenaHeaders {
28
+ totalLength: number
29
+ payloadLength: number
30
+ deleted: boolean
31
+ header0: number
32
+ header1: number
33
+ header2: number
34
+ }
35
+ export interface IStorageStrategy {
36
+ alloc(data: Uint8Array, headers?: ArenaCustomHeaders): ArenaLocation
37
+ read(location: ArenaLocation): Uint8Array | null
38
+ free(location: ArenaLocation): ArenaLocation
39
+ estimate(size: number, amnt: number): number
40
+ reset(): void
41
+ clear(): void
42
+
43
+ /** Eager Collection */
44
+ collectActiveRecords(): ArenaLocation[]
45
+
46
+ /** Lazy Iterator */
47
+ records(): Generator<[Uint8Array, ArenaLocation]>
48
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bumparena",
3
- "version":"0.0.7",
3
+ "version":"0.9.0",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "main": "dist/arena.js",
package/bench/bench.md DELETED
@@ -1,38 +0,0 @@
1
- # Benchmark 1
2
-
3
- ## bun arena.ts;
4
- 183098.55 ms
5
- {
6
- rss: 11240919040,
7
- heapTotal: 8595075072,
8
- heapUsed: 4817152633,
9
- external: 2157456969,
10
- arrayBuffers: 2156686216,
11
- }
12
- arenasize: 2097152 KB
13
-
14
-
15
-
16
- ## bun array.ts
17
- 765961.27 ms
18
- Count: 50000000
19
- {
20
- rss: 28036014080,
21
- heapTotal: 9476152320,
22
- heapUsed: 11222438346,
23
- external: 7170077276,
24
- arrayBuffers: 2921230601,
25
- }
26
-
27
- ---
28
-
29
- ## Direct Comparison
30
-
31
- | Metric | Arena Implementation (Optimized) | Standard Array Implementation | Difference / Factor |
32
- | :--- | :--- | :--- | :--- |
33
- | **Total Time** | **183,098 ms** (3.05 min) | **765,961 ms** (12.76 min) | **~4.2x Faster** |
34
- | **Time per 50M Lines** | **~18.3 sec** | **~76.6 sec** | **- 58.3 sec / Round** |
35
- | **RAM Usage (RSS)** | **11.24 GB** | **28.04 GB** | **16.8 GB Saved** |
36
- | **Heap Used (JS Objects)** | **4.82 GB** | **11.22 GB** | **2.3x More Efficient** |
37
- | **External (Buffer)** | **2.16 GB** | **7.17 GB** | **Compact Memory Footprint** |
38
-