@jax-js/jax 0.1.12 → 0.1.13

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
@@ -76,6 +76,7 @@ Demos on the jax-js website:
76
76
  - [Object detection: D-FINE (ONNX)](https://jax-js.com/d-fine)
77
77
  - [Object detection: DETR ResNet-50 (ONNX)](https://jax-js.com/detr-resnet-50)
78
78
  - [Fluid simulation (Navier-Stokes)](https://jax-js.com/fluid-sim)
79
+ - [Neural cellular automata](https://jax-js.com/nca-growing)
79
80
  - [In-browser REPL](https://jax-js.com/repl)
80
81
  - [Matmul benchmark](https://jax-js.com/bench/matmul)
81
82
  - [Matvec benchmark](https://jax-js.com/bench/matvec)
@@ -4522,7 +4522,7 @@ var WasmBackend = class {
4522
4522
  const buffer = this.#getBuffer(slot);
4523
4523
  if (start === void 0) start = 0;
4524
4524
  if (count === void 0) count = buffer.byteLength - start;
4525
- if (buffer.buffer instanceof SharedArrayBuffer) return new Uint8Array(buffer.slice(start, start + count));
4525
+ if (hasSharedArrayBuffer() && buffer.buffer instanceof SharedArrayBuffer) return new Uint8Array(buffer.slice(start, start + count));
4526
4526
  else return buffer.slice(start, start + count);
4527
4527
  }
4528
4528
  async prepareKernel(kernel) {
@@ -5061,7 +5061,7 @@ async function createBackend(device) {
5061
5061
  if (!navigator.gpu) return null;
5062
5062
  const adapter = await navigator.gpu.requestAdapter({ powerPreference: "high-performance" });
5063
5063
  if (!adapter) return null;
5064
- const { WebGPUBackend } = await import("./webgpu-C2kLdkUh.js");
5064
+ const { WebGPUBackend } = await import("./webgpu-NkF1TZ0t.js");
5065
5065
  const importantLimits = [
5066
5066
  "maxBufferSize",
5067
5067
  "maxComputeInvocationsPerWorkgroup",
@@ -5099,7 +5099,7 @@ async function createBackend(device) {
5099
5099
  });
5100
5100
  if (!gl) return null;
5101
5101
  if (!gl.getExtension("EXT_color_buffer_float")) return null;
5102
- const { WebGLBackend } = await import("./webgl-BhsnpeB0.js");
5102
+ const { WebGLBackend } = await import("./webgl-NsFtyIts.js");
5103
5103
  return new WebGLBackend(gl);
5104
5104
  } else throw new Error(`Backend not found: ${device}`);
5105
5105
  }
@@ -4523,7 +4523,7 @@ var WasmBackend = class {
4523
4523
  const buffer = this.#getBuffer(slot);
4524
4524
  if (start === void 0) start = 0;
4525
4525
  if (count === void 0) count = buffer.byteLength - start;
4526
- if (buffer.buffer instanceof SharedArrayBuffer) return new Uint8Array(buffer.slice(start, start + count));
4526
+ if (hasSharedArrayBuffer() && buffer.buffer instanceof SharedArrayBuffer) return new Uint8Array(buffer.slice(start, start + count));
4527
4527
  else return buffer.slice(start, start + count);
4528
4528
  }
4529
4529
  async prepareKernel(kernel) {
@@ -5062,7 +5062,7 @@ async function createBackend(device) {
5062
5062
  if (!navigator.gpu) return null;
5063
5063
  const adapter = await navigator.gpu.requestAdapter({ powerPreference: "high-performance" });
5064
5064
  if (!adapter) return null;
5065
- const { WebGPUBackend } = await Promise.resolve().then(() => require("./webgpu-C4S8Uq9e.cjs"));
5065
+ const { WebGPUBackend } = await Promise.resolve().then(() => require("./webgpu-DDGCYtHa.cjs"));
5066
5066
  const importantLimits = [
5067
5067
  "maxBufferSize",
5068
5068
  "maxComputeInvocationsPerWorkgroup",
@@ -5100,7 +5100,7 @@ async function createBackend(device) {
5100
5100
  });
5101
5101
  if (!gl) return null;
5102
5102
  if (!gl.getExtension("EXT_color_buffer_float")) return null;
5103
- const { WebGLBackend } = await Promise.resolve().then(() => require("./webgl-CD3WK_Me.cjs"));
5103
+ const { WebGLBackend } = await Promise.resolve().then(() => require("./webgl-pbfUGDA6.cjs"));
5104
5104
  return new WebGLBackend(gl);
5105
5105
  } else throw new Error(`Backend not found: ${device}`);
5106
5106
  }
package/dist/index.cjs CHANGED
@@ -30,7 +30,7 @@ var __toESM = (mod$1, isNodeMode, target) => (target = mod$1 != null ? __create(
30
30
  }) : target, mod$1));
31
31
 
32
32
  //#endregion
33
- const require_backend = require('./backend-x-6vqzIM.cjs');
33
+ const require_backend = require('./backend-DMyuoWi2.cjs');
34
34
 
35
35
  //#region src/frontend/convolution.ts
36
36
  /**
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { __export } from "./chunk-Cl8Af3a2.js";
2
- import { AluExp, AluGroup, AluOp, AluVar, DEBUG, DType, FpHash, Kernel, PPrint, Reduction, Routine, Routines, ShapeTracker, accessorAluExp, accessorGlobal, assertNonNull, byteWidth, checkAxis, checkInts, deepEqual, defaultDevice, devices, dtypedArray, dtypedJsArray, generalBroadcast, getBackend, getWebGPUDevice, init, invertPermutation, isFloatDtype, isNumberPair, isPermutation, normalizeAxis, partitionList, prod, promoteTypes, range, recursiveFlatten, rep, runWithCache, setDebug, startTrace, stopTrace, toposort, unravelAlu, unzip2, zip, zipn } from "./backend-DI-V78Rk.js";
2
+ import { AluExp, AluGroup, AluOp, AluVar, DEBUG, DType, FpHash, Kernel, PPrint, Reduction, Routine, Routines, ShapeTracker, accessorAluExp, accessorGlobal, assertNonNull, byteWidth, checkAxis, checkInts, deepEqual, defaultDevice, devices, dtypedArray, dtypedJsArray, generalBroadcast, getBackend, getWebGPUDevice, init, invertPermutation, isFloatDtype, isNumberPair, isPermutation, normalizeAxis, partitionList, prod, promoteTypes, range, recursiveFlatten, rep, runWithCache, setDebug, startTrace, stopTrace, toposort, unravelAlu, unzip2, zip, zipn } from "./backend-DLEk-B3V.js";
3
3
 
4
4
  //#region src/frontend/convolution.ts
5
5
  /**
@@ -1,4 +1,4 @@
1
- import { AluGroup, AluOp, DEBUG, DType, Executable, SlotError, UnsupportedOpError, UnsupportedRoutineError, isFloatDtype, range, strip1, tuneNullopt } from "./backend-DI-V78Rk.js";
1
+ import { AluGroup, AluOp, DEBUG, DType, Executable, SlotError, UnsupportedOpError, UnsupportedRoutineError, isFloatDtype, range, strip1, tuneNullopt } from "./backend-DLEk-B3V.js";
2
2
 
3
3
  //#region src/backend/webgl/builtins.ts
4
4
  const threefrySrc = `
@@ -1,4 +1,4 @@
1
- const require_backend = require('./backend-x-6vqzIM.cjs');
1
+ const require_backend = require('./backend-DMyuoWi2.cjs');
2
2
 
3
3
  //#region src/backend/webgl/builtins.ts
4
4
  const threefrySrc = `
@@ -1,4 +1,4 @@
1
- const require_backend = require('./backend-x-6vqzIM.cjs');
1
+ const require_backend = require('./backend-DMyuoWi2.cjs');
2
2
 
3
3
  //#region src/backend/webgpu/builtins.ts
4
4
  const threefrySrc = `
@@ -1099,6 +1099,8 @@ function flushTracingBatch(device, batch) {
1099
1099
 
1100
1100
  //#endregion
1101
1101
  //#region src/backend/webgpu.ts
1102
+ const MAX_REUSABLE_BUFFER_BYTES = 64 * 1024 * 1024;
1103
+ const MAX_REUSABLE_BUFFERS_PER_SIZE = 64;
1102
1104
  /** Implementation of `Backend` that uses WebGPU in browsers. */
1103
1105
  var WebGPUBackend = class {
1104
1106
  type = "webgpu";
@@ -1109,6 +1111,7 @@ var WebGPUBackend = class {
1109
1111
  nextSlot;
1110
1112
  #cachedShaderMap = /* @__PURE__ */ new Map();
1111
1113
  #reusableZsb;
1114
+ #bufferPool = /* @__PURE__ */ new Map();
1112
1115
  constructor(device) {
1113
1116
  this.device = device;
1114
1117
  if (require_backend.DEBUG >= 3 && device.adapterInfo) console.info("webgpu adapter:", device.adapterInfo.vendor, device.adapterInfo.architecture);
@@ -1123,31 +1126,22 @@ var WebGPUBackend = class {
1123
1126
  });
1124
1127
  }
1125
1128
  malloc(size, initialData) {
1126
- let buffer;
1127
- const paddedSize = Math.ceil(size / 4) * 4;
1128
- if (size === 0) buffer = this.#reusableZsb;
1129
- else if (initialData) {
1130
- if (initialData.byteLength !== size) throw new Error("initialData size does not match buffer size");
1131
- if (initialData.byteLength < 4096) {
1132
- buffer = this.#createBuffer(paddedSize, { mapped: true });
1133
- new Uint8Array(buffer.getMappedRange(), 0, size).set(initialData);
1134
- buffer.unmap();
1135
- } else {
1136
- buffer = this.#createBuffer(paddedSize);
1137
- if (initialData.byteLength % 4 === 0) this.device.queue.writeBuffer(buffer, 0, initialData);
1138
- else {
1139
- const aligned = initialData.byteLength - initialData.byteLength % 4;
1140
- this.device.queue.writeBuffer(buffer, 0, initialData, 0, aligned);
1141
- const remainder = new Uint8Array(4);
1142
- remainder.set(initialData.subarray(aligned));
1143
- this.device.queue.writeBuffer(buffer, aligned, remainder);
1144
- }
1145
- }
1146
- } else buffer = this.#createBuffer(paddedSize);
1129
+ if (initialData && initialData.byteLength !== size) throw new Error("initialData size does not match buffer size");
1130
+ const allocatedSize = Math.ceil(size / 4) * 4 || 4;
1131
+ const buffer = size === 0 ? this.#reusableZsb : this.#acquireBuffer(allocatedSize);
1132
+ if (initialData && size > 0) if (initialData.byteLength % 4 === 0) this.device.queue.writeBuffer(buffer, 0, initialData);
1133
+ else {
1134
+ const aligned = initialData.byteLength - initialData.byteLength % 4;
1135
+ if (aligned > 0) this.device.queue.writeBuffer(buffer, 0, initialData, 0, aligned);
1136
+ const remainder = new Uint8Array(4);
1137
+ remainder.set(initialData.subarray(aligned));
1138
+ this.device.queue.writeBuffer(buffer, aligned, remainder);
1139
+ }
1147
1140
  const slot = this.nextSlot++;
1148
1141
  this.buffers.set(slot, {
1149
1142
  buffer,
1150
1143
  size,
1144
+ allocatedSize,
1151
1145
  ref: 1
1152
1146
  });
1153
1147
  return slot;
@@ -1163,7 +1157,7 @@ var WebGPUBackend = class {
1163
1157
  buffer.ref--;
1164
1158
  if (buffer.ref === 0) {
1165
1159
  this.buffers.delete(slot);
1166
- if (buffer.buffer !== this.#reusableZsb) buffer.buffer.destroy();
1160
+ if (buffer.buffer !== this.#reusableZsb) this.#releaseBuffer(buffer.buffer, buffer.allocatedSize);
1167
1161
  }
1168
1162
  }
1169
1163
  async read(slot, start, count) {
@@ -1251,6 +1245,29 @@ var WebGPUBackend = class {
1251
1245
  size: buffer.size
1252
1246
  };
1253
1247
  }
1248
+ #acquireBuffer(size) {
1249
+ if (size > MAX_REUSABLE_BUFFER_BYTES) return this.#createBuffer(size);
1250
+ const bucket = this.#bufferPool.get(size);
1251
+ const buffer = bucket?.pop();
1252
+ if (bucket && bucket.length === 0) this.#bufferPool.delete(size);
1253
+ return buffer ?? this.#createBuffer(size);
1254
+ }
1255
+ #releaseBuffer(buffer, size) {
1256
+ if (size > MAX_REUSABLE_BUFFER_BYTES) {
1257
+ buffer.destroy();
1258
+ return;
1259
+ }
1260
+ const bucket = this.#bufferPool.get(size);
1261
+ if (!bucket) {
1262
+ this.#bufferPool.set(size, [buffer]);
1263
+ return;
1264
+ }
1265
+ if (bucket.length >= MAX_REUSABLE_BUFFERS_PER_SIZE) {
1266
+ buffer.destroy();
1267
+ return;
1268
+ }
1269
+ bucket.push(buffer);
1270
+ }
1254
1271
  /**
1255
1272
  * Create a GPU buffer.
1256
1273
  *
@@ -1,4 +1,4 @@
1
- import { AluExp, AluGroup, AluOp, DEBUG, DType, Executable, FpHash, Routines, SlotError, UnsupportedOpError, UnsupportedRoutineError, emitTrace, findPow2, isFloatDtype, isTracing, mapSetUnion, onFlushTrace, prod, range, strip1, traceSourceInfo, tuneWebgpu } from "./backend-DI-V78Rk.js";
1
+ import { AluExp, AluGroup, AluOp, DEBUG, DType, Executable, FpHash, Routines, SlotError, UnsupportedOpError, UnsupportedRoutineError, emitTrace, findPow2, isFloatDtype, isTracing, mapSetUnion, onFlushTrace, prod, range, strip1, traceSourceInfo, tuneWebgpu } from "./backend-DLEk-B3V.js";
2
2
 
3
3
  //#region src/backend/webgpu/builtins.ts
4
4
  const threefrySrc = `
@@ -1099,6 +1099,8 @@ function flushTracingBatch(device, batch) {
1099
1099
 
1100
1100
  //#endregion
1101
1101
  //#region src/backend/webgpu.ts
1102
+ const MAX_REUSABLE_BUFFER_BYTES = 64 * 1024 * 1024;
1103
+ const MAX_REUSABLE_BUFFERS_PER_SIZE = 64;
1102
1104
  /** Implementation of `Backend` that uses WebGPU in browsers. */
1103
1105
  var WebGPUBackend = class {
1104
1106
  type = "webgpu";
@@ -1109,6 +1111,7 @@ var WebGPUBackend = class {
1109
1111
  nextSlot;
1110
1112
  #cachedShaderMap = /* @__PURE__ */ new Map();
1111
1113
  #reusableZsb;
1114
+ #bufferPool = /* @__PURE__ */ new Map();
1112
1115
  constructor(device) {
1113
1116
  this.device = device;
1114
1117
  if (DEBUG >= 3 && device.adapterInfo) console.info("webgpu adapter:", device.adapterInfo.vendor, device.adapterInfo.architecture);
@@ -1123,31 +1126,22 @@ var WebGPUBackend = class {
1123
1126
  });
1124
1127
  }
1125
1128
  malloc(size, initialData) {
1126
- let buffer;
1127
- const paddedSize = Math.ceil(size / 4) * 4;
1128
- if (size === 0) buffer = this.#reusableZsb;
1129
- else if (initialData) {
1130
- if (initialData.byteLength !== size) throw new Error("initialData size does not match buffer size");
1131
- if (initialData.byteLength < 4096) {
1132
- buffer = this.#createBuffer(paddedSize, { mapped: true });
1133
- new Uint8Array(buffer.getMappedRange(), 0, size).set(initialData);
1134
- buffer.unmap();
1135
- } else {
1136
- buffer = this.#createBuffer(paddedSize);
1137
- if (initialData.byteLength % 4 === 0) this.device.queue.writeBuffer(buffer, 0, initialData);
1138
- else {
1139
- const aligned = initialData.byteLength - initialData.byteLength % 4;
1140
- this.device.queue.writeBuffer(buffer, 0, initialData, 0, aligned);
1141
- const remainder = new Uint8Array(4);
1142
- remainder.set(initialData.subarray(aligned));
1143
- this.device.queue.writeBuffer(buffer, aligned, remainder);
1144
- }
1145
- }
1146
- } else buffer = this.#createBuffer(paddedSize);
1129
+ if (initialData && initialData.byteLength !== size) throw new Error("initialData size does not match buffer size");
1130
+ const allocatedSize = Math.ceil(size / 4) * 4 || 4;
1131
+ const buffer = size === 0 ? this.#reusableZsb : this.#acquireBuffer(allocatedSize);
1132
+ if (initialData && size > 0) if (initialData.byteLength % 4 === 0) this.device.queue.writeBuffer(buffer, 0, initialData);
1133
+ else {
1134
+ const aligned = initialData.byteLength - initialData.byteLength % 4;
1135
+ if (aligned > 0) this.device.queue.writeBuffer(buffer, 0, initialData, 0, aligned);
1136
+ const remainder = new Uint8Array(4);
1137
+ remainder.set(initialData.subarray(aligned));
1138
+ this.device.queue.writeBuffer(buffer, aligned, remainder);
1139
+ }
1147
1140
  const slot = this.nextSlot++;
1148
1141
  this.buffers.set(slot, {
1149
1142
  buffer,
1150
1143
  size,
1144
+ allocatedSize,
1151
1145
  ref: 1
1152
1146
  });
1153
1147
  return slot;
@@ -1163,7 +1157,7 @@ var WebGPUBackend = class {
1163
1157
  buffer.ref--;
1164
1158
  if (buffer.ref === 0) {
1165
1159
  this.buffers.delete(slot);
1166
- if (buffer.buffer !== this.#reusableZsb) buffer.buffer.destroy();
1160
+ if (buffer.buffer !== this.#reusableZsb) this.#releaseBuffer(buffer.buffer, buffer.allocatedSize);
1167
1161
  }
1168
1162
  }
1169
1163
  async read(slot, start, count) {
@@ -1251,6 +1245,29 @@ var WebGPUBackend = class {
1251
1245
  size: buffer.size
1252
1246
  };
1253
1247
  }
1248
+ #acquireBuffer(size) {
1249
+ if (size > MAX_REUSABLE_BUFFER_BYTES) return this.#createBuffer(size);
1250
+ const bucket = this.#bufferPool.get(size);
1251
+ const buffer = bucket?.pop();
1252
+ if (bucket && bucket.length === 0) this.#bufferPool.delete(size);
1253
+ return buffer ?? this.#createBuffer(size);
1254
+ }
1255
+ #releaseBuffer(buffer, size) {
1256
+ if (size > MAX_REUSABLE_BUFFER_BYTES) {
1257
+ buffer.destroy();
1258
+ return;
1259
+ }
1260
+ const bucket = this.#bufferPool.get(size);
1261
+ if (!bucket) {
1262
+ this.#bufferPool.set(size, [buffer]);
1263
+ return;
1264
+ }
1265
+ if (bucket.length >= MAX_REUSABLE_BUFFERS_PER_SIZE) {
1266
+ buffer.destroy();
1267
+ return;
1268
+ }
1269
+ bucket.push(buffer);
1270
+ }
1254
1271
  /**
1255
1272
  * Create a GPU buffer.
1256
1273
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jax-js/jax",
3
- "version": "0.1.12",
3
+ "version": "0.1.13",
4
4
  "description": "Numerical computing and ML in the browser",
5
5
  "keywords": [
6
6
  "machine learning",