@cosyte/bench 0.1.1 → 0.1.2

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/dist/index.d.ts CHANGED
@@ -59,6 +59,20 @@ interface BenchContractShape {
59
59
  readonly GC_MAX_ROUNDS: number;
60
60
  /** Fresh processes timed for the cold import, for the target and for an empty module each. */
61
61
  readonly IMPORT_RUNS: number;
62
+ /**
63
+ * A case whose last three warmup batches each took at least this many milliseconds a pass runs on
64
+ * the large-case plan: every batch is one pass, so the warmup rule's aggregation cannot happen.
65
+ */
66
+ readonly LARGE_PASS_MS: number;
67
+ /** Passes in each of the two windows whose medians the large-case warmup compares. */
68
+ readonly LARGE_WARMUP_WINDOW: number;
69
+ /** Hard cap on the large-case warmup, in milliseconds, from the start of the warmup. */
70
+ readonly LARGE_WARMUP_MAX_MS: number;
71
+ /**
72
+ * The long run also runs on a benchmark's largest size whose rounds fit in this many milliseconds,
73
+ * a round being at least one pass.
74
+ */
75
+ readonly LONG_RUN_MAX_MS: number;
62
76
  /** The timing comparison may become a required check when A/A false alarms are under this rate. */
63
77
  readonly REQUIRED_FALSE_ALARM_RATE: number;
64
78
  /** The confidence that the false alarm rate is under the line, for the rule above. */
@@ -199,16 +213,27 @@ declare const WARMUP: Readonly<{
199
213
  STABLE_TOL: number;
200
214
  STABLE_BATCHES: number;
201
215
  }>;
216
+ /**
217
+ * Which warmup rule a process ended on. `standard` is ADR 0001 section 2's. `large` is the
218
+ * large-case plan, for a case whose every batch is a single pass: see {@link warmUp}.
219
+ */
220
+ type WarmupPlan = "standard" | "large";
202
221
  /** What the warmup did. */
203
222
  interface WarmupReport {
204
- /** Whether three batches in a row came within 5% of their median before 5 s ran out. */
223
+ /**
224
+ * Whether the warmup settled: on the standard plan, three batches in a row within 5% of their
225
+ * median before 5 s ran out; on the large-case plan, two windows of passes with medians within 5%
226
+ * of each other before 30 s ran out.
227
+ */
205
228
  readonly stable: boolean;
206
229
  /** Wall time spent warming, in milliseconds. */
207
230
  readonly elapsedMs: number;
208
231
  /** Passes over the corpus. */
209
232
  readonly passes: number;
210
- /** Each batch's milliseconds per pass. */
233
+ /** Each batch's milliseconds per pass. On the large-case plan every batch after the switch is one pass. */
211
234
  readonly batches: readonly number[];
235
+ /** The rule the warmup ended on. */
236
+ readonly plan: WarmupPlan;
212
237
  }
213
238
  /** Per-call latency, or why there is none. */
214
239
  type LatencyReport = {
@@ -235,16 +260,32 @@ type LatencyReport = {
235
260
  *
236
261
  * They read the heap through a {@link HeapProbe}, so their tests can drive them with a scripted heap.
237
262
  * The real probe follows ADR 0001 section 8: a zero-argument `gc()` only, settled by rule rather than
238
- * by a count.
263
+ * by a count. The measuring process also runs with `--no-concurrent-array-buffer-sweeping`, so a
264
+ * collection frees the ArrayBuffers it found dead before it ends, and the external memory a
265
+ * collection reports before and after is what it held and what it kept.
239
266
  *
240
267
  * @packageDocumentation
241
268
  */
242
269
 
243
- /** Why a memory measurement has no number. */
270
+ /**
271
+ * Why a memory measurement has no number. `allocation-window-gc` is no longer written: a case whose
272
+ * every window collects is now counted with its collections. It stays here because documents
273
+ * written before carry it.
274
+ */
244
275
  type MemorySkipReason = "gc-unavailable" | "gc-unsettled" | "allocation-window-gc";
276
+ /**
277
+ * How allocations were counted. `no-gc-window`: the heap's growth over windows in which no
278
+ * collection ran. `gc-accounted`: every window collected, so the growth over each window plus what
279
+ * its collections reclaimed.
280
+ */
281
+ type AllocationMethod = "no-gc-window" | "gc-accounted";
245
282
  /** Allocations per operation. */
246
283
  type AllocationReport = {
247
284
  readonly status: "measured";
285
+ /** How they were counted. Absent in a document written before it was recorded: `no-gc-window`. */
286
+ readonly method?: AllocationMethod;
287
+ /** Collections that ran in the two windows counted: 0 for `no-gc-window`. */
288
+ readonly collections?: number;
248
289
  /** The smaller of the two windows, in operations. */
249
290
  readonly windowOps: number;
250
291
  /** Bytes allocated on the V8 heap per operation. */
@@ -255,14 +296,29 @@ type AllocationReport = {
255
296
  readonly status: "skipped";
256
297
  readonly reason: MemorySkipReason;
257
298
  };
258
- /** Peak heap per call. */
299
+ /** Peak memory per call: the V8 heap, external memory, and the two together. */
259
300
  type PeakReport = {
260
301
  readonly status: "measured";
261
302
  readonly calls: number;
262
- /** The highest peak of any call, in bytes above the settled heap before it. */
303
+ /** The highest V8 heap peak of any call, in bytes above the settled heap before it. */
263
304
  readonly peakHeapBytes: number;
264
- /** The median call's peak. */
305
+ /** The median call's V8 heap peak. */
265
306
  readonly medianPeakHeapBytes: number;
307
+ /**
308
+ * The highest external peak of any call (Buffers, ArrayBuffers), above the external memory
309
+ * held before it. Absent in a document written before external memory was read.
310
+ */
311
+ readonly peakExternalBytes?: number;
312
+ /** The median call's external peak. */
313
+ readonly medianPeakExternalBytes?: number;
314
+ /**
315
+ * The highest peak of the V8 heap and external memory together, above the two before the call:
316
+ * the figure a memory budget reads. Not the sum of the two peaks above, which need not come at
317
+ * one moment.
318
+ */
319
+ readonly peakTotalBytes?: number;
320
+ /** The median call's peak of the two together. */
321
+ readonly medianPeakTotalBytes?: number;
266
322
  } | {
267
323
  readonly status: "skipped";
268
324
  readonly reason: MemorySkipReason;
@@ -356,6 +412,13 @@ interface CaseComparison extends CaseRef {
356
412
  readonly baseSamples: readonly (readonly number[])[];
357
413
  /** Each round's head samples, whole. */
358
414
  readonly headSamples: readonly (readonly number[])[];
415
+ /**
416
+ * Each round's base process: the warmup rule it ended on. Absent in a document written before it
417
+ * was recorded.
418
+ */
419
+ readonly basePlans?: readonly WarmupPlan[];
420
+ /** Each round's head process: the warmup rule it ended on. */
421
+ readonly headPlans?: readonly WarmupPlan[];
359
422
  /** Each round's `head / base`. */
360
423
  readonly ratios: readonly number[];
361
424
  readonly medianRatio: number | null;
@@ -474,6 +537,8 @@ type Throughput = {
474
537
  readonly processes: readonly {
475
538
  readonly samplesMsPerOp: readonly number[];
476
539
  readonly medianMsPerOp: number;
540
+ /** The warmup rule the process ended on. Absent in a document written before it was recorded. */
541
+ readonly plan?: WarmupPlan;
477
542
  }[];
478
543
  /** The median of the process medians. */
479
544
  readonly medianMsPerOp: number;
@@ -832,6 +897,18 @@ declare const RESULTS_SCHEMA: {
832
897
  readonly medianRatio: {
833
898
  readonly type: readonly ["number", "null"];
834
899
  };
900
+ readonly basePlans: {
901
+ readonly type: "array";
902
+ readonly items: {
903
+ readonly enum: readonly ["standard", "large"];
904
+ };
905
+ };
906
+ readonly headPlans: {
907
+ readonly type: "array";
908
+ readonly items: {
909
+ readonly enum: readonly ["standard", "large"];
910
+ };
911
+ };
835
912
  readonly interval: {
836
913
  readonly $ref: "#/$defs/interval";
837
914
  };
package/dist/index.mjs CHANGED
@@ -29,6 +29,10 @@ var BENCH_CONTRACT = Object.freeze({
29
29
  GC_SETTLE_ROUNDS: 2,
30
30
  GC_MAX_ROUNDS: 7,
31
31
  IMPORT_RUNS: 20,
32
+ LARGE_PASS_MS: 50,
33
+ LARGE_WARMUP_WINDOW: 5,
34
+ LARGE_WARMUP_MAX_MS: 3e4,
35
+ LONG_RUN_MAX_MS: 6e4,
32
36
  REQUIRED_FALSE_ALARM_RATE: 0.01,
33
37
  REQUIRED_CONFIDENCE: 0.95
34
38
  });
@@ -151,6 +155,7 @@ var skipped = {
151
155
  properties: { status: { const: "skipped" }, reason: str }
152
156
  };
153
157
  var measuredOrSkipped = (measured) => ({ oneOf: [measured, skipped] });
158
+ var plan = { enum: ["standard", "large"] };
154
159
  var orNull = (s) => ({ oneOf: [{ type: "null" }, s] });
155
160
  var RESULTS_SCHEMA = {
156
161
  $schema: "https://json-schema.org/draft/2020-12/schema",
@@ -267,6 +272,9 @@ var RESULTS_SCHEMA = {
267
272
  headMsPerOp: nums,
268
273
  ratios: nums,
269
274
  medianRatio: numOrNull,
275
+ // Added within version 1, so not required: a document written before them is still valid.
276
+ basePlans: { type: "array", items: plan },
277
+ headPlans: { type: "array", items: plan },
270
278
  interval: { $ref: "#/$defs/interval" },
271
279
  verdict: {
272
280
  enum: ["regression", "improvement", "no-regression", "inconclusive", "skipped"]
@@ -396,7 +404,8 @@ var RESULTS_SCHEMA = {
396
404
  items: {
397
405
  type: "object",
398
406
  required: ["samplesMsPerOp", "medianMsPerOp"],
399
- properties: { samplesMsPerOp: nums, medianMsPerOp: num }
407
+ // `plan` was added within version 1, so it is not required.
408
+ properties: { samplesMsPerOp: nums, medianMsPerOp: num, plan }
400
409
  }
401
410
  },
402
411
  medianMsPerOp: num,
@@ -423,6 +432,9 @@ var RESULTS_SCHEMA = {
423
432
  required: ["status", "windowOps", "heapBytesPerOp", "externalBytesPerOp"],
424
433
  properties: {
425
434
  status: { const: "measured" },
435
+ // Added within version 1, so not required.
436
+ method: { enum: ["no-gc-window", "gc-accounted"] },
437
+ collections: int,
426
438
  windowOps: int,
427
439
  heapBytesPerOp: num,
428
440
  externalBytesPerOp: num
@@ -437,7 +449,12 @@ var RESULTS_SCHEMA = {
437
449
  status: { const: "measured" },
438
450
  calls: int,
439
451
  peakHeapBytes: num,
440
- medianPeakHeapBytes: num
452
+ medianPeakHeapBytes: num,
453
+ // Added within version 1, so not required.
454
+ peakExternalBytes: num,
455
+ medianPeakExternalBytes: num,
456
+ peakTotalBytes: num,
457
+ medianPeakTotalBytes: num
441
458
  }
442
459
  })
443
460
  ),