overtake 1.1.3 → 1.1.4

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.
@@ -17,6 +17,7 @@ _export(exports, {
17
17
  }
18
18
  });
19
19
  const _utilscjs = require("./utils.cjs");
20
+ const _typescjs = require("./types.cjs");
20
21
  const units = [
21
22
  {
22
23
  unit: 'ns',
@@ -91,17 +92,17 @@ const createReport = (durations, type)=>{
91
92
  switch(type){
92
93
  case 'min':
93
94
  {
94
- return new Report(type, durations[0]);
95
+ return new Report(type, durations[0], 0, _typescjs.DURATION_SCALE);
95
96
  }
96
97
  case 'max':
97
98
  {
98
- return new Report(type, durations[n - 1]);
99
+ return new Report(type, durations[n - 1], 0, _typescjs.DURATION_SCALE);
99
100
  }
100
101
  case 'median':
101
102
  {
102
103
  const mid = Math.floor(n / 2);
103
104
  const med = n % 2 === 0 ? (durations[mid - 1] + durations[mid]) / 2n : durations[mid];
104
- return new Report(type, med);
105
+ return new Report(type, med, 0, _typescjs.DURATION_SCALE);
105
106
  }
106
107
  case 'mode':
107
108
  {
@@ -124,7 +125,7 @@ const createReport = (durations, type)=>{
124
125
  if (lastIdx < n - 1) upper = durations[lastIdx + 1];
125
126
  const gap = (0, _utilscjs.max)(modeVal - lower, upper - modeVal);
126
127
  const uncertainty = modeVal > 0 ? Number(gap / 2n * 100n / modeVal) : 0;
127
- return new Report(type, modeVal, uncertainty);
128
+ return new Report(type, modeVal, uncertainty, _typescjs.DURATION_SCALE);
128
129
  }
129
130
  case 'ops':
130
131
  {
@@ -132,15 +133,15 @@ const createReport = (durations, type)=>{
132
133
  for (const duration of durations){
133
134
  sum += duration;
134
135
  }
135
- const avgNs = sum / BigInt(n);
136
- const nsPerSec = 1_000_000_000n;
137
- const raw = Number(nsPerSec) / Number(avgNs);
136
+ const avgScaled = sum / BigInt(n);
137
+ const nsPerSecScaled = 1_000_000_000n * _typescjs.DURATION_SCALE;
138
+ const raw = Number(nsPerSecScaled) / Number(avgScaled);
138
139
  const extra = raw < 1 ? Math.ceil(-Math.log10(raw)) : 0;
139
140
  const exp = raw > 100 ? 0 : 2 + extra;
140
141
  const scale = 10n ** BigInt(exp);
141
- const value = avgNs > 0n ? nsPerSec * scale / avgNs : 0n;
142
+ const value = avgScaled > 0n ? nsPerSecScaled * scale / avgScaled : 0n;
142
143
  const deviation = durations[n - 1] - durations[0];
143
- const uncertainty = avgNs > 0 ? Number((0, _utilscjs.div)(deviation * scale, 2n * avgNs)) : 0;
144
+ const uncertainty = avgScaled > 0 ? Number((0, _utilscjs.div)(deviation * scale, 2n * avgScaled)) : 0;
144
145
  return new Report(type, value, uncertainty, scale);
145
146
  }
146
147
  case 'mean':
@@ -150,16 +151,16 @@ const createReport = (durations, type)=>{
150
151
  sum += duration;
151
152
  }
152
153
  const value = (0, _utilscjs.divs)(sum, BigInt(n), 1n);
153
- return new Report(type, value);
154
+ return new Report(type, value, 0, _typescjs.DURATION_SCALE);
154
155
  }
155
156
  default:
156
157
  {
157
158
  const p = Number(type.slice(1));
158
159
  if (p === 0) {
159
- return new Report(type, durations[0]);
160
+ return new Report(type, durations[0], 0, _typescjs.DURATION_SCALE);
160
161
  }
161
162
  if (p === 100) {
162
- return new Report(type, durations[n - 1]);
163
+ return new Report(type, durations[n - 1], 0, _typescjs.DURATION_SCALE);
163
164
  }
164
165
  const idx = Math.ceil(p / 100 * n) - 1;
165
166
  const value = durations[Math.min(Math.max(idx, 0), n - 1)];
@@ -167,7 +168,7 @@ const createReport = (durations, type)=>{
167
168
  const next = idx < n - 1 ? durations[idx + 1] : value;
168
169
  const gap = (0, _utilscjs.max)(value - prev, next - value);
169
170
  const uncertainty = value > 0 ? Number((0, _utilscjs.div)((0, _utilscjs.divs)(gap, 2n, 100_00n), value)) / 100 : 0;
170
- return new Report(type, value, uncertainty);
171
+ return new Report(type, value, uncertainty, _typescjs.DURATION_SCALE);
171
172
  }
172
173
  }
173
174
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/reporter.ts"],"sourcesContent":["import { div, max, divs } from './utils.js';\nimport { ReportType } from './types.js';\n\nconst units = [\n { unit: 'ns', factor: 1 },\n { unit: 'µs', factor: 1e3 },\n { unit: 'ms', factor: 1e6 },\n { unit: 's', factor: 1e9 },\n { unit: 'm', factor: 60 * 1e9 },\n { unit: 'h', factor: 3600 * 1e9 },\n] as const;\n\nfunction smartFixed(n: number): string {\n return n.toLocaleString(undefined, {\n minimumFractionDigits: 0,\n maximumFractionDigits: 2,\n useGrouping: true,\n });\n}\nexport class Report {\n constructor(\n public readonly type: ReportType,\n public readonly value: bigint,\n public readonly uncertainty: number = 0,\n public readonly scale: bigint = 1n,\n ) {}\n valueOf() {\n return Number(div(this.value, this.scale));\n }\n toString() {\n const uncertainty = this.uncertainty ? ` ± ${smartFixed(this.uncertainty)}%` : '';\n\n const value = this.valueOf();\n if (this.type === 'ops') {\n return `${smartFixed(value)} ops/s${uncertainty}`;\n }\n let display = value;\n let unit = 'ns';\n\n for (const { unit: u, factor } of units) {\n const candidate = value / factor;\n if (candidate < 1000) {\n display = candidate;\n unit = u;\n break;\n }\n }\n return `${smartFixed(display)} ${unit}${uncertainty}`;\n }\n}\n\nexport const createReport = (durations: BigUint64Array, type: ReportType): Report => {\n const n = durations.length;\n if (n === 0) {\n return new Report(type, 0n);\n }\n switch (type) {\n case 'min': {\n return new Report(type, durations[0]);\n }\n case 'max': {\n return new Report(type, durations[n - 1]);\n }\n case 'median': {\n const mid = Math.floor(n / 2);\n const med = n % 2 === 0 ? (durations[mid - 1] + durations[mid]) / 2n : durations[mid];\n return new Report(type, med);\n }\n\n case 'mode': {\n const freq = new Map<bigint, bigint>();\n let maxCount = 0n;\n let modeVal = durations[0];\n for (const d of durations) {\n const count = (freq.get(d) || 0n) + 1n;\n freq.set(d, count);\n if (count > maxCount) {\n maxCount = count;\n modeVal = d;\n }\n }\n let lower = modeVal;\n let upper = modeVal;\n const firstIdx = durations.indexOf(modeVal);\n const lastIdx = durations.lastIndexOf(modeVal);\n if (firstIdx > 0) lower = durations[firstIdx - 1];\n if (lastIdx < n - 1) upper = durations[lastIdx + 1];\n const gap = max(modeVal - lower, upper - modeVal);\n const uncertainty = modeVal > 0 ? Number(((gap / 2n) * 100n) / modeVal) : 0;\n return new Report(type, modeVal, uncertainty);\n }\n\n case 'ops': {\n let sum = 0n;\n for (const duration of durations) {\n sum += duration;\n }\n const avgNs = sum / BigInt(n);\n const nsPerSec = 1_000_000_000n;\n const raw = Number(nsPerSec) / Number(avgNs);\n const extra = raw < 1 ? Math.ceil(-Math.log10(raw)) : 0;\n\n const exp = raw > 100 ? 0 : 2 + extra;\n\n const scale = 10n ** BigInt(exp);\n\n const value = avgNs > 0n ? (nsPerSec * scale) / avgNs : 0n;\n const deviation = durations[n - 1] - durations[0];\n const uncertainty = avgNs > 0 ? Number(div(deviation * scale, 2n * avgNs)) : 0;\n return new Report(type, value, uncertainty, scale);\n }\n case 'mean': {\n let sum = 0n;\n for (const duration of durations) {\n sum += duration;\n }\n const value = divs(sum, BigInt(n), 1n);\n return new Report(type, value);\n }\n\n default: {\n const p = Number(type.slice(1));\n if (p === 0) {\n return new Report(type, durations[0]);\n }\n if (p === 100) {\n return new Report(type, durations[n - 1]);\n }\n const idx = Math.ceil((p / 100) * n) - 1;\n const value = durations[Math.min(Math.max(idx, 0), n - 1)];\n const prev = idx > 0 ? durations[idx - 1] : value;\n const next = idx < n - 1 ? durations[idx + 1] : value;\n const gap = max(value - prev, next - value);\n const uncertainty = value > 0 ? Number(div(divs(gap, 2n, 100_00n), value)) / 100 : 0;\n\n return new Report(type, value, uncertainty);\n }\n }\n};\n"],"names":["Report","createReport","units","unit","factor","smartFixed","n","toLocaleString","undefined","minimumFractionDigits","maximumFractionDigits","useGrouping","type","value","uncertainty","scale","valueOf","Number","div","toString","display","u","candidate","durations","length","mid","Math","floor","med","freq","Map","maxCount","modeVal","d","count","get","set","lower","upper","firstIdx","indexOf","lastIdx","lastIndexOf","gap","max","sum","duration","avgNs","BigInt","nsPerSec","raw","extra","ceil","log10","exp","deviation","divs","p","slice","idx","min","prev","next"],"mappings":"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"}
1
+ {"version":3,"sources":["../src/reporter.ts"],"sourcesContent":["import { div, max, divs } from './utils.js';\nimport { ReportType, DURATION_SCALE } from './types.js';\n\nconst units = [\n { unit: 'ns', factor: 1 },\n { unit: 'µs', factor: 1e3 },\n { unit: 'ms', factor: 1e6 },\n { unit: 's', factor: 1e9 },\n { unit: 'm', factor: 60 * 1e9 },\n { unit: 'h', factor: 3600 * 1e9 },\n] as const;\n\nfunction smartFixed(n: number): string {\n return n.toLocaleString(undefined, {\n minimumFractionDigits: 0,\n maximumFractionDigits: 2,\n useGrouping: true,\n });\n}\nexport class Report {\n constructor(\n public readonly type: ReportType,\n public readonly value: bigint,\n public readonly uncertainty: number = 0,\n public readonly scale: bigint = 1n,\n ) {}\n valueOf() {\n return Number(div(this.value, this.scale));\n }\n toString() {\n const uncertainty = this.uncertainty ? ` ± ${smartFixed(this.uncertainty)}%` : '';\n\n const value = this.valueOf();\n if (this.type === 'ops') {\n return `${smartFixed(value)} ops/s${uncertainty}`;\n }\n let display = value;\n let unit = 'ns';\n\n for (const { unit: u, factor } of units) {\n const candidate = value / factor;\n if (candidate < 1000) {\n display = candidate;\n unit = u;\n break;\n }\n }\n return `${smartFixed(display)} ${unit}${uncertainty}`;\n }\n}\n\nexport const createReport = (durations: BigUint64Array, type: ReportType): Report => {\n const n = durations.length;\n if (n === 0) {\n return new Report(type, 0n);\n }\n switch (type) {\n case 'min': {\n return new Report(type, durations[0], 0, DURATION_SCALE);\n }\n case 'max': {\n return new Report(type, durations[n - 1], 0, DURATION_SCALE);\n }\n case 'median': {\n const mid = Math.floor(n / 2);\n const med = n % 2 === 0 ? (durations[mid - 1] + durations[mid]) / 2n : durations[mid];\n return new Report(type, med, 0, DURATION_SCALE);\n }\n\n case 'mode': {\n const freq = new Map<bigint, bigint>();\n let maxCount = 0n;\n let modeVal = durations[0];\n for (const d of durations) {\n const count = (freq.get(d) || 0n) + 1n;\n freq.set(d, count);\n if (count > maxCount) {\n maxCount = count;\n modeVal = d;\n }\n }\n let lower = modeVal;\n let upper = modeVal;\n const firstIdx = durations.indexOf(modeVal);\n const lastIdx = durations.lastIndexOf(modeVal);\n if (firstIdx > 0) lower = durations[firstIdx - 1];\n if (lastIdx < n - 1) upper = durations[lastIdx + 1];\n const gap = max(modeVal - lower, upper - modeVal);\n const uncertainty = modeVal > 0 ? Number(((gap / 2n) * 100n) / modeVal) : 0;\n return new Report(type, modeVal, uncertainty, DURATION_SCALE);\n }\n\n case 'ops': {\n let sum = 0n;\n for (const duration of durations) {\n sum += duration;\n }\n const avgScaled = sum / BigInt(n);\n const nsPerSecScaled = 1_000_000_000n * DURATION_SCALE;\n const raw = Number(nsPerSecScaled) / Number(avgScaled);\n const extra = raw < 1 ? Math.ceil(-Math.log10(raw)) : 0;\n\n const exp = raw > 100 ? 0 : 2 + extra;\n\n const scale = 10n ** BigInt(exp);\n\n const value = avgScaled > 0n ? (nsPerSecScaled * scale) / avgScaled : 0n;\n const deviation = durations[n - 1] - durations[0];\n const uncertainty = avgScaled > 0 ? Number(div(deviation * scale, 2n * avgScaled)) : 0;\n return new Report(type, value, uncertainty, scale);\n }\n case 'mean': {\n let sum = 0n;\n for (const duration of durations) {\n sum += duration;\n }\n const value = divs(sum, BigInt(n), 1n);\n return new Report(type, value, 0, DURATION_SCALE);\n }\n\n default: {\n const p = Number(type.slice(1));\n if (p === 0) {\n return new Report(type, durations[0], 0, DURATION_SCALE);\n }\n if (p === 100) {\n return new Report(type, durations[n - 1], 0, DURATION_SCALE);\n }\n const idx = Math.ceil((p / 100) * n) - 1;\n const value = durations[Math.min(Math.max(idx, 0), n - 1)];\n const prev = idx > 0 ? durations[idx - 1] : value;\n const next = idx < n - 1 ? durations[idx + 1] : value;\n const gap = max(value - prev, next - value);\n const uncertainty = value > 0 ? Number(div(divs(gap, 2n, 100_00n), value)) / 100 : 0;\n\n return new Report(type, value, uncertainty, DURATION_SCALE);\n }\n }\n};\n"],"names":["Report","createReport","units","unit","factor","smartFixed","n","toLocaleString","undefined","minimumFractionDigits","maximumFractionDigits","useGrouping","type","value","uncertainty","scale","valueOf","Number","div","toString","display","u","candidate","durations","length","DURATION_SCALE","mid","Math","floor","med","freq","Map","maxCount","modeVal","d","count","get","set","lower","upper","firstIdx","indexOf","lastIdx","lastIndexOf","gap","max","sum","duration","avgScaled","BigInt","nsPerSecScaled","raw","extra","ceil","log10","exp","deviation","divs","p","slice","idx","min","prev","next"],"mappings":"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"}
package/build/reporter.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { div, max, divs } from "./utils.js";
2
+ import { DURATION_SCALE } from "./types.js";
2
3
  const units = [
3
4
  {
4
5
  unit: 'ns',
@@ -73,17 +74,17 @@ export const createReport = (durations, type)=>{
73
74
  switch(type){
74
75
  case 'min':
75
76
  {
76
- return new Report(type, durations[0]);
77
+ return new Report(type, durations[0], 0, DURATION_SCALE);
77
78
  }
78
79
  case 'max':
79
80
  {
80
- return new Report(type, durations[n - 1]);
81
+ return new Report(type, durations[n - 1], 0, DURATION_SCALE);
81
82
  }
82
83
  case 'median':
83
84
  {
84
85
  const mid = Math.floor(n / 2);
85
86
  const med = n % 2 === 0 ? (durations[mid - 1] + durations[mid]) / 2n : durations[mid];
86
- return new Report(type, med);
87
+ return new Report(type, med, 0, DURATION_SCALE);
87
88
  }
88
89
  case 'mode':
89
90
  {
@@ -106,7 +107,7 @@ export const createReport = (durations, type)=>{
106
107
  if (lastIdx < n - 1) upper = durations[lastIdx + 1];
107
108
  const gap = max(modeVal - lower, upper - modeVal);
108
109
  const uncertainty = modeVal > 0 ? Number(gap / 2n * 100n / modeVal) : 0;
109
- return new Report(type, modeVal, uncertainty);
110
+ return new Report(type, modeVal, uncertainty, DURATION_SCALE);
110
111
  }
111
112
  case 'ops':
112
113
  {
@@ -114,15 +115,15 @@ export const createReport = (durations, type)=>{
114
115
  for (const duration of durations){
115
116
  sum += duration;
116
117
  }
117
- const avgNs = sum / BigInt(n);
118
- const nsPerSec = 1_000_000_000n;
119
- const raw = Number(nsPerSec) / Number(avgNs);
118
+ const avgScaled = sum / BigInt(n);
119
+ const nsPerSecScaled = 1_000_000_000n * DURATION_SCALE;
120
+ const raw = Number(nsPerSecScaled) / Number(avgScaled);
120
121
  const extra = raw < 1 ? Math.ceil(-Math.log10(raw)) : 0;
121
122
  const exp = raw > 100 ? 0 : 2 + extra;
122
123
  const scale = 10n ** BigInt(exp);
123
- const value = avgNs > 0n ? nsPerSec * scale / avgNs : 0n;
124
+ const value = avgScaled > 0n ? nsPerSecScaled * scale / avgScaled : 0n;
124
125
  const deviation = durations[n - 1] - durations[0];
125
- const uncertainty = avgNs > 0 ? Number(div(deviation * scale, 2n * avgNs)) : 0;
126
+ const uncertainty = avgScaled > 0 ? Number(div(deviation * scale, 2n * avgScaled)) : 0;
126
127
  return new Report(type, value, uncertainty, scale);
127
128
  }
128
129
  case 'mean':
@@ -132,16 +133,16 @@ export const createReport = (durations, type)=>{
132
133
  sum += duration;
133
134
  }
134
135
  const value = divs(sum, BigInt(n), 1n);
135
- return new Report(type, value);
136
+ return new Report(type, value, 0, DURATION_SCALE);
136
137
  }
137
138
  default:
138
139
  {
139
140
  const p = Number(type.slice(1));
140
141
  if (p === 0) {
141
- return new Report(type, durations[0]);
142
+ return new Report(type, durations[0], 0, DURATION_SCALE);
142
143
  }
143
144
  if (p === 100) {
144
- return new Report(type, durations[n - 1]);
145
+ return new Report(type, durations[n - 1], 0, DURATION_SCALE);
145
146
  }
146
147
  const idx = Math.ceil(p / 100 * n) - 1;
147
148
  const value = durations[Math.min(Math.max(idx, 0), n - 1)];
@@ -149,7 +150,7 @@ export const createReport = (durations, type)=>{
149
150
  const next = idx < n - 1 ? durations[idx + 1] : value;
150
151
  const gap = max(value - prev, next - value);
151
152
  const uncertainty = value > 0 ? Number(div(divs(gap, 2n, 100_00n), value)) / 100 : 0;
152
- return new Report(type, value, uncertainty);
153
+ return new Report(type, value, uncertainty, DURATION_SCALE);
153
154
  }
154
155
  }
155
156
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/reporter.ts"],"sourcesContent":["import { div, max, divs } from './utils.js';\nimport { ReportType } from './types.js';\n\nconst units = [\n { unit: 'ns', factor: 1 },\n { unit: 'µs', factor: 1e3 },\n { unit: 'ms', factor: 1e6 },\n { unit: 's', factor: 1e9 },\n { unit: 'm', factor: 60 * 1e9 },\n { unit: 'h', factor: 3600 * 1e9 },\n] as const;\n\nfunction smartFixed(n: number): string {\n return n.toLocaleString(undefined, {\n minimumFractionDigits: 0,\n maximumFractionDigits: 2,\n useGrouping: true,\n });\n}\nexport class Report {\n constructor(\n public readonly type: ReportType,\n public readonly value: bigint,\n public readonly uncertainty: number = 0,\n public readonly scale: bigint = 1n,\n ) {}\n valueOf() {\n return Number(div(this.value, this.scale));\n }\n toString() {\n const uncertainty = this.uncertainty ? ` ± ${smartFixed(this.uncertainty)}%` : '';\n\n const value = this.valueOf();\n if (this.type === 'ops') {\n return `${smartFixed(value)} ops/s${uncertainty}`;\n }\n let display = value;\n let unit = 'ns';\n\n for (const { unit: u, factor } of units) {\n const candidate = value / factor;\n if (candidate < 1000) {\n display = candidate;\n unit = u;\n break;\n }\n }\n return `${smartFixed(display)} ${unit}${uncertainty}`;\n }\n}\n\nexport const createReport = (durations: BigUint64Array, type: ReportType): Report => {\n const n = durations.length;\n if (n === 0) {\n return new Report(type, 0n);\n }\n switch (type) {\n case 'min': {\n return new Report(type, durations[0]);\n }\n case 'max': {\n return new Report(type, durations[n - 1]);\n }\n case 'median': {\n const mid = Math.floor(n / 2);\n const med = n % 2 === 0 ? (durations[mid - 1] + durations[mid]) / 2n : durations[mid];\n return new Report(type, med);\n }\n\n case 'mode': {\n const freq = new Map<bigint, bigint>();\n let maxCount = 0n;\n let modeVal = durations[0];\n for (const d of durations) {\n const count = (freq.get(d) || 0n) + 1n;\n freq.set(d, count);\n if (count > maxCount) {\n maxCount = count;\n modeVal = d;\n }\n }\n let lower = modeVal;\n let upper = modeVal;\n const firstIdx = durations.indexOf(modeVal);\n const lastIdx = durations.lastIndexOf(modeVal);\n if (firstIdx > 0) lower = durations[firstIdx - 1];\n if (lastIdx < n - 1) upper = durations[lastIdx + 1];\n const gap = max(modeVal - lower, upper - modeVal);\n const uncertainty = modeVal > 0 ? Number(((gap / 2n) * 100n) / modeVal) : 0;\n return new Report(type, modeVal, uncertainty);\n }\n\n case 'ops': {\n let sum = 0n;\n for (const duration of durations) {\n sum += duration;\n }\n const avgNs = sum / BigInt(n);\n const nsPerSec = 1_000_000_000n;\n const raw = Number(nsPerSec) / Number(avgNs);\n const extra = raw < 1 ? Math.ceil(-Math.log10(raw)) : 0;\n\n const exp = raw > 100 ? 0 : 2 + extra;\n\n const scale = 10n ** BigInt(exp);\n\n const value = avgNs > 0n ? (nsPerSec * scale) / avgNs : 0n;\n const deviation = durations[n - 1] - durations[0];\n const uncertainty = avgNs > 0 ? Number(div(deviation * scale, 2n * avgNs)) : 0;\n return new Report(type, value, uncertainty, scale);\n }\n case 'mean': {\n let sum = 0n;\n for (const duration of durations) {\n sum += duration;\n }\n const value = divs(sum, BigInt(n), 1n);\n return new Report(type, value);\n }\n\n default: {\n const p = Number(type.slice(1));\n if (p === 0) {\n return new Report(type, durations[0]);\n }\n if (p === 100) {\n return new Report(type, durations[n - 1]);\n }\n const idx = Math.ceil((p / 100) * n) - 1;\n const value = durations[Math.min(Math.max(idx, 0), n - 1)];\n const prev = idx > 0 ? durations[idx - 1] : value;\n const next = idx < n - 1 ? durations[idx + 1] : value;\n const gap = max(value - prev, next - value);\n const uncertainty = value > 0 ? Number(div(divs(gap, 2n, 100_00n), value)) / 100 : 0;\n\n return new Report(type, value, uncertainty);\n }\n }\n};\n"],"names":["div","max","divs","units","unit","factor","smartFixed","n","toLocaleString","undefined","minimumFractionDigits","maximumFractionDigits","useGrouping","Report","type","value","uncertainty","scale","valueOf","Number","toString","display","u","candidate","createReport","durations","length","mid","Math","floor","med","freq","Map","maxCount","modeVal","d","count","get","set","lower","upper","firstIdx","indexOf","lastIdx","lastIndexOf","gap","sum","duration","avgNs","BigInt","nsPerSec","raw","extra","ceil","log10","exp","deviation","p","slice","idx","min","prev","next"],"mappings":"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"}
1
+ {"version":3,"sources":["../src/reporter.ts"],"sourcesContent":["import { div, max, divs } from './utils.js';\nimport { ReportType, DURATION_SCALE } from './types.js';\n\nconst units = [\n { unit: 'ns', factor: 1 },\n { unit: 'µs', factor: 1e3 },\n { unit: 'ms', factor: 1e6 },\n { unit: 's', factor: 1e9 },\n { unit: 'm', factor: 60 * 1e9 },\n { unit: 'h', factor: 3600 * 1e9 },\n] as const;\n\nfunction smartFixed(n: number): string {\n return n.toLocaleString(undefined, {\n minimumFractionDigits: 0,\n maximumFractionDigits: 2,\n useGrouping: true,\n });\n}\nexport class Report {\n constructor(\n public readonly type: ReportType,\n public readonly value: bigint,\n public readonly uncertainty: number = 0,\n public readonly scale: bigint = 1n,\n ) {}\n valueOf() {\n return Number(div(this.value, this.scale));\n }\n toString() {\n const uncertainty = this.uncertainty ? ` ± ${smartFixed(this.uncertainty)}%` : '';\n\n const value = this.valueOf();\n if (this.type === 'ops') {\n return `${smartFixed(value)} ops/s${uncertainty}`;\n }\n let display = value;\n let unit = 'ns';\n\n for (const { unit: u, factor } of units) {\n const candidate = value / factor;\n if (candidate < 1000) {\n display = candidate;\n unit = u;\n break;\n }\n }\n return `${smartFixed(display)} ${unit}${uncertainty}`;\n }\n}\n\nexport const createReport = (durations: BigUint64Array, type: ReportType): Report => {\n const n = durations.length;\n if (n === 0) {\n return new Report(type, 0n);\n }\n switch (type) {\n case 'min': {\n return new Report(type, durations[0], 0, DURATION_SCALE);\n }\n case 'max': {\n return new Report(type, durations[n - 1], 0, DURATION_SCALE);\n }\n case 'median': {\n const mid = Math.floor(n / 2);\n const med = n % 2 === 0 ? (durations[mid - 1] + durations[mid]) / 2n : durations[mid];\n return new Report(type, med, 0, DURATION_SCALE);\n }\n\n case 'mode': {\n const freq = new Map<bigint, bigint>();\n let maxCount = 0n;\n let modeVal = durations[0];\n for (const d of durations) {\n const count = (freq.get(d) || 0n) + 1n;\n freq.set(d, count);\n if (count > maxCount) {\n maxCount = count;\n modeVal = d;\n }\n }\n let lower = modeVal;\n let upper = modeVal;\n const firstIdx = durations.indexOf(modeVal);\n const lastIdx = durations.lastIndexOf(modeVal);\n if (firstIdx > 0) lower = durations[firstIdx - 1];\n if (lastIdx < n - 1) upper = durations[lastIdx + 1];\n const gap = max(modeVal - lower, upper - modeVal);\n const uncertainty = modeVal > 0 ? Number(((gap / 2n) * 100n) / modeVal) : 0;\n return new Report(type, modeVal, uncertainty, DURATION_SCALE);\n }\n\n case 'ops': {\n let sum = 0n;\n for (const duration of durations) {\n sum += duration;\n }\n const avgScaled = sum / BigInt(n);\n const nsPerSecScaled = 1_000_000_000n * DURATION_SCALE;\n const raw = Number(nsPerSecScaled) / Number(avgScaled);\n const extra = raw < 1 ? Math.ceil(-Math.log10(raw)) : 0;\n\n const exp = raw > 100 ? 0 : 2 + extra;\n\n const scale = 10n ** BigInt(exp);\n\n const value = avgScaled > 0n ? (nsPerSecScaled * scale) / avgScaled : 0n;\n const deviation = durations[n - 1] - durations[0];\n const uncertainty = avgScaled > 0 ? Number(div(deviation * scale, 2n * avgScaled)) : 0;\n return new Report(type, value, uncertainty, scale);\n }\n case 'mean': {\n let sum = 0n;\n for (const duration of durations) {\n sum += duration;\n }\n const value = divs(sum, BigInt(n), 1n);\n return new Report(type, value, 0, DURATION_SCALE);\n }\n\n default: {\n const p = Number(type.slice(1));\n if (p === 0) {\n return new Report(type, durations[0], 0, DURATION_SCALE);\n }\n if (p === 100) {\n return new Report(type, durations[n - 1], 0, DURATION_SCALE);\n }\n const idx = Math.ceil((p / 100) * n) - 1;\n const value = durations[Math.min(Math.max(idx, 0), n - 1)];\n const prev = idx > 0 ? durations[idx - 1] : value;\n const next = idx < n - 1 ? durations[idx + 1] : value;\n const gap = max(value - prev, next - value);\n const uncertainty = value > 0 ? Number(div(divs(gap, 2n, 100_00n), value)) / 100 : 0;\n\n return new Report(type, value, uncertainty, DURATION_SCALE);\n }\n }\n};\n"],"names":["div","max","divs","DURATION_SCALE","units","unit","factor","smartFixed","n","toLocaleString","undefined","minimumFractionDigits","maximumFractionDigits","useGrouping","Report","type","value","uncertainty","scale","valueOf","Number","toString","display","u","candidate","createReport","durations","length","mid","Math","floor","med","freq","Map","maxCount","modeVal","d","count","get","set","lower","upper","firstIdx","indexOf","lastIdx","lastIndexOf","gap","sum","duration","avgScaled","BigInt","nsPerSecScaled","raw","extra","ceil","log10","exp","deviation","p","slice","idx","min","prev","next"],"mappings":"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"}
package/build/runner.cjs CHANGED
@@ -92,7 +92,7 @@ const collectSample = async ({ batchSize, run, runRaw, runIsAsync, pre, preIsAsy
92
92
  consume(runRaw(context, data));
93
93
  }
94
94
  }
95
- return (hr() - batchStart) / BigInt(batchSize);
95
+ return (hr() - batchStart) * _typescjs.DURATION_SCALE / BigInt(batchSize);
96
96
  }
97
97
  let sampleDuration = 0n;
98
98
  for(let b = 0; b < batchSize; b++){
@@ -120,7 +120,7 @@ const collectSample = async ({ batchSize, run, runRaw, runIsAsync, pre, preIsAsy
120
120
  }
121
121
  }
122
122
  }
123
- return sampleDuration / BigInt(batchSize);
123
+ return sampleDuration * _typescjs.DURATION_SCALE / BigInt(batchSize);
124
124
  };
125
125
  const tuneParameters = async ({ initialBatch, run, runRaw, runIsAsync, pre, preIsAsync, post, postIsAsync, context, data, minCycles, relThreshold, maxCycles, nextNonce })=>{
126
126
  let batchSize = initialBatch;
@@ -354,7 +354,7 @@ const benchmark = async ({ setup, teardown, pre, run: runRaw, post, data, warmup
354
354
  consume(runRaw(context, input));
355
355
  }
356
356
  }
357
- return (hr() - batchStart) / BigInt(batchSize);
357
+ return (hr() - batchStart) * _typescjs.DURATION_SCALE / BigInt(batchSize);
358
358
  }
359
359
  if (preSync) {
360
360
  preSync(context, input);
@@ -422,7 +422,7 @@ const benchmark = async ({ setup, teardown, pre, run: runRaw, post, data, warmup
422
422
  }
423
423
  }
424
424
  const batchDuration = hr() - batchStart;
425
- sampleDuration = batchDuration / BigInt(batchSize);
425
+ sampleDuration = batchDuration * _typescjs.DURATION_SCALE / BigInt(batchSize);
426
426
  } else {
427
427
  for(let b = 0; b < batchSize; b++){
428
428
  if (preSync) {
@@ -438,7 +438,7 @@ const benchmark = async ({ setup, teardown, pre, run: runRaw, post, data, warmup
438
438
  await postAsync(context, input);
439
439
  }
440
440
  }
441
- sampleDuration /= BigInt(batchSize);
441
+ sampleDuration = sampleDuration * _typescjs.DURATION_SCALE / BigInt(batchSize);
442
442
  }
443
443
  const sampleEnd = _nodeperf_hooks.performance.now();
444
444
  if (!disableFiltering) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/runner.ts"],"sourcesContent":["import { performance, PerformanceObserver } from 'node:perf_hooks';\nimport { Options, Control } from './types.js';\nimport { GCWatcher } from './gc-watcher.js';\nimport { StepFn } from './types.js';\n\nconst COMPLETE_VALUE = 100_00;\n\nconst hr = process.hrtime.bigint.bind(process.hrtime);\n\nconst sink = new Int32Array(new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT));\nconst consume = (value: unknown) => {\n let payload = 0;\n switch (typeof value) {\n case 'number':\n payload = Number.isFinite(value) ? Math.trunc(value) : 0;\n break;\n case 'bigint':\n payload = Number(value & 0xffff_ffffn);\n break;\n case 'string':\n payload = value.length;\n break;\n case 'boolean':\n payload = value ? 1 : 0;\n break;\n case 'object':\n payload = value === null ? 0 : 1;\n break;\n case 'function':\n payload = 1;\n break;\n default:\n payload = -1;\n }\n Atomics.xor(sink, 0, payload);\n};\n\nconst runSync = (run: Function, overhead: bigint) => {\n return (...args: unknown[]) => {\n const start = hr();\n const result = run(...args);\n consume(result);\n const duration = hr() - start;\n return duration > overhead ? duration - overhead : 0n;\n };\n};\n\nconst runAsync = (run: Function) => {\n return async (...args: unknown[]) => {\n const start = hr();\n const result = await run(...args);\n consume(result);\n return hr() - start;\n };\n};\n\nconst isThenable = (value: unknown): value is PromiseLike<unknown> => {\n return value !== null && (typeof value === 'object' || typeof value === 'function') && typeof (value as PromiseLike<unknown>).then === 'function';\n};\n\nconst TARGET_SAMPLE_NS = 1_000_000n; // aim for ~1ms per measured sample\nconst MAX_BATCH = 1_048_576;\nconst PROGRESS_STRIDE = 16;\nconst GC_STRIDE = 32;\nconst OUTLIER_MULTIPLIER = 4;\nconst OUTLIER_IQR_MULTIPLIER = 3;\nconst OUTLIER_WINDOW = 64;\nconst OUTLIER_ABS_THRESHOLD_NS = 10_000;\nconst BASELINE_SAMPLES = 16;\nconst OUTLIER_SCRATCH = new Float64Array(OUTLIER_WINDOW);\n\ntype GCEvent = { start: number; end: number };\ntype RunTimedSync<TContext, TInput> = (ctx: TContext, data: TInput, nonce?: number) => bigint;\ntype RunTimedAsync<TContext, TInput> = (ctx: TContext, data: TInput, nonce?: number) => Promise<bigint>;\n\nconst measureTimerOverhead = () => {\n let total = 0n;\n for (let i = 0; i < BASELINE_SAMPLES; i++) {\n const start = hr();\n consume(0);\n total += hr() - start;\n }\n return total / BigInt(BASELINE_SAMPLES);\n};\n\nconst collectSample = async <TContext, TInput>({\n batchSize,\n run,\n runRaw,\n runIsAsync,\n pre,\n preIsAsync,\n post,\n postIsAsync,\n context,\n data,\n nextNonce,\n}: {\n batchSize: number;\n run: RunTimedSync<TContext, TInput> | RunTimedAsync<TContext, TInput>;\n runRaw: StepFn<TContext, TInput>;\n runIsAsync: boolean;\n pre: StepFn<TContext, TInput> | undefined;\n preIsAsync: boolean;\n post: StepFn<TContext, TInput> | undefined;\n postIsAsync: boolean;\n context: TContext;\n data: TInput;\n nextNonce: (() => number) | null;\n}) => {\n const canBatchTime = !runIsAsync && !pre && !post;\n if (canBatchTime) {\n const batchStart = hr();\n if (nextNonce) {\n for (let b = 0; b < batchSize; b++) {\n consume((runRaw as Function)(context, data, nextNonce()));\n }\n } else {\n for (let b = 0; b < batchSize; b++) {\n consume(runRaw(context, data));\n }\n }\n return (hr() - batchStart) / BigInt(batchSize);\n }\n\n let sampleDuration = 0n;\n for (let b = 0; b < batchSize; b++) {\n if (pre) {\n if (preIsAsync) {\n await pre(context, data);\n } else {\n pre(context, data);\n }\n }\n\n if (runIsAsync) {\n const runAsyncFn = run as RunTimedAsync<TContext, TInput>;\n const duration = nextNonce ? await runAsyncFn(context, data, nextNonce()) : await runAsyncFn(context, data);\n sampleDuration += duration;\n } else {\n const runSyncFn = run as RunTimedSync<TContext, TInput>;\n const duration = nextNonce ? runSyncFn(context, data, nextNonce()) : runSyncFn(context, data);\n sampleDuration += duration;\n }\n\n if (post) {\n if (postIsAsync) {\n await post(context, data);\n } else {\n post(context, data);\n }\n }\n }\n return sampleDuration / BigInt(batchSize);\n};\n\nconst tuneParameters = async <TContext, TInput>({\n initialBatch,\n run,\n runRaw,\n runIsAsync,\n pre,\n preIsAsync,\n post,\n postIsAsync,\n context,\n data,\n minCycles,\n relThreshold,\n maxCycles,\n nextNonce,\n}: {\n initialBatch: number;\n run: RunTimedSync<TContext, TInput> | RunTimedAsync<TContext, TInput>;\n runRaw: StepFn<TContext, TInput>;\n runIsAsync: boolean;\n pre?: StepFn<TContext, TInput>;\n preIsAsync: boolean;\n post?: StepFn<TContext, TInput>;\n postIsAsync: boolean;\n context: TContext;\n data: TInput;\n minCycles: number;\n relThreshold: number;\n maxCycles: number;\n nextNonce: (() => number) | null;\n}) => {\n let batchSize = initialBatch;\n let bestCv = Number.POSITIVE_INFINITY;\n let bestBatch = batchSize;\n\n for (let attempt = 0; attempt < 3; attempt++) {\n const samples: number[] = [];\n const sampleCount = Math.min(8, maxCycles);\n for (let s = 0; s < sampleCount; s++) {\n const duration = await collectSample({\n batchSize,\n run,\n runRaw,\n runIsAsync,\n pre,\n preIsAsync,\n post,\n postIsAsync,\n context,\n data,\n nextNonce,\n });\n samples.push(Number(duration));\n }\n const mean = samples.reduce((acc, v) => acc + v, 0) / samples.length;\n const variance = samples.reduce((acc, v) => acc + (v - mean) * (v - mean), 0) / Math.max(1, samples.length - 1);\n const stddev = Math.sqrt(variance);\n const cv = mean === 0 ? Number.POSITIVE_INFINITY : stddev / mean;\n\n if (cv < bestCv) {\n bestCv = cv;\n bestBatch = batchSize;\n }\n\n if (cv <= relThreshold || batchSize >= MAX_BATCH) {\n break;\n }\n batchSize = Math.min(MAX_BATCH, batchSize * 2);\n }\n\n const tunedRel = bestCv < relThreshold ? Math.max(bestCv * 1.5, relThreshold * 0.5) : relThreshold;\n const tunedMin = Math.min(maxCycles, Math.max(minCycles, Math.ceil(minCycles * Math.max(1, bestCv / (relThreshold || 1e-6)))));\n\n return { batchSize: bestBatch, relThreshold: tunedRel, minCycles: tunedMin };\n};\n\nconst createGCTracker = () => {\n if (process.env.OVERTAKE_GC_OBSERVER !== '1') {\n return null;\n }\n if (typeof PerformanceObserver === 'undefined') {\n return null;\n }\n\n const events: GCEvent[] = [];\n const observer = new PerformanceObserver((list) => {\n for (const entry of list.getEntries()) {\n events.push({ start: entry.startTime, end: entry.startTime + entry.duration });\n }\n });\n\n try {\n observer.observe({ entryTypes: ['gc'] });\n } catch {\n return null;\n }\n\n const overlaps = (start: number, end: number) => {\n let noisy = false;\n for (let i = events.length - 1; i >= 0; i--) {\n const event = events[i];\n if (event.end < start - 5_000) {\n events.splice(i, 1);\n continue;\n }\n if (event.start <= end && event.end >= start) {\n noisy = true;\n }\n }\n return noisy;\n };\n\n const dispose = () => observer.disconnect();\n\n return { overlaps, dispose };\n};\n\nconst pushWindow = (arr: number[], value: number, cap: number) => {\n if (arr.length === cap) {\n arr.shift();\n }\n arr.push(value);\n};\n\nconst medianAndIqr = (arr: number[]) => {\n if (arr.length === 0) return { median: 0, iqr: 0 };\n for (let i = 0; i < arr.length; i++) {\n OUTLIER_SCRATCH[i] = arr[i];\n }\n const view = OUTLIER_SCRATCH.subarray(0, arr.length);\n view.sort();\n const mid = Math.floor(view.length / 2);\n const median = view.length % 2 === 0 ? (view[mid - 1] + view[mid]) / 2 : view[mid];\n const q1Idx = Math.floor(view.length * 0.25);\n const q3Idx = Math.floor(view.length * 0.75);\n const q1 = view[q1Idx];\n const q3 = view[q3Idx];\n return { median, iqr: q3 - q1 };\n};\n\nconst windowCv = (arr: number[]) => {\n if (arr.length < 2) return Number.POSITIVE_INFINITY;\n const mean = arr.reduce((a, v) => a + v, 0) / arr.length;\n const variance = arr.reduce((a, v) => a + (v - mean) * (v - mean), 0) / (arr.length - 1);\n const stddev = Math.sqrt(variance);\n return mean === 0 ? Number.POSITIVE_INFINITY : stddev / mean;\n};\n\nexport const benchmark = async <TContext, TInput>({\n setup,\n teardown,\n pre,\n run: runRaw,\n post,\n data,\n\n warmupCycles,\n minCycles,\n absThreshold,\n relThreshold,\n gcObserver = false,\n\n durationsSAB,\n controlSAB,\n}: Required<Options<TContext, TInput>>) => {\n const durations = new BigUint64Array(durationsSAB);\n const control = new Int32Array(controlSAB);\n\n control[Control.INDEX] = 0;\n control[Control.PROGRESS] = 0;\n control[Control.COMPLETE] = 255;\n\n const context = (await setup?.()) as TContext;\n const input = data as TInput;\n const maxCycles = durations.length;\n const gcWatcher = gcObserver ? new GCWatcher() : null;\n const gcTracker = gcObserver ? createGCTracker() : null;\n\n try {\n // classify sync/async and capture initial duration\n let preIsAsync = false;\n if (pre) {\n const preResult = pre(context, input);\n preIsAsync = isThenable(preResult);\n if (preIsAsync) {\n await preResult;\n }\n }\n\n const probeStart = hr();\n const probeResult = runRaw(context, input);\n const runIsAsync = isThenable(probeResult);\n if (runIsAsync) {\n const resolved = await probeResult;\n consume(resolved);\n } else {\n consume(probeResult);\n }\n const durationProbeRaw = hr() - probeStart;\n\n let postIsAsync = false;\n if (post) {\n const postResult = post(context, input);\n postIsAsync = isThenable(postResult);\n if (postIsAsync) {\n await postResult;\n }\n }\n\n const timerOverhead = runIsAsync ? 0n : measureTimerOverhead();\n let durationProbe = runIsAsync ? durationProbeRaw : durationProbeRaw > timerOverhead ? durationProbeRaw - timerOverhead : 0n;\n\n const shouldPerturbInput = process.env.OVERTAKE_PERTURB_INPUT === '1';\n let nonce = 0;\n const nextNonce = shouldPerturbInput\n ? () => {\n nonce = (nonce + 1) | 0;\n return nonce;\n }\n : null;\n\n if (!runIsAsync && !pre && !post) {\n const batchProbeSize = 10_000;\n const batchProbeStart = hr();\n if (nextNonce) {\n for (let i = 0; i < batchProbeSize; i++) {\n consume((runRaw as Function)(context, input, nextNonce()));\n }\n } else {\n for (let i = 0; i < batchProbeSize; i++) {\n consume(runRaw(context, input));\n }\n }\n durationProbe = (hr() - batchProbeStart) / BigInt(batchProbeSize);\n }\n\n const runTimedSync = runIsAsync ? null : runSync(runRaw, timerOverhead);\n const runTimedAsync = runIsAsync ? runAsync(runRaw) : null;\n const run = runIsAsync ? runTimedAsync! : runTimedSync!;\n\n const runOnceSync: RunTimedSync<TContext, TInput> | null = runIsAsync ? null : nextNonce ? (ctx, dataValue) => runTimedSync!(ctx, dataValue, nextNonce()) : runTimedSync!;\n const runOnceAsync: RunTimedAsync<TContext, TInput> | null = runIsAsync ? (nextNonce ? (ctx, dataValue) => runTimedAsync!(ctx, dataValue, nextNonce()) : runTimedAsync!) : null;\n\n const preSync = preIsAsync ? null : pre;\n const preAsync = preIsAsync ? pre : null;\n const postSync = postIsAsync ? null : post;\n const postAsync = postIsAsync ? post : null;\n\n // choose batch size to amortize timer overhead\n const durationPerRun = durationProbe === 0n ? 1n : durationProbe;\n const suggestedBatch = Number(TARGET_SAMPLE_NS / durationPerRun);\n const minBatchForFastOps = durationProbe < 100n ? 100_000 : 1;\n const initialBatchSize = Math.min(MAX_BATCH, Math.max(minBatchForFastOps, suggestedBatch));\n\n // auto-tune based on warmup samples\n const tuned = await tuneParameters({\n initialBatch: initialBatchSize,\n run,\n runRaw,\n runIsAsync,\n pre,\n preIsAsync,\n post,\n postIsAsync,\n context,\n data: input,\n minCycles,\n relThreshold,\n maxCycles,\n nextNonce,\n });\n let batchSize = tuned.batchSize;\n minCycles = tuned.minCycles;\n relThreshold = tuned.relThreshold;\n\n // warmup: run until requested cycles, adapt if unstable\n const warmupStart = performance.now();\n let warmupRemaining = warmupCycles;\n const warmupWindow: number[] = [];\n const warmupCap = Math.max(warmupCycles, Math.min(maxCycles, warmupCycles * 4 || 1000));\n const canBatchTime = !runIsAsync && !preSync && !preAsync && !postSync && !postAsync;\n\n const runWarmup = async () => {\n if (canBatchTime) {\n const batchStart = hr();\n if (nextNonce) {\n for (let b = 0; b < batchSize; b++) {\n consume((runRaw as Function)(context, input, nextNonce()));\n }\n } else {\n for (let b = 0; b < batchSize; b++) {\n consume(runRaw(context, input));\n }\n }\n return (hr() - batchStart) / BigInt(batchSize);\n }\n\n if (preSync) {\n preSync(context, input);\n } else if (preAsync) {\n await preAsync(context, input);\n }\n\n const duration = runIsAsync ? await runOnceAsync!(context, input) : runOnceSync!(context, input);\n\n if (postSync) {\n postSync(context, input);\n } else if (postAsync) {\n await postAsync(context, input);\n }\n\n return duration;\n };\n\n while (performance.now() - warmupStart < 1_000 && warmupRemaining > 0) {\n const duration = await runWarmup();\n pushWindow(warmupWindow, Number(duration), warmupCap);\n warmupRemaining--;\n }\n let warmupDone = 0;\n while (warmupDone < warmupRemaining) {\n const duration = await runWarmup();\n pushWindow(warmupWindow, Number(duration), warmupCap);\n warmupDone++;\n if (global.gc && warmupDone % GC_STRIDE === 0) {\n global.gc();\n }\n }\n while (warmupWindow.length >= 8 && warmupWindow.length < warmupCap) {\n const cv = windowCv(warmupWindow);\n if (cv <= relThreshold * 2) {\n break;\n }\n const duration = await runWarmup();\n pushWindow(warmupWindow, Number(duration), warmupCap);\n }\n\n let i = 0;\n let mean = 0n;\n let m2 = 0n;\n const outlierWindow: number[] = [];\n let skipped = 0;\n const maxSkipped = maxCycles * 10;\n let disableFiltering = false;\n\n while (true) {\n if (i >= maxCycles) break;\n if (!disableFiltering && skipped >= maxSkipped) {\n console.error(`Warning: ${skipped} samples skipped due to noise/outlier detection. ` + `Disabling filtering for remaining samples. Results may have higher variance.`);\n disableFiltering = true;\n }\n\n if (global.gc && i > 0 && i % GC_STRIDE === 0) {\n global.gc();\n }\n\n const gcMarker = gcWatcher?.start();\n const sampleStart = performance.now();\n let sampleDuration = 0n;\n\n if (canBatchTime) {\n const batchStart = hr();\n if (nextNonce) {\n for (let b = 0; b < batchSize; b++) {\n consume((runRaw as Function)(context, input, nextNonce()));\n }\n } else {\n for (let b = 0; b < batchSize; b++) {\n consume(runRaw(context, input));\n }\n }\n const batchDuration = hr() - batchStart;\n sampleDuration = batchDuration / BigInt(batchSize);\n } else {\n for (let b = 0; b < batchSize; b++) {\n if (preSync) {\n preSync(context, input);\n } else if (preAsync) {\n await preAsync(context, input);\n }\n\n const duration = runIsAsync ? await runOnceAsync!(context, input) : runOnceSync!(context, input);\n sampleDuration += duration;\n\n if (postSync) {\n postSync(context, input);\n } else if (postAsync) {\n await postAsync(context, input);\n }\n }\n sampleDuration /= BigInt(batchSize);\n }\n\n const sampleEnd = performance.now();\n if (!disableFiltering) {\n const gcNoise = (gcMarker ? gcWatcher!.seen(gcMarker) : false) || (gcTracker?.overlaps(sampleStart, sampleEnd) ?? false);\n if (gcNoise) {\n skipped++;\n continue;\n }\n }\n\n const durationNumber = Number(sampleDuration);\n pushWindow(outlierWindow, durationNumber, OUTLIER_WINDOW);\n if (!disableFiltering) {\n const { median, iqr } = medianAndIqr(outlierWindow);\n const maxAllowed = median + OUTLIER_IQR_MULTIPLIER * iqr || Number.POSITIVE_INFINITY;\n if (outlierWindow.length >= 8 && durationNumber > maxAllowed && durationNumber - median > OUTLIER_ABS_THRESHOLD_NS) {\n skipped++;\n continue;\n }\n\n const meanNumber = Number(mean);\n if (i >= 8 && meanNumber > 0 && durationNumber > OUTLIER_MULTIPLIER * meanNumber && durationNumber - meanNumber > OUTLIER_ABS_THRESHOLD_NS) {\n skipped++;\n continue;\n }\n }\n\n durations[i++] = sampleDuration;\n const delta = sampleDuration - mean;\n mean += delta / BigInt(i);\n m2 += delta * (sampleDuration - mean);\n\n const progress = Math.max(i / maxCycles) * COMPLETE_VALUE;\n if (i % PROGRESS_STRIDE === 0) {\n control[Control.PROGRESS] = progress;\n }\n\n if (i >= minCycles) {\n const variance = Number(m2) / (i - 1);\n const stddev = Math.sqrt(variance);\n if (stddev <= Number(absThreshold)) {\n break;\n }\n\n const meanNum = Number(mean);\n const cov = stddev / (meanNum || 1);\n if (cov <= relThreshold) {\n break;\n }\n }\n }\n\n control[Control.INDEX] = i;\n control[Control.COMPLETE] = 0;\n } catch (e) {\n console.error(e && typeof e === 'object' && 'stack' in e ? e.stack : e);\n control[Control.COMPLETE] = 1;\n } finally {\n gcTracker?.dispose?.();\n try {\n await teardown?.(context);\n } catch (e) {\n control[Control.COMPLETE] = 2;\n console.error(e && typeof e === 'object' && 'stack' in e ? e.stack : e);\n }\n }\n\n return control[Control.COMPLETE];\n};\n"],"names":["benchmark","COMPLETE_VALUE","hr","process","hrtime","bigint","bind","sink","Int32Array","SharedArrayBuffer","BYTES_PER_ELEMENT","consume","value","payload","Number","isFinite","Math","trunc","length","Atomics","xor","runSync","run","overhead","args","start","result","duration","runAsync","isThenable","then","TARGET_SAMPLE_NS","MAX_BATCH","PROGRESS_STRIDE","GC_STRIDE","OUTLIER_MULTIPLIER","OUTLIER_IQR_MULTIPLIER","OUTLIER_WINDOW","OUTLIER_ABS_THRESHOLD_NS","BASELINE_SAMPLES","OUTLIER_SCRATCH","Float64Array","measureTimerOverhead","total","i","BigInt","collectSample","batchSize","runRaw","runIsAsync","pre","preIsAsync","post","postIsAsync","context","data","nextNonce","canBatchTime","batchStart","b","sampleDuration","runAsyncFn","runSyncFn","tuneParameters","initialBatch","minCycles","relThreshold","maxCycles","bestCv","POSITIVE_INFINITY","bestBatch","attempt","samples","sampleCount","min","s","push","mean","reduce","acc","v","variance","max","stddev","sqrt","cv","tunedRel","tunedMin","ceil","createGCTracker","env","OVERTAKE_GC_OBSERVER","PerformanceObserver","events","observer","list","entry","getEntries","startTime","end","observe","entryTypes","overlaps","noisy","event","splice","dispose","disconnect","pushWindow","arr","cap","shift","medianAndIqr","median","iqr","view","subarray","sort","mid","floor","q1Idx","q3Idx","q1","q3","windowCv","a","setup","teardown","warmupCycles","absThreshold","gcObserver","durationsSAB","controlSAB","durations","BigUint64Array","control","Control","INDEX","PROGRESS","COMPLETE","input","gcWatcher","GCWatcher","gcTracker","preResult","probeStart","probeResult","resolved","durationProbeRaw","postResult","timerOverhead","durationProbe","shouldPerturbInput","OVERTAKE_PERTURB_INPUT","nonce","batchProbeSize","batchProbeStart","runTimedSync","runTimedAsync","runOnceSync","ctx","dataValue","runOnceAsync","preSync","preAsync","postSync","postAsync","durationPerRun","suggestedBatch","minBatchForFastOps","initialBatchSize","tuned","warmupStart","performance","now","warmupRemaining","warmupWindow","warmupCap","runWarmup","warmupDone","global","gc","m2","outlierWindow","skipped","maxSkipped","disableFiltering","console","error","gcMarker","sampleStart","batchDuration","sampleEnd","gcNoise","seen","durationNumber","maxAllowed","meanNumber","delta","progress","meanNum","cov","e","stack"],"mappings":"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"}
1
+ {"version":3,"sources":["../src/runner.ts"],"sourcesContent":["import { performance, PerformanceObserver } from 'node:perf_hooks';\nimport { Options, Control, DURATION_SCALE } from './types.js';\nimport { GCWatcher } from './gc-watcher.js';\nimport { StepFn } from './types.js';\n\nconst COMPLETE_VALUE = 100_00;\n\nconst hr = process.hrtime.bigint.bind(process.hrtime);\n\nconst sink = new Int32Array(new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT));\nconst consume = (value: unknown) => {\n let payload = 0;\n switch (typeof value) {\n case 'number':\n payload = Number.isFinite(value) ? Math.trunc(value) : 0;\n break;\n case 'bigint':\n payload = Number(value & 0xffff_ffffn);\n break;\n case 'string':\n payload = value.length;\n break;\n case 'boolean':\n payload = value ? 1 : 0;\n break;\n case 'object':\n payload = value === null ? 0 : 1;\n break;\n case 'function':\n payload = 1;\n break;\n default:\n payload = -1;\n }\n Atomics.xor(sink, 0, payload);\n};\n\nconst runSync = (run: Function, overhead: bigint) => {\n return (...args: unknown[]) => {\n const start = hr();\n const result = run(...args);\n consume(result);\n const duration = hr() - start;\n return duration > overhead ? duration - overhead : 0n;\n };\n};\n\nconst runAsync = (run: Function) => {\n return async (...args: unknown[]) => {\n const start = hr();\n const result = await run(...args);\n consume(result);\n return hr() - start;\n };\n};\n\nconst isThenable = (value: unknown): value is PromiseLike<unknown> => {\n return value !== null && (typeof value === 'object' || typeof value === 'function') && typeof (value as PromiseLike<unknown>).then === 'function';\n};\n\nconst TARGET_SAMPLE_NS = 1_000_000n; // aim for ~1ms per measured sample\nconst MAX_BATCH = 1_048_576;\nconst PROGRESS_STRIDE = 16;\nconst GC_STRIDE = 32;\nconst OUTLIER_MULTIPLIER = 4;\nconst OUTLIER_IQR_MULTIPLIER = 3;\nconst OUTLIER_WINDOW = 64;\nconst OUTLIER_ABS_THRESHOLD_NS = 10_000;\nconst BASELINE_SAMPLES = 16;\nconst OUTLIER_SCRATCH = new Float64Array(OUTLIER_WINDOW);\n\ntype GCEvent = { start: number; end: number };\ntype RunTimedSync<TContext, TInput> = (ctx: TContext, data: TInput, nonce?: number) => bigint;\ntype RunTimedAsync<TContext, TInput> = (ctx: TContext, data: TInput, nonce?: number) => Promise<bigint>;\n\nconst measureTimerOverhead = () => {\n let total = 0n;\n for (let i = 0; i < BASELINE_SAMPLES; i++) {\n const start = hr();\n consume(0);\n total += hr() - start;\n }\n return total / BigInt(BASELINE_SAMPLES);\n};\n\nconst collectSample = async <TContext, TInput>({\n batchSize,\n run,\n runRaw,\n runIsAsync,\n pre,\n preIsAsync,\n post,\n postIsAsync,\n context,\n data,\n nextNonce,\n}: {\n batchSize: number;\n run: RunTimedSync<TContext, TInput> | RunTimedAsync<TContext, TInput>;\n runRaw: StepFn<TContext, TInput>;\n runIsAsync: boolean;\n pre: StepFn<TContext, TInput> | undefined;\n preIsAsync: boolean;\n post: StepFn<TContext, TInput> | undefined;\n postIsAsync: boolean;\n context: TContext;\n data: TInput;\n nextNonce: (() => number) | null;\n}) => {\n const canBatchTime = !runIsAsync && !pre && !post;\n if (canBatchTime) {\n const batchStart = hr();\n if (nextNonce) {\n for (let b = 0; b < batchSize; b++) {\n consume((runRaw as Function)(context, data, nextNonce()));\n }\n } else {\n for (let b = 0; b < batchSize; b++) {\n consume(runRaw(context, data));\n }\n }\n return ((hr() - batchStart) * DURATION_SCALE) / BigInt(batchSize);\n }\n\n let sampleDuration = 0n;\n for (let b = 0; b < batchSize; b++) {\n if (pre) {\n if (preIsAsync) {\n await pre(context, data);\n } else {\n pre(context, data);\n }\n }\n\n if (runIsAsync) {\n const runAsyncFn = run as RunTimedAsync<TContext, TInput>;\n const duration = nextNonce ? await runAsyncFn(context, data, nextNonce()) : await runAsyncFn(context, data);\n sampleDuration += duration;\n } else {\n const runSyncFn = run as RunTimedSync<TContext, TInput>;\n const duration = nextNonce ? runSyncFn(context, data, nextNonce()) : runSyncFn(context, data);\n sampleDuration += duration;\n }\n\n if (post) {\n if (postIsAsync) {\n await post(context, data);\n } else {\n post(context, data);\n }\n }\n }\n return (sampleDuration * DURATION_SCALE) / BigInt(batchSize);\n};\n\nconst tuneParameters = async <TContext, TInput>({\n initialBatch,\n run,\n runRaw,\n runIsAsync,\n pre,\n preIsAsync,\n post,\n postIsAsync,\n context,\n data,\n minCycles,\n relThreshold,\n maxCycles,\n nextNonce,\n}: {\n initialBatch: number;\n run: RunTimedSync<TContext, TInput> | RunTimedAsync<TContext, TInput>;\n runRaw: StepFn<TContext, TInput>;\n runIsAsync: boolean;\n pre?: StepFn<TContext, TInput>;\n preIsAsync: boolean;\n post?: StepFn<TContext, TInput>;\n postIsAsync: boolean;\n context: TContext;\n data: TInput;\n minCycles: number;\n relThreshold: number;\n maxCycles: number;\n nextNonce: (() => number) | null;\n}) => {\n let batchSize = initialBatch;\n let bestCv = Number.POSITIVE_INFINITY;\n let bestBatch = batchSize;\n\n for (let attempt = 0; attempt < 3; attempt++) {\n const samples: number[] = [];\n const sampleCount = Math.min(8, maxCycles);\n for (let s = 0; s < sampleCount; s++) {\n const duration = await collectSample({\n batchSize,\n run,\n runRaw,\n runIsAsync,\n pre,\n preIsAsync,\n post,\n postIsAsync,\n context,\n data,\n nextNonce,\n });\n samples.push(Number(duration));\n }\n const mean = samples.reduce((acc, v) => acc + v, 0) / samples.length;\n const variance = samples.reduce((acc, v) => acc + (v - mean) * (v - mean), 0) / Math.max(1, samples.length - 1);\n const stddev = Math.sqrt(variance);\n const cv = mean === 0 ? Number.POSITIVE_INFINITY : stddev / mean;\n\n if (cv < bestCv) {\n bestCv = cv;\n bestBatch = batchSize;\n }\n\n if (cv <= relThreshold || batchSize >= MAX_BATCH) {\n break;\n }\n batchSize = Math.min(MAX_BATCH, batchSize * 2);\n }\n\n const tunedRel = bestCv < relThreshold ? Math.max(bestCv * 1.5, relThreshold * 0.5) : relThreshold;\n const tunedMin = Math.min(maxCycles, Math.max(minCycles, Math.ceil(minCycles * Math.max(1, bestCv / (relThreshold || 1e-6)))));\n\n return { batchSize: bestBatch, relThreshold: tunedRel, minCycles: tunedMin };\n};\n\nconst createGCTracker = () => {\n if (process.env.OVERTAKE_GC_OBSERVER !== '1') {\n return null;\n }\n if (typeof PerformanceObserver === 'undefined') {\n return null;\n }\n\n const events: GCEvent[] = [];\n const observer = new PerformanceObserver((list) => {\n for (const entry of list.getEntries()) {\n events.push({ start: entry.startTime, end: entry.startTime + entry.duration });\n }\n });\n\n try {\n observer.observe({ entryTypes: ['gc'] });\n } catch {\n return null;\n }\n\n const overlaps = (start: number, end: number) => {\n let noisy = false;\n for (let i = events.length - 1; i >= 0; i--) {\n const event = events[i];\n if (event.end < start - 5_000) {\n events.splice(i, 1);\n continue;\n }\n if (event.start <= end && event.end >= start) {\n noisy = true;\n }\n }\n return noisy;\n };\n\n const dispose = () => observer.disconnect();\n\n return { overlaps, dispose };\n};\n\nconst pushWindow = (arr: number[], value: number, cap: number) => {\n if (arr.length === cap) {\n arr.shift();\n }\n arr.push(value);\n};\n\nconst medianAndIqr = (arr: number[]) => {\n if (arr.length === 0) return { median: 0, iqr: 0 };\n for (let i = 0; i < arr.length; i++) {\n OUTLIER_SCRATCH[i] = arr[i];\n }\n const view = OUTLIER_SCRATCH.subarray(0, arr.length);\n view.sort();\n const mid = Math.floor(view.length / 2);\n const median = view.length % 2 === 0 ? (view[mid - 1] + view[mid]) / 2 : view[mid];\n const q1Idx = Math.floor(view.length * 0.25);\n const q3Idx = Math.floor(view.length * 0.75);\n const q1 = view[q1Idx];\n const q3 = view[q3Idx];\n return { median, iqr: q3 - q1 };\n};\n\nconst windowCv = (arr: number[]) => {\n if (arr.length < 2) return Number.POSITIVE_INFINITY;\n const mean = arr.reduce((a, v) => a + v, 0) / arr.length;\n const variance = arr.reduce((a, v) => a + (v - mean) * (v - mean), 0) / (arr.length - 1);\n const stddev = Math.sqrt(variance);\n return mean === 0 ? Number.POSITIVE_INFINITY : stddev / mean;\n};\n\nexport const benchmark = async <TContext, TInput>({\n setup,\n teardown,\n pre,\n run: runRaw,\n post,\n data,\n\n warmupCycles,\n minCycles,\n absThreshold,\n relThreshold,\n gcObserver = false,\n\n durationsSAB,\n controlSAB,\n}: Required<Options<TContext, TInput>>) => {\n const durations = new BigUint64Array(durationsSAB);\n const control = new Int32Array(controlSAB);\n\n control[Control.INDEX] = 0;\n control[Control.PROGRESS] = 0;\n control[Control.COMPLETE] = 255;\n\n const context = (await setup?.()) as TContext;\n const input = data as TInput;\n const maxCycles = durations.length;\n const gcWatcher = gcObserver ? new GCWatcher() : null;\n const gcTracker = gcObserver ? createGCTracker() : null;\n\n try {\n // classify sync/async and capture initial duration\n let preIsAsync = false;\n if (pre) {\n const preResult = pre(context, input);\n preIsAsync = isThenable(preResult);\n if (preIsAsync) {\n await preResult;\n }\n }\n\n const probeStart = hr();\n const probeResult = runRaw(context, input);\n const runIsAsync = isThenable(probeResult);\n if (runIsAsync) {\n const resolved = await probeResult;\n consume(resolved);\n } else {\n consume(probeResult);\n }\n const durationProbeRaw = hr() - probeStart;\n\n let postIsAsync = false;\n if (post) {\n const postResult = post(context, input);\n postIsAsync = isThenable(postResult);\n if (postIsAsync) {\n await postResult;\n }\n }\n\n const timerOverhead = runIsAsync ? 0n : measureTimerOverhead();\n let durationProbe = runIsAsync ? durationProbeRaw : durationProbeRaw > timerOverhead ? durationProbeRaw - timerOverhead : 0n;\n\n const shouldPerturbInput = process.env.OVERTAKE_PERTURB_INPUT === '1';\n let nonce = 0;\n const nextNonce = shouldPerturbInput\n ? () => {\n nonce = (nonce + 1) | 0;\n return nonce;\n }\n : null;\n\n if (!runIsAsync && !pre && !post) {\n const batchProbeSize = 10_000;\n const batchProbeStart = hr();\n if (nextNonce) {\n for (let i = 0; i < batchProbeSize; i++) {\n consume((runRaw as Function)(context, input, nextNonce()));\n }\n } else {\n for (let i = 0; i < batchProbeSize; i++) {\n consume(runRaw(context, input));\n }\n }\n durationProbe = (hr() - batchProbeStart) / BigInt(batchProbeSize);\n }\n\n const runTimedSync = runIsAsync ? null : runSync(runRaw, timerOverhead);\n const runTimedAsync = runIsAsync ? runAsync(runRaw) : null;\n const run = runIsAsync ? runTimedAsync! : runTimedSync!;\n\n const runOnceSync: RunTimedSync<TContext, TInput> | null = runIsAsync ? null : nextNonce ? (ctx, dataValue) => runTimedSync!(ctx, dataValue, nextNonce()) : runTimedSync!;\n const runOnceAsync: RunTimedAsync<TContext, TInput> | null = runIsAsync ? (nextNonce ? (ctx, dataValue) => runTimedAsync!(ctx, dataValue, nextNonce()) : runTimedAsync!) : null;\n\n const preSync = preIsAsync ? null : pre;\n const preAsync = preIsAsync ? pre : null;\n const postSync = postIsAsync ? null : post;\n const postAsync = postIsAsync ? post : null;\n\n // choose batch size to amortize timer overhead\n const durationPerRun = durationProbe === 0n ? 1n : durationProbe;\n const suggestedBatch = Number(TARGET_SAMPLE_NS / durationPerRun);\n const minBatchForFastOps = durationProbe < 100n ? 100_000 : 1;\n const initialBatchSize = Math.min(MAX_BATCH, Math.max(minBatchForFastOps, suggestedBatch));\n\n // auto-tune based on warmup samples\n const tuned = await tuneParameters({\n initialBatch: initialBatchSize,\n run,\n runRaw,\n runIsAsync,\n pre,\n preIsAsync,\n post,\n postIsAsync,\n context,\n data: input,\n minCycles,\n relThreshold,\n maxCycles,\n nextNonce,\n });\n let batchSize = tuned.batchSize;\n minCycles = tuned.minCycles;\n relThreshold = tuned.relThreshold;\n\n // warmup: run until requested cycles, adapt if unstable\n const warmupStart = performance.now();\n let warmupRemaining = warmupCycles;\n const warmupWindow: number[] = [];\n const warmupCap = Math.max(warmupCycles, Math.min(maxCycles, warmupCycles * 4 || 1000));\n const canBatchTime = !runIsAsync && !preSync && !preAsync && !postSync && !postAsync;\n\n const runWarmup = async () => {\n if (canBatchTime) {\n const batchStart = hr();\n if (nextNonce) {\n for (let b = 0; b < batchSize; b++) {\n consume((runRaw as Function)(context, input, nextNonce()));\n }\n } else {\n for (let b = 0; b < batchSize; b++) {\n consume(runRaw(context, input));\n }\n }\n return ((hr() - batchStart) * DURATION_SCALE) / BigInt(batchSize);\n }\n\n if (preSync) {\n preSync(context, input);\n } else if (preAsync) {\n await preAsync(context, input);\n }\n\n const duration = runIsAsync ? await runOnceAsync!(context, input) : runOnceSync!(context, input);\n\n if (postSync) {\n postSync(context, input);\n } else if (postAsync) {\n await postAsync(context, input);\n }\n\n return duration;\n };\n\n while (performance.now() - warmupStart < 1_000 && warmupRemaining > 0) {\n const duration = await runWarmup();\n pushWindow(warmupWindow, Number(duration), warmupCap);\n warmupRemaining--;\n }\n let warmupDone = 0;\n while (warmupDone < warmupRemaining) {\n const duration = await runWarmup();\n pushWindow(warmupWindow, Number(duration), warmupCap);\n warmupDone++;\n if (global.gc && warmupDone % GC_STRIDE === 0) {\n global.gc();\n }\n }\n while (warmupWindow.length >= 8 && warmupWindow.length < warmupCap) {\n const cv = windowCv(warmupWindow);\n if (cv <= relThreshold * 2) {\n break;\n }\n const duration = await runWarmup();\n pushWindow(warmupWindow, Number(duration), warmupCap);\n }\n\n let i = 0;\n let mean = 0n;\n let m2 = 0n;\n const outlierWindow: number[] = [];\n let skipped = 0;\n const maxSkipped = maxCycles * 10;\n let disableFiltering = false;\n\n while (true) {\n if (i >= maxCycles) break;\n if (!disableFiltering && skipped >= maxSkipped) {\n console.error(`Warning: ${skipped} samples skipped due to noise/outlier detection. ` + `Disabling filtering for remaining samples. Results may have higher variance.`);\n disableFiltering = true;\n }\n\n if (global.gc && i > 0 && i % GC_STRIDE === 0) {\n global.gc();\n }\n\n const gcMarker = gcWatcher?.start();\n const sampleStart = performance.now();\n let sampleDuration = 0n;\n\n if (canBatchTime) {\n const batchStart = hr();\n if (nextNonce) {\n for (let b = 0; b < batchSize; b++) {\n consume((runRaw as Function)(context, input, nextNonce()));\n }\n } else {\n for (let b = 0; b < batchSize; b++) {\n consume(runRaw(context, input));\n }\n }\n const batchDuration = hr() - batchStart;\n sampleDuration = (batchDuration * DURATION_SCALE) / BigInt(batchSize);\n } else {\n for (let b = 0; b < batchSize; b++) {\n if (preSync) {\n preSync(context, input);\n } else if (preAsync) {\n await preAsync(context, input);\n }\n\n const duration = runIsAsync ? await runOnceAsync!(context, input) : runOnceSync!(context, input);\n sampleDuration += duration;\n\n if (postSync) {\n postSync(context, input);\n } else if (postAsync) {\n await postAsync(context, input);\n }\n }\n sampleDuration = (sampleDuration * DURATION_SCALE) / BigInt(batchSize);\n }\n\n const sampleEnd = performance.now();\n if (!disableFiltering) {\n const gcNoise = (gcMarker ? gcWatcher!.seen(gcMarker) : false) || (gcTracker?.overlaps(sampleStart, sampleEnd) ?? false);\n if (gcNoise) {\n skipped++;\n continue;\n }\n }\n\n const durationNumber = Number(sampleDuration);\n pushWindow(outlierWindow, durationNumber, OUTLIER_WINDOW);\n if (!disableFiltering) {\n const { median, iqr } = medianAndIqr(outlierWindow);\n const maxAllowed = median + OUTLIER_IQR_MULTIPLIER * iqr || Number.POSITIVE_INFINITY;\n if (outlierWindow.length >= 8 && durationNumber > maxAllowed && durationNumber - median > OUTLIER_ABS_THRESHOLD_NS) {\n skipped++;\n continue;\n }\n\n const meanNumber = Number(mean);\n if (i >= 8 && meanNumber > 0 && durationNumber > OUTLIER_MULTIPLIER * meanNumber && durationNumber - meanNumber > OUTLIER_ABS_THRESHOLD_NS) {\n skipped++;\n continue;\n }\n }\n\n durations[i++] = sampleDuration;\n const delta = sampleDuration - mean;\n mean += delta / BigInt(i);\n m2 += delta * (sampleDuration - mean);\n\n const progress = Math.max(i / maxCycles) * COMPLETE_VALUE;\n if (i % PROGRESS_STRIDE === 0) {\n control[Control.PROGRESS] = progress;\n }\n\n if (i >= minCycles) {\n const variance = Number(m2) / (i - 1);\n const stddev = Math.sqrt(variance);\n if (stddev <= Number(absThreshold)) {\n break;\n }\n\n const meanNum = Number(mean);\n const cov = stddev / (meanNum || 1);\n if (cov <= relThreshold) {\n break;\n }\n }\n }\n\n control[Control.INDEX] = i;\n control[Control.COMPLETE] = 0;\n } catch (e) {\n console.error(e && typeof e === 'object' && 'stack' in e ? e.stack : e);\n control[Control.COMPLETE] = 1;\n } finally {\n gcTracker?.dispose?.();\n try {\n await teardown?.(context);\n } catch (e) {\n control[Control.COMPLETE] = 2;\n console.error(e && typeof e === 'object' && 'stack' in e ? e.stack : e);\n }\n }\n\n return control[Control.COMPLETE];\n};\n"],"names":["benchmark","COMPLETE_VALUE","hr","process","hrtime","bigint","bind","sink","Int32Array","SharedArrayBuffer","BYTES_PER_ELEMENT","consume","value","payload","Number","isFinite","Math","trunc","length","Atomics","xor","runSync","run","overhead","args","start","result","duration","runAsync","isThenable","then","TARGET_SAMPLE_NS","MAX_BATCH","PROGRESS_STRIDE","GC_STRIDE","OUTLIER_MULTIPLIER","OUTLIER_IQR_MULTIPLIER","OUTLIER_WINDOW","OUTLIER_ABS_THRESHOLD_NS","BASELINE_SAMPLES","OUTLIER_SCRATCH","Float64Array","measureTimerOverhead","total","i","BigInt","collectSample","batchSize","runRaw","runIsAsync","pre","preIsAsync","post","postIsAsync","context","data","nextNonce","canBatchTime","batchStart","b","DURATION_SCALE","sampleDuration","runAsyncFn","runSyncFn","tuneParameters","initialBatch","minCycles","relThreshold","maxCycles","bestCv","POSITIVE_INFINITY","bestBatch","attempt","samples","sampleCount","min","s","push","mean","reduce","acc","v","variance","max","stddev","sqrt","cv","tunedRel","tunedMin","ceil","createGCTracker","env","OVERTAKE_GC_OBSERVER","PerformanceObserver","events","observer","list","entry","getEntries","startTime","end","observe","entryTypes","overlaps","noisy","event","splice","dispose","disconnect","pushWindow","arr","cap","shift","medianAndIqr","median","iqr","view","subarray","sort","mid","floor","q1Idx","q3Idx","q1","q3","windowCv","a","setup","teardown","warmupCycles","absThreshold","gcObserver","durationsSAB","controlSAB","durations","BigUint64Array","control","Control","INDEX","PROGRESS","COMPLETE","input","gcWatcher","GCWatcher","gcTracker","preResult","probeStart","probeResult","resolved","durationProbeRaw","postResult","timerOverhead","durationProbe","shouldPerturbInput","OVERTAKE_PERTURB_INPUT","nonce","batchProbeSize","batchProbeStart","runTimedSync","runTimedAsync","runOnceSync","ctx","dataValue","runOnceAsync","preSync","preAsync","postSync","postAsync","durationPerRun","suggestedBatch","minBatchForFastOps","initialBatchSize","tuned","warmupStart","performance","now","warmupRemaining","warmupWindow","warmupCap","runWarmup","warmupDone","global","gc","m2","outlierWindow","skipped","maxSkipped","disableFiltering","console","error","gcMarker","sampleStart","batchDuration","sampleEnd","gcNoise","seen","durationNumber","maxAllowed","meanNumber","delta","progress","meanNum","cov","e","stack"],"mappings":"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"}
package/build/runner.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { performance, PerformanceObserver } from 'node:perf_hooks';
2
- import { Control } from "./types.js";
2
+ import { Control, DURATION_SCALE } from "./types.js";
3
3
  import { GCWatcher } from "./gc-watcher.js";
4
4
  const COMPLETE_VALUE = 100_00;
5
5
  const hr = process.hrtime.bigint.bind(process.hrtime);
@@ -82,7 +82,7 @@ const collectSample = async ({ batchSize, run, runRaw, runIsAsync, pre, preIsAsy
82
82
  consume(runRaw(context, data));
83
83
  }
84
84
  }
85
- return (hr() - batchStart) / BigInt(batchSize);
85
+ return (hr() - batchStart) * DURATION_SCALE / BigInt(batchSize);
86
86
  }
87
87
  let sampleDuration = 0n;
88
88
  for(let b = 0; b < batchSize; b++){
@@ -110,7 +110,7 @@ const collectSample = async ({ batchSize, run, runRaw, runIsAsync, pre, preIsAsy
110
110
  }
111
111
  }
112
112
  }
113
- return sampleDuration / BigInt(batchSize);
113
+ return sampleDuration * DURATION_SCALE / BigInt(batchSize);
114
114
  };
115
115
  const tuneParameters = async ({ initialBatch, run, runRaw, runIsAsync, pre, preIsAsync, post, postIsAsync, context, data, minCycles, relThreshold, maxCycles, nextNonce })=>{
116
116
  let batchSize = initialBatch;
@@ -344,7 +344,7 @@ export const benchmark = async ({ setup, teardown, pre, run: runRaw, post, data,
344
344
  consume(runRaw(context, input));
345
345
  }
346
346
  }
347
- return (hr() - batchStart) / BigInt(batchSize);
347
+ return (hr() - batchStart) * DURATION_SCALE / BigInt(batchSize);
348
348
  }
349
349
  if (preSync) {
350
350
  preSync(context, input);
@@ -412,7 +412,7 @@ export const benchmark = async ({ setup, teardown, pre, run: runRaw, post, data,
412
412
  }
413
413
  }
414
414
  const batchDuration = hr() - batchStart;
415
- sampleDuration = batchDuration / BigInt(batchSize);
415
+ sampleDuration = batchDuration * DURATION_SCALE / BigInt(batchSize);
416
416
  } else {
417
417
  for(let b = 0; b < batchSize; b++){
418
418
  if (preSync) {
@@ -428,7 +428,7 @@ export const benchmark = async ({ setup, teardown, pre, run: runRaw, post, data,
428
428
  await postAsync(context, input);
429
429
  }
430
430
  }
431
- sampleDuration /= BigInt(batchSize);
431
+ sampleDuration = sampleDuration * DURATION_SCALE / BigInt(batchSize);
432
432
  }
433
433
  const sampleEnd = performance.now();
434
434
  if (!disableFiltering) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/runner.ts"],"sourcesContent":["import { performance, PerformanceObserver } from 'node:perf_hooks';\nimport { Options, Control } from './types.js';\nimport { GCWatcher } from './gc-watcher.js';\nimport { StepFn } from './types.js';\n\nconst COMPLETE_VALUE = 100_00;\n\nconst hr = process.hrtime.bigint.bind(process.hrtime);\n\nconst sink = new Int32Array(new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT));\nconst consume = (value: unknown) => {\n let payload = 0;\n switch (typeof value) {\n case 'number':\n payload = Number.isFinite(value) ? Math.trunc(value) : 0;\n break;\n case 'bigint':\n payload = Number(value & 0xffff_ffffn);\n break;\n case 'string':\n payload = value.length;\n break;\n case 'boolean':\n payload = value ? 1 : 0;\n break;\n case 'object':\n payload = value === null ? 0 : 1;\n break;\n case 'function':\n payload = 1;\n break;\n default:\n payload = -1;\n }\n Atomics.xor(sink, 0, payload);\n};\n\nconst runSync = (run: Function, overhead: bigint) => {\n return (...args: unknown[]) => {\n const start = hr();\n const result = run(...args);\n consume(result);\n const duration = hr() - start;\n return duration > overhead ? duration - overhead : 0n;\n };\n};\n\nconst runAsync = (run: Function) => {\n return async (...args: unknown[]) => {\n const start = hr();\n const result = await run(...args);\n consume(result);\n return hr() - start;\n };\n};\n\nconst isThenable = (value: unknown): value is PromiseLike<unknown> => {\n return value !== null && (typeof value === 'object' || typeof value === 'function') && typeof (value as PromiseLike<unknown>).then === 'function';\n};\n\nconst TARGET_SAMPLE_NS = 1_000_000n; // aim for ~1ms per measured sample\nconst MAX_BATCH = 1_048_576;\nconst PROGRESS_STRIDE = 16;\nconst GC_STRIDE = 32;\nconst OUTLIER_MULTIPLIER = 4;\nconst OUTLIER_IQR_MULTIPLIER = 3;\nconst OUTLIER_WINDOW = 64;\nconst OUTLIER_ABS_THRESHOLD_NS = 10_000;\nconst BASELINE_SAMPLES = 16;\nconst OUTLIER_SCRATCH = new Float64Array(OUTLIER_WINDOW);\n\ntype GCEvent = { start: number; end: number };\ntype RunTimedSync<TContext, TInput> = (ctx: TContext, data: TInput, nonce?: number) => bigint;\ntype RunTimedAsync<TContext, TInput> = (ctx: TContext, data: TInput, nonce?: number) => Promise<bigint>;\n\nconst measureTimerOverhead = () => {\n let total = 0n;\n for (let i = 0; i < BASELINE_SAMPLES; i++) {\n const start = hr();\n consume(0);\n total += hr() - start;\n }\n return total / BigInt(BASELINE_SAMPLES);\n};\n\nconst collectSample = async <TContext, TInput>({\n batchSize,\n run,\n runRaw,\n runIsAsync,\n pre,\n preIsAsync,\n post,\n postIsAsync,\n context,\n data,\n nextNonce,\n}: {\n batchSize: number;\n run: RunTimedSync<TContext, TInput> | RunTimedAsync<TContext, TInput>;\n runRaw: StepFn<TContext, TInput>;\n runIsAsync: boolean;\n pre: StepFn<TContext, TInput> | undefined;\n preIsAsync: boolean;\n post: StepFn<TContext, TInput> | undefined;\n postIsAsync: boolean;\n context: TContext;\n data: TInput;\n nextNonce: (() => number) | null;\n}) => {\n const canBatchTime = !runIsAsync && !pre && !post;\n if (canBatchTime) {\n const batchStart = hr();\n if (nextNonce) {\n for (let b = 0; b < batchSize; b++) {\n consume((runRaw as Function)(context, data, nextNonce()));\n }\n } else {\n for (let b = 0; b < batchSize; b++) {\n consume(runRaw(context, data));\n }\n }\n return (hr() - batchStart) / BigInt(batchSize);\n }\n\n let sampleDuration = 0n;\n for (let b = 0; b < batchSize; b++) {\n if (pre) {\n if (preIsAsync) {\n await pre(context, data);\n } else {\n pre(context, data);\n }\n }\n\n if (runIsAsync) {\n const runAsyncFn = run as RunTimedAsync<TContext, TInput>;\n const duration = nextNonce ? await runAsyncFn(context, data, nextNonce()) : await runAsyncFn(context, data);\n sampleDuration += duration;\n } else {\n const runSyncFn = run as RunTimedSync<TContext, TInput>;\n const duration = nextNonce ? runSyncFn(context, data, nextNonce()) : runSyncFn(context, data);\n sampleDuration += duration;\n }\n\n if (post) {\n if (postIsAsync) {\n await post(context, data);\n } else {\n post(context, data);\n }\n }\n }\n return sampleDuration / BigInt(batchSize);\n};\n\nconst tuneParameters = async <TContext, TInput>({\n initialBatch,\n run,\n runRaw,\n runIsAsync,\n pre,\n preIsAsync,\n post,\n postIsAsync,\n context,\n data,\n minCycles,\n relThreshold,\n maxCycles,\n nextNonce,\n}: {\n initialBatch: number;\n run: RunTimedSync<TContext, TInput> | RunTimedAsync<TContext, TInput>;\n runRaw: StepFn<TContext, TInput>;\n runIsAsync: boolean;\n pre?: StepFn<TContext, TInput>;\n preIsAsync: boolean;\n post?: StepFn<TContext, TInput>;\n postIsAsync: boolean;\n context: TContext;\n data: TInput;\n minCycles: number;\n relThreshold: number;\n maxCycles: number;\n nextNonce: (() => number) | null;\n}) => {\n let batchSize = initialBatch;\n let bestCv = Number.POSITIVE_INFINITY;\n let bestBatch = batchSize;\n\n for (let attempt = 0; attempt < 3; attempt++) {\n const samples: number[] = [];\n const sampleCount = Math.min(8, maxCycles);\n for (let s = 0; s < sampleCount; s++) {\n const duration = await collectSample({\n batchSize,\n run,\n runRaw,\n runIsAsync,\n pre,\n preIsAsync,\n post,\n postIsAsync,\n context,\n data,\n nextNonce,\n });\n samples.push(Number(duration));\n }\n const mean = samples.reduce((acc, v) => acc + v, 0) / samples.length;\n const variance = samples.reduce((acc, v) => acc + (v - mean) * (v - mean), 0) / Math.max(1, samples.length - 1);\n const stddev = Math.sqrt(variance);\n const cv = mean === 0 ? Number.POSITIVE_INFINITY : stddev / mean;\n\n if (cv < bestCv) {\n bestCv = cv;\n bestBatch = batchSize;\n }\n\n if (cv <= relThreshold || batchSize >= MAX_BATCH) {\n break;\n }\n batchSize = Math.min(MAX_BATCH, batchSize * 2);\n }\n\n const tunedRel = bestCv < relThreshold ? Math.max(bestCv * 1.5, relThreshold * 0.5) : relThreshold;\n const tunedMin = Math.min(maxCycles, Math.max(minCycles, Math.ceil(minCycles * Math.max(1, bestCv / (relThreshold || 1e-6)))));\n\n return { batchSize: bestBatch, relThreshold: tunedRel, minCycles: tunedMin };\n};\n\nconst createGCTracker = () => {\n if (process.env.OVERTAKE_GC_OBSERVER !== '1') {\n return null;\n }\n if (typeof PerformanceObserver === 'undefined') {\n return null;\n }\n\n const events: GCEvent[] = [];\n const observer = new PerformanceObserver((list) => {\n for (const entry of list.getEntries()) {\n events.push({ start: entry.startTime, end: entry.startTime + entry.duration });\n }\n });\n\n try {\n observer.observe({ entryTypes: ['gc'] });\n } catch {\n return null;\n }\n\n const overlaps = (start: number, end: number) => {\n let noisy = false;\n for (let i = events.length - 1; i >= 0; i--) {\n const event = events[i];\n if (event.end < start - 5_000) {\n events.splice(i, 1);\n continue;\n }\n if (event.start <= end && event.end >= start) {\n noisy = true;\n }\n }\n return noisy;\n };\n\n const dispose = () => observer.disconnect();\n\n return { overlaps, dispose };\n};\n\nconst pushWindow = (arr: number[], value: number, cap: number) => {\n if (arr.length === cap) {\n arr.shift();\n }\n arr.push(value);\n};\n\nconst medianAndIqr = (arr: number[]) => {\n if (arr.length === 0) return { median: 0, iqr: 0 };\n for (let i = 0; i < arr.length; i++) {\n OUTLIER_SCRATCH[i] = arr[i];\n }\n const view = OUTLIER_SCRATCH.subarray(0, arr.length);\n view.sort();\n const mid = Math.floor(view.length / 2);\n const median = view.length % 2 === 0 ? (view[mid - 1] + view[mid]) / 2 : view[mid];\n const q1Idx = Math.floor(view.length * 0.25);\n const q3Idx = Math.floor(view.length * 0.75);\n const q1 = view[q1Idx];\n const q3 = view[q3Idx];\n return { median, iqr: q3 - q1 };\n};\n\nconst windowCv = (arr: number[]) => {\n if (arr.length < 2) return Number.POSITIVE_INFINITY;\n const mean = arr.reduce((a, v) => a + v, 0) / arr.length;\n const variance = arr.reduce((a, v) => a + (v - mean) * (v - mean), 0) / (arr.length - 1);\n const stddev = Math.sqrt(variance);\n return mean === 0 ? Number.POSITIVE_INFINITY : stddev / mean;\n};\n\nexport const benchmark = async <TContext, TInput>({\n setup,\n teardown,\n pre,\n run: runRaw,\n post,\n data,\n\n warmupCycles,\n minCycles,\n absThreshold,\n relThreshold,\n gcObserver = false,\n\n durationsSAB,\n controlSAB,\n}: Required<Options<TContext, TInput>>) => {\n const durations = new BigUint64Array(durationsSAB);\n const control = new Int32Array(controlSAB);\n\n control[Control.INDEX] = 0;\n control[Control.PROGRESS] = 0;\n control[Control.COMPLETE] = 255;\n\n const context = (await setup?.()) as TContext;\n const input = data as TInput;\n const maxCycles = durations.length;\n const gcWatcher = gcObserver ? new GCWatcher() : null;\n const gcTracker = gcObserver ? createGCTracker() : null;\n\n try {\n // classify sync/async and capture initial duration\n let preIsAsync = false;\n if (pre) {\n const preResult = pre(context, input);\n preIsAsync = isThenable(preResult);\n if (preIsAsync) {\n await preResult;\n }\n }\n\n const probeStart = hr();\n const probeResult = runRaw(context, input);\n const runIsAsync = isThenable(probeResult);\n if (runIsAsync) {\n const resolved = await probeResult;\n consume(resolved);\n } else {\n consume(probeResult);\n }\n const durationProbeRaw = hr() - probeStart;\n\n let postIsAsync = false;\n if (post) {\n const postResult = post(context, input);\n postIsAsync = isThenable(postResult);\n if (postIsAsync) {\n await postResult;\n }\n }\n\n const timerOverhead = runIsAsync ? 0n : measureTimerOverhead();\n let durationProbe = runIsAsync ? durationProbeRaw : durationProbeRaw > timerOverhead ? durationProbeRaw - timerOverhead : 0n;\n\n const shouldPerturbInput = process.env.OVERTAKE_PERTURB_INPUT === '1';\n let nonce = 0;\n const nextNonce = shouldPerturbInput\n ? () => {\n nonce = (nonce + 1) | 0;\n return nonce;\n }\n : null;\n\n if (!runIsAsync && !pre && !post) {\n const batchProbeSize = 10_000;\n const batchProbeStart = hr();\n if (nextNonce) {\n for (let i = 0; i < batchProbeSize; i++) {\n consume((runRaw as Function)(context, input, nextNonce()));\n }\n } else {\n for (let i = 0; i < batchProbeSize; i++) {\n consume(runRaw(context, input));\n }\n }\n durationProbe = (hr() - batchProbeStart) / BigInt(batchProbeSize);\n }\n\n const runTimedSync = runIsAsync ? null : runSync(runRaw, timerOverhead);\n const runTimedAsync = runIsAsync ? runAsync(runRaw) : null;\n const run = runIsAsync ? runTimedAsync! : runTimedSync!;\n\n const runOnceSync: RunTimedSync<TContext, TInput> | null = runIsAsync ? null : nextNonce ? (ctx, dataValue) => runTimedSync!(ctx, dataValue, nextNonce()) : runTimedSync!;\n const runOnceAsync: RunTimedAsync<TContext, TInput> | null = runIsAsync ? (nextNonce ? (ctx, dataValue) => runTimedAsync!(ctx, dataValue, nextNonce()) : runTimedAsync!) : null;\n\n const preSync = preIsAsync ? null : pre;\n const preAsync = preIsAsync ? pre : null;\n const postSync = postIsAsync ? null : post;\n const postAsync = postIsAsync ? post : null;\n\n // choose batch size to amortize timer overhead\n const durationPerRun = durationProbe === 0n ? 1n : durationProbe;\n const suggestedBatch = Number(TARGET_SAMPLE_NS / durationPerRun);\n const minBatchForFastOps = durationProbe < 100n ? 100_000 : 1;\n const initialBatchSize = Math.min(MAX_BATCH, Math.max(minBatchForFastOps, suggestedBatch));\n\n // auto-tune based on warmup samples\n const tuned = await tuneParameters({\n initialBatch: initialBatchSize,\n run,\n runRaw,\n runIsAsync,\n pre,\n preIsAsync,\n post,\n postIsAsync,\n context,\n data: input,\n minCycles,\n relThreshold,\n maxCycles,\n nextNonce,\n });\n let batchSize = tuned.batchSize;\n minCycles = tuned.minCycles;\n relThreshold = tuned.relThreshold;\n\n // warmup: run until requested cycles, adapt if unstable\n const warmupStart = performance.now();\n let warmupRemaining = warmupCycles;\n const warmupWindow: number[] = [];\n const warmupCap = Math.max(warmupCycles, Math.min(maxCycles, warmupCycles * 4 || 1000));\n const canBatchTime = !runIsAsync && !preSync && !preAsync && !postSync && !postAsync;\n\n const runWarmup = async () => {\n if (canBatchTime) {\n const batchStart = hr();\n if (nextNonce) {\n for (let b = 0; b < batchSize; b++) {\n consume((runRaw as Function)(context, input, nextNonce()));\n }\n } else {\n for (let b = 0; b < batchSize; b++) {\n consume(runRaw(context, input));\n }\n }\n return (hr() - batchStart) / BigInt(batchSize);\n }\n\n if (preSync) {\n preSync(context, input);\n } else if (preAsync) {\n await preAsync(context, input);\n }\n\n const duration = runIsAsync ? await runOnceAsync!(context, input) : runOnceSync!(context, input);\n\n if (postSync) {\n postSync(context, input);\n } else if (postAsync) {\n await postAsync(context, input);\n }\n\n return duration;\n };\n\n while (performance.now() - warmupStart < 1_000 && warmupRemaining > 0) {\n const duration = await runWarmup();\n pushWindow(warmupWindow, Number(duration), warmupCap);\n warmupRemaining--;\n }\n let warmupDone = 0;\n while (warmupDone < warmupRemaining) {\n const duration = await runWarmup();\n pushWindow(warmupWindow, Number(duration), warmupCap);\n warmupDone++;\n if (global.gc && warmupDone % GC_STRIDE === 0) {\n global.gc();\n }\n }\n while (warmupWindow.length >= 8 && warmupWindow.length < warmupCap) {\n const cv = windowCv(warmupWindow);\n if (cv <= relThreshold * 2) {\n break;\n }\n const duration = await runWarmup();\n pushWindow(warmupWindow, Number(duration), warmupCap);\n }\n\n let i = 0;\n let mean = 0n;\n let m2 = 0n;\n const outlierWindow: number[] = [];\n let skipped = 0;\n const maxSkipped = maxCycles * 10;\n let disableFiltering = false;\n\n while (true) {\n if (i >= maxCycles) break;\n if (!disableFiltering && skipped >= maxSkipped) {\n console.error(`Warning: ${skipped} samples skipped due to noise/outlier detection. ` + `Disabling filtering for remaining samples. Results may have higher variance.`);\n disableFiltering = true;\n }\n\n if (global.gc && i > 0 && i % GC_STRIDE === 0) {\n global.gc();\n }\n\n const gcMarker = gcWatcher?.start();\n const sampleStart = performance.now();\n let sampleDuration = 0n;\n\n if (canBatchTime) {\n const batchStart = hr();\n if (nextNonce) {\n for (let b = 0; b < batchSize; b++) {\n consume((runRaw as Function)(context, input, nextNonce()));\n }\n } else {\n for (let b = 0; b < batchSize; b++) {\n consume(runRaw(context, input));\n }\n }\n const batchDuration = hr() - batchStart;\n sampleDuration = batchDuration / BigInt(batchSize);\n } else {\n for (let b = 0; b < batchSize; b++) {\n if (preSync) {\n preSync(context, input);\n } else if (preAsync) {\n await preAsync(context, input);\n }\n\n const duration = runIsAsync ? await runOnceAsync!(context, input) : runOnceSync!(context, input);\n sampleDuration += duration;\n\n if (postSync) {\n postSync(context, input);\n } else if (postAsync) {\n await postAsync(context, input);\n }\n }\n sampleDuration /= BigInt(batchSize);\n }\n\n const sampleEnd = performance.now();\n if (!disableFiltering) {\n const gcNoise = (gcMarker ? gcWatcher!.seen(gcMarker) : false) || (gcTracker?.overlaps(sampleStart, sampleEnd) ?? false);\n if (gcNoise) {\n skipped++;\n continue;\n }\n }\n\n const durationNumber = Number(sampleDuration);\n pushWindow(outlierWindow, durationNumber, OUTLIER_WINDOW);\n if (!disableFiltering) {\n const { median, iqr } = medianAndIqr(outlierWindow);\n const maxAllowed = median + OUTLIER_IQR_MULTIPLIER * iqr || Number.POSITIVE_INFINITY;\n if (outlierWindow.length >= 8 && durationNumber > maxAllowed && durationNumber - median > OUTLIER_ABS_THRESHOLD_NS) {\n skipped++;\n continue;\n }\n\n const meanNumber = Number(mean);\n if (i >= 8 && meanNumber > 0 && durationNumber > OUTLIER_MULTIPLIER * meanNumber && durationNumber - meanNumber > OUTLIER_ABS_THRESHOLD_NS) {\n skipped++;\n continue;\n }\n }\n\n durations[i++] = sampleDuration;\n const delta = sampleDuration - mean;\n mean += delta / BigInt(i);\n m2 += delta * (sampleDuration - mean);\n\n const progress = Math.max(i / maxCycles) * COMPLETE_VALUE;\n if (i % PROGRESS_STRIDE === 0) {\n control[Control.PROGRESS] = progress;\n }\n\n if (i >= minCycles) {\n const variance = Number(m2) / (i - 1);\n const stddev = Math.sqrt(variance);\n if (stddev <= Number(absThreshold)) {\n break;\n }\n\n const meanNum = Number(mean);\n const cov = stddev / (meanNum || 1);\n if (cov <= relThreshold) {\n break;\n }\n }\n }\n\n control[Control.INDEX] = i;\n control[Control.COMPLETE] = 0;\n } catch (e) {\n console.error(e && typeof e === 'object' && 'stack' in e ? e.stack : e);\n control[Control.COMPLETE] = 1;\n } finally {\n gcTracker?.dispose?.();\n try {\n await teardown?.(context);\n } catch (e) {\n control[Control.COMPLETE] = 2;\n console.error(e && typeof e === 'object' && 'stack' in e ? e.stack : e);\n }\n }\n\n return control[Control.COMPLETE];\n};\n"],"names":["performance","PerformanceObserver","Control","GCWatcher","COMPLETE_VALUE","hr","process","hrtime","bigint","bind","sink","Int32Array","SharedArrayBuffer","BYTES_PER_ELEMENT","consume","value","payload","Number","isFinite","Math","trunc","length","Atomics","xor","runSync","run","overhead","args","start","result","duration","runAsync","isThenable","then","TARGET_SAMPLE_NS","MAX_BATCH","PROGRESS_STRIDE","GC_STRIDE","OUTLIER_MULTIPLIER","OUTLIER_IQR_MULTIPLIER","OUTLIER_WINDOW","OUTLIER_ABS_THRESHOLD_NS","BASELINE_SAMPLES","OUTLIER_SCRATCH","Float64Array","measureTimerOverhead","total","i","BigInt","collectSample","batchSize","runRaw","runIsAsync","pre","preIsAsync","post","postIsAsync","context","data","nextNonce","canBatchTime","batchStart","b","sampleDuration","runAsyncFn","runSyncFn","tuneParameters","initialBatch","minCycles","relThreshold","maxCycles","bestCv","POSITIVE_INFINITY","bestBatch","attempt","samples","sampleCount","min","s","push","mean","reduce","acc","v","variance","max","stddev","sqrt","cv","tunedRel","tunedMin","ceil","createGCTracker","env","OVERTAKE_GC_OBSERVER","events","observer","list","entry","getEntries","startTime","end","observe","entryTypes","overlaps","noisy","event","splice","dispose","disconnect","pushWindow","arr","cap","shift","medianAndIqr","median","iqr","view","subarray","sort","mid","floor","q1Idx","q3Idx","q1","q3","windowCv","a","benchmark","setup","teardown","warmupCycles","absThreshold","gcObserver","durationsSAB","controlSAB","durations","BigUint64Array","control","INDEX","PROGRESS","COMPLETE","input","gcWatcher","gcTracker","preResult","probeStart","probeResult","resolved","durationProbeRaw","postResult","timerOverhead","durationProbe","shouldPerturbInput","OVERTAKE_PERTURB_INPUT","nonce","batchProbeSize","batchProbeStart","runTimedSync","runTimedAsync","runOnceSync","ctx","dataValue","runOnceAsync","preSync","preAsync","postSync","postAsync","durationPerRun","suggestedBatch","minBatchForFastOps","initialBatchSize","tuned","warmupStart","now","warmupRemaining","warmupWindow","warmupCap","runWarmup","warmupDone","global","gc","m2","outlierWindow","skipped","maxSkipped","disableFiltering","console","error","gcMarker","sampleStart","batchDuration","sampleEnd","gcNoise","seen","durationNumber","maxAllowed","meanNumber","delta","progress","meanNum","cov","e","stack"],"mappings":"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"}
1
+ {"version":3,"sources":["../src/runner.ts"],"sourcesContent":["import { performance, PerformanceObserver } from 'node:perf_hooks';\nimport { Options, Control, DURATION_SCALE } from './types.js';\nimport { GCWatcher } from './gc-watcher.js';\nimport { StepFn } from './types.js';\n\nconst COMPLETE_VALUE = 100_00;\n\nconst hr = process.hrtime.bigint.bind(process.hrtime);\n\nconst sink = new Int32Array(new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT));\nconst consume = (value: unknown) => {\n let payload = 0;\n switch (typeof value) {\n case 'number':\n payload = Number.isFinite(value) ? Math.trunc(value) : 0;\n break;\n case 'bigint':\n payload = Number(value & 0xffff_ffffn);\n break;\n case 'string':\n payload = value.length;\n break;\n case 'boolean':\n payload = value ? 1 : 0;\n break;\n case 'object':\n payload = value === null ? 0 : 1;\n break;\n case 'function':\n payload = 1;\n break;\n default:\n payload = -1;\n }\n Atomics.xor(sink, 0, payload);\n};\n\nconst runSync = (run: Function, overhead: bigint) => {\n return (...args: unknown[]) => {\n const start = hr();\n const result = run(...args);\n consume(result);\n const duration = hr() - start;\n return duration > overhead ? duration - overhead : 0n;\n };\n};\n\nconst runAsync = (run: Function) => {\n return async (...args: unknown[]) => {\n const start = hr();\n const result = await run(...args);\n consume(result);\n return hr() - start;\n };\n};\n\nconst isThenable = (value: unknown): value is PromiseLike<unknown> => {\n return value !== null && (typeof value === 'object' || typeof value === 'function') && typeof (value as PromiseLike<unknown>).then === 'function';\n};\n\nconst TARGET_SAMPLE_NS = 1_000_000n; // aim for ~1ms per measured sample\nconst MAX_BATCH = 1_048_576;\nconst PROGRESS_STRIDE = 16;\nconst GC_STRIDE = 32;\nconst OUTLIER_MULTIPLIER = 4;\nconst OUTLIER_IQR_MULTIPLIER = 3;\nconst OUTLIER_WINDOW = 64;\nconst OUTLIER_ABS_THRESHOLD_NS = 10_000;\nconst BASELINE_SAMPLES = 16;\nconst OUTLIER_SCRATCH = new Float64Array(OUTLIER_WINDOW);\n\ntype GCEvent = { start: number; end: number };\ntype RunTimedSync<TContext, TInput> = (ctx: TContext, data: TInput, nonce?: number) => bigint;\ntype RunTimedAsync<TContext, TInput> = (ctx: TContext, data: TInput, nonce?: number) => Promise<bigint>;\n\nconst measureTimerOverhead = () => {\n let total = 0n;\n for (let i = 0; i < BASELINE_SAMPLES; i++) {\n const start = hr();\n consume(0);\n total += hr() - start;\n }\n return total / BigInt(BASELINE_SAMPLES);\n};\n\nconst collectSample = async <TContext, TInput>({\n batchSize,\n run,\n runRaw,\n runIsAsync,\n pre,\n preIsAsync,\n post,\n postIsAsync,\n context,\n data,\n nextNonce,\n}: {\n batchSize: number;\n run: RunTimedSync<TContext, TInput> | RunTimedAsync<TContext, TInput>;\n runRaw: StepFn<TContext, TInput>;\n runIsAsync: boolean;\n pre: StepFn<TContext, TInput> | undefined;\n preIsAsync: boolean;\n post: StepFn<TContext, TInput> | undefined;\n postIsAsync: boolean;\n context: TContext;\n data: TInput;\n nextNonce: (() => number) | null;\n}) => {\n const canBatchTime = !runIsAsync && !pre && !post;\n if (canBatchTime) {\n const batchStart = hr();\n if (nextNonce) {\n for (let b = 0; b < batchSize; b++) {\n consume((runRaw as Function)(context, data, nextNonce()));\n }\n } else {\n for (let b = 0; b < batchSize; b++) {\n consume(runRaw(context, data));\n }\n }\n return ((hr() - batchStart) * DURATION_SCALE) / BigInt(batchSize);\n }\n\n let sampleDuration = 0n;\n for (let b = 0; b < batchSize; b++) {\n if (pre) {\n if (preIsAsync) {\n await pre(context, data);\n } else {\n pre(context, data);\n }\n }\n\n if (runIsAsync) {\n const runAsyncFn = run as RunTimedAsync<TContext, TInput>;\n const duration = nextNonce ? await runAsyncFn(context, data, nextNonce()) : await runAsyncFn(context, data);\n sampleDuration += duration;\n } else {\n const runSyncFn = run as RunTimedSync<TContext, TInput>;\n const duration = nextNonce ? runSyncFn(context, data, nextNonce()) : runSyncFn(context, data);\n sampleDuration += duration;\n }\n\n if (post) {\n if (postIsAsync) {\n await post(context, data);\n } else {\n post(context, data);\n }\n }\n }\n return (sampleDuration * DURATION_SCALE) / BigInt(batchSize);\n};\n\nconst tuneParameters = async <TContext, TInput>({\n initialBatch,\n run,\n runRaw,\n runIsAsync,\n pre,\n preIsAsync,\n post,\n postIsAsync,\n context,\n data,\n minCycles,\n relThreshold,\n maxCycles,\n nextNonce,\n}: {\n initialBatch: number;\n run: RunTimedSync<TContext, TInput> | RunTimedAsync<TContext, TInput>;\n runRaw: StepFn<TContext, TInput>;\n runIsAsync: boolean;\n pre?: StepFn<TContext, TInput>;\n preIsAsync: boolean;\n post?: StepFn<TContext, TInput>;\n postIsAsync: boolean;\n context: TContext;\n data: TInput;\n minCycles: number;\n relThreshold: number;\n maxCycles: number;\n nextNonce: (() => number) | null;\n}) => {\n let batchSize = initialBatch;\n let bestCv = Number.POSITIVE_INFINITY;\n let bestBatch = batchSize;\n\n for (let attempt = 0; attempt < 3; attempt++) {\n const samples: number[] = [];\n const sampleCount = Math.min(8, maxCycles);\n for (let s = 0; s < sampleCount; s++) {\n const duration = await collectSample({\n batchSize,\n run,\n runRaw,\n runIsAsync,\n pre,\n preIsAsync,\n post,\n postIsAsync,\n context,\n data,\n nextNonce,\n });\n samples.push(Number(duration));\n }\n const mean = samples.reduce((acc, v) => acc + v, 0) / samples.length;\n const variance = samples.reduce((acc, v) => acc + (v - mean) * (v - mean), 0) / Math.max(1, samples.length - 1);\n const stddev = Math.sqrt(variance);\n const cv = mean === 0 ? Number.POSITIVE_INFINITY : stddev / mean;\n\n if (cv < bestCv) {\n bestCv = cv;\n bestBatch = batchSize;\n }\n\n if (cv <= relThreshold || batchSize >= MAX_BATCH) {\n break;\n }\n batchSize = Math.min(MAX_BATCH, batchSize * 2);\n }\n\n const tunedRel = bestCv < relThreshold ? Math.max(bestCv * 1.5, relThreshold * 0.5) : relThreshold;\n const tunedMin = Math.min(maxCycles, Math.max(minCycles, Math.ceil(minCycles * Math.max(1, bestCv / (relThreshold || 1e-6)))));\n\n return { batchSize: bestBatch, relThreshold: tunedRel, minCycles: tunedMin };\n};\n\nconst createGCTracker = () => {\n if (process.env.OVERTAKE_GC_OBSERVER !== '1') {\n return null;\n }\n if (typeof PerformanceObserver === 'undefined') {\n return null;\n }\n\n const events: GCEvent[] = [];\n const observer = new PerformanceObserver((list) => {\n for (const entry of list.getEntries()) {\n events.push({ start: entry.startTime, end: entry.startTime + entry.duration });\n }\n });\n\n try {\n observer.observe({ entryTypes: ['gc'] });\n } catch {\n return null;\n }\n\n const overlaps = (start: number, end: number) => {\n let noisy = false;\n for (let i = events.length - 1; i >= 0; i--) {\n const event = events[i];\n if (event.end < start - 5_000) {\n events.splice(i, 1);\n continue;\n }\n if (event.start <= end && event.end >= start) {\n noisy = true;\n }\n }\n return noisy;\n };\n\n const dispose = () => observer.disconnect();\n\n return { overlaps, dispose };\n};\n\nconst pushWindow = (arr: number[], value: number, cap: number) => {\n if (arr.length === cap) {\n arr.shift();\n }\n arr.push(value);\n};\n\nconst medianAndIqr = (arr: number[]) => {\n if (arr.length === 0) return { median: 0, iqr: 0 };\n for (let i = 0; i < arr.length; i++) {\n OUTLIER_SCRATCH[i] = arr[i];\n }\n const view = OUTLIER_SCRATCH.subarray(0, arr.length);\n view.sort();\n const mid = Math.floor(view.length / 2);\n const median = view.length % 2 === 0 ? (view[mid - 1] + view[mid]) / 2 : view[mid];\n const q1Idx = Math.floor(view.length * 0.25);\n const q3Idx = Math.floor(view.length * 0.75);\n const q1 = view[q1Idx];\n const q3 = view[q3Idx];\n return { median, iqr: q3 - q1 };\n};\n\nconst windowCv = (arr: number[]) => {\n if (arr.length < 2) return Number.POSITIVE_INFINITY;\n const mean = arr.reduce((a, v) => a + v, 0) / arr.length;\n const variance = arr.reduce((a, v) => a + (v - mean) * (v - mean), 0) / (arr.length - 1);\n const stddev = Math.sqrt(variance);\n return mean === 0 ? Number.POSITIVE_INFINITY : stddev / mean;\n};\n\nexport const benchmark = async <TContext, TInput>({\n setup,\n teardown,\n pre,\n run: runRaw,\n post,\n data,\n\n warmupCycles,\n minCycles,\n absThreshold,\n relThreshold,\n gcObserver = false,\n\n durationsSAB,\n controlSAB,\n}: Required<Options<TContext, TInput>>) => {\n const durations = new BigUint64Array(durationsSAB);\n const control = new Int32Array(controlSAB);\n\n control[Control.INDEX] = 0;\n control[Control.PROGRESS] = 0;\n control[Control.COMPLETE] = 255;\n\n const context = (await setup?.()) as TContext;\n const input = data as TInput;\n const maxCycles = durations.length;\n const gcWatcher = gcObserver ? new GCWatcher() : null;\n const gcTracker = gcObserver ? createGCTracker() : null;\n\n try {\n // classify sync/async and capture initial duration\n let preIsAsync = false;\n if (pre) {\n const preResult = pre(context, input);\n preIsAsync = isThenable(preResult);\n if (preIsAsync) {\n await preResult;\n }\n }\n\n const probeStart = hr();\n const probeResult = runRaw(context, input);\n const runIsAsync = isThenable(probeResult);\n if (runIsAsync) {\n const resolved = await probeResult;\n consume(resolved);\n } else {\n consume(probeResult);\n }\n const durationProbeRaw = hr() - probeStart;\n\n let postIsAsync = false;\n if (post) {\n const postResult = post(context, input);\n postIsAsync = isThenable(postResult);\n if (postIsAsync) {\n await postResult;\n }\n }\n\n const timerOverhead = runIsAsync ? 0n : measureTimerOverhead();\n let durationProbe = runIsAsync ? durationProbeRaw : durationProbeRaw > timerOverhead ? durationProbeRaw - timerOverhead : 0n;\n\n const shouldPerturbInput = process.env.OVERTAKE_PERTURB_INPUT === '1';\n let nonce = 0;\n const nextNonce = shouldPerturbInput\n ? () => {\n nonce = (nonce + 1) | 0;\n return nonce;\n }\n : null;\n\n if (!runIsAsync && !pre && !post) {\n const batchProbeSize = 10_000;\n const batchProbeStart = hr();\n if (nextNonce) {\n for (let i = 0; i < batchProbeSize; i++) {\n consume((runRaw as Function)(context, input, nextNonce()));\n }\n } else {\n for (let i = 0; i < batchProbeSize; i++) {\n consume(runRaw(context, input));\n }\n }\n durationProbe = (hr() - batchProbeStart) / BigInt(batchProbeSize);\n }\n\n const runTimedSync = runIsAsync ? null : runSync(runRaw, timerOverhead);\n const runTimedAsync = runIsAsync ? runAsync(runRaw) : null;\n const run = runIsAsync ? runTimedAsync! : runTimedSync!;\n\n const runOnceSync: RunTimedSync<TContext, TInput> | null = runIsAsync ? null : nextNonce ? (ctx, dataValue) => runTimedSync!(ctx, dataValue, nextNonce()) : runTimedSync!;\n const runOnceAsync: RunTimedAsync<TContext, TInput> | null = runIsAsync ? (nextNonce ? (ctx, dataValue) => runTimedAsync!(ctx, dataValue, nextNonce()) : runTimedAsync!) : null;\n\n const preSync = preIsAsync ? null : pre;\n const preAsync = preIsAsync ? pre : null;\n const postSync = postIsAsync ? null : post;\n const postAsync = postIsAsync ? post : null;\n\n // choose batch size to amortize timer overhead\n const durationPerRun = durationProbe === 0n ? 1n : durationProbe;\n const suggestedBatch = Number(TARGET_SAMPLE_NS / durationPerRun);\n const minBatchForFastOps = durationProbe < 100n ? 100_000 : 1;\n const initialBatchSize = Math.min(MAX_BATCH, Math.max(minBatchForFastOps, suggestedBatch));\n\n // auto-tune based on warmup samples\n const tuned = await tuneParameters({\n initialBatch: initialBatchSize,\n run,\n runRaw,\n runIsAsync,\n pre,\n preIsAsync,\n post,\n postIsAsync,\n context,\n data: input,\n minCycles,\n relThreshold,\n maxCycles,\n nextNonce,\n });\n let batchSize = tuned.batchSize;\n minCycles = tuned.minCycles;\n relThreshold = tuned.relThreshold;\n\n // warmup: run until requested cycles, adapt if unstable\n const warmupStart = performance.now();\n let warmupRemaining = warmupCycles;\n const warmupWindow: number[] = [];\n const warmupCap = Math.max(warmupCycles, Math.min(maxCycles, warmupCycles * 4 || 1000));\n const canBatchTime = !runIsAsync && !preSync && !preAsync && !postSync && !postAsync;\n\n const runWarmup = async () => {\n if (canBatchTime) {\n const batchStart = hr();\n if (nextNonce) {\n for (let b = 0; b < batchSize; b++) {\n consume((runRaw as Function)(context, input, nextNonce()));\n }\n } else {\n for (let b = 0; b < batchSize; b++) {\n consume(runRaw(context, input));\n }\n }\n return ((hr() - batchStart) * DURATION_SCALE) / BigInt(batchSize);\n }\n\n if (preSync) {\n preSync(context, input);\n } else if (preAsync) {\n await preAsync(context, input);\n }\n\n const duration = runIsAsync ? await runOnceAsync!(context, input) : runOnceSync!(context, input);\n\n if (postSync) {\n postSync(context, input);\n } else if (postAsync) {\n await postAsync(context, input);\n }\n\n return duration;\n };\n\n while (performance.now() - warmupStart < 1_000 && warmupRemaining > 0) {\n const duration = await runWarmup();\n pushWindow(warmupWindow, Number(duration), warmupCap);\n warmupRemaining--;\n }\n let warmupDone = 0;\n while (warmupDone < warmupRemaining) {\n const duration = await runWarmup();\n pushWindow(warmupWindow, Number(duration), warmupCap);\n warmupDone++;\n if (global.gc && warmupDone % GC_STRIDE === 0) {\n global.gc();\n }\n }\n while (warmupWindow.length >= 8 && warmupWindow.length < warmupCap) {\n const cv = windowCv(warmupWindow);\n if (cv <= relThreshold * 2) {\n break;\n }\n const duration = await runWarmup();\n pushWindow(warmupWindow, Number(duration), warmupCap);\n }\n\n let i = 0;\n let mean = 0n;\n let m2 = 0n;\n const outlierWindow: number[] = [];\n let skipped = 0;\n const maxSkipped = maxCycles * 10;\n let disableFiltering = false;\n\n while (true) {\n if (i >= maxCycles) break;\n if (!disableFiltering && skipped >= maxSkipped) {\n console.error(`Warning: ${skipped} samples skipped due to noise/outlier detection. ` + `Disabling filtering for remaining samples. Results may have higher variance.`);\n disableFiltering = true;\n }\n\n if (global.gc && i > 0 && i % GC_STRIDE === 0) {\n global.gc();\n }\n\n const gcMarker = gcWatcher?.start();\n const sampleStart = performance.now();\n let sampleDuration = 0n;\n\n if (canBatchTime) {\n const batchStart = hr();\n if (nextNonce) {\n for (let b = 0; b < batchSize; b++) {\n consume((runRaw as Function)(context, input, nextNonce()));\n }\n } else {\n for (let b = 0; b < batchSize; b++) {\n consume(runRaw(context, input));\n }\n }\n const batchDuration = hr() - batchStart;\n sampleDuration = (batchDuration * DURATION_SCALE) / BigInt(batchSize);\n } else {\n for (let b = 0; b < batchSize; b++) {\n if (preSync) {\n preSync(context, input);\n } else if (preAsync) {\n await preAsync(context, input);\n }\n\n const duration = runIsAsync ? await runOnceAsync!(context, input) : runOnceSync!(context, input);\n sampleDuration += duration;\n\n if (postSync) {\n postSync(context, input);\n } else if (postAsync) {\n await postAsync(context, input);\n }\n }\n sampleDuration = (sampleDuration * DURATION_SCALE) / BigInt(batchSize);\n }\n\n const sampleEnd = performance.now();\n if (!disableFiltering) {\n const gcNoise = (gcMarker ? gcWatcher!.seen(gcMarker) : false) || (gcTracker?.overlaps(sampleStart, sampleEnd) ?? false);\n if (gcNoise) {\n skipped++;\n continue;\n }\n }\n\n const durationNumber = Number(sampleDuration);\n pushWindow(outlierWindow, durationNumber, OUTLIER_WINDOW);\n if (!disableFiltering) {\n const { median, iqr } = medianAndIqr(outlierWindow);\n const maxAllowed = median + OUTLIER_IQR_MULTIPLIER * iqr || Number.POSITIVE_INFINITY;\n if (outlierWindow.length >= 8 && durationNumber > maxAllowed && durationNumber - median > OUTLIER_ABS_THRESHOLD_NS) {\n skipped++;\n continue;\n }\n\n const meanNumber = Number(mean);\n if (i >= 8 && meanNumber > 0 && durationNumber > OUTLIER_MULTIPLIER * meanNumber && durationNumber - meanNumber > OUTLIER_ABS_THRESHOLD_NS) {\n skipped++;\n continue;\n }\n }\n\n durations[i++] = sampleDuration;\n const delta = sampleDuration - mean;\n mean += delta / BigInt(i);\n m2 += delta * (sampleDuration - mean);\n\n const progress = Math.max(i / maxCycles) * COMPLETE_VALUE;\n if (i % PROGRESS_STRIDE === 0) {\n control[Control.PROGRESS] = progress;\n }\n\n if (i >= minCycles) {\n const variance = Number(m2) / (i - 1);\n const stddev = Math.sqrt(variance);\n if (stddev <= Number(absThreshold)) {\n break;\n }\n\n const meanNum = Number(mean);\n const cov = stddev / (meanNum || 1);\n if (cov <= relThreshold) {\n break;\n }\n }\n }\n\n control[Control.INDEX] = i;\n control[Control.COMPLETE] = 0;\n } catch (e) {\n console.error(e && typeof e === 'object' && 'stack' in e ? e.stack : e);\n control[Control.COMPLETE] = 1;\n } finally {\n gcTracker?.dispose?.();\n try {\n await teardown?.(context);\n } catch (e) {\n control[Control.COMPLETE] = 2;\n console.error(e && typeof e === 'object' && 'stack' in e ? e.stack : e);\n }\n }\n\n return control[Control.COMPLETE];\n};\n"],"names":["performance","PerformanceObserver","Control","DURATION_SCALE","GCWatcher","COMPLETE_VALUE","hr","process","hrtime","bigint","bind","sink","Int32Array","SharedArrayBuffer","BYTES_PER_ELEMENT","consume","value","payload","Number","isFinite","Math","trunc","length","Atomics","xor","runSync","run","overhead","args","start","result","duration","runAsync","isThenable","then","TARGET_SAMPLE_NS","MAX_BATCH","PROGRESS_STRIDE","GC_STRIDE","OUTLIER_MULTIPLIER","OUTLIER_IQR_MULTIPLIER","OUTLIER_WINDOW","OUTLIER_ABS_THRESHOLD_NS","BASELINE_SAMPLES","OUTLIER_SCRATCH","Float64Array","measureTimerOverhead","total","i","BigInt","collectSample","batchSize","runRaw","runIsAsync","pre","preIsAsync","post","postIsAsync","context","data","nextNonce","canBatchTime","batchStart","b","sampleDuration","runAsyncFn","runSyncFn","tuneParameters","initialBatch","minCycles","relThreshold","maxCycles","bestCv","POSITIVE_INFINITY","bestBatch","attempt","samples","sampleCount","min","s","push","mean","reduce","acc","v","variance","max","stddev","sqrt","cv","tunedRel","tunedMin","ceil","createGCTracker","env","OVERTAKE_GC_OBSERVER","events","observer","list","entry","getEntries","startTime","end","observe","entryTypes","overlaps","noisy","event","splice","dispose","disconnect","pushWindow","arr","cap","shift","medianAndIqr","median","iqr","view","subarray","sort","mid","floor","q1Idx","q3Idx","q1","q3","windowCv","a","benchmark","setup","teardown","warmupCycles","absThreshold","gcObserver","durationsSAB","controlSAB","durations","BigUint64Array","control","INDEX","PROGRESS","COMPLETE","input","gcWatcher","gcTracker","preResult","probeStart","probeResult","resolved","durationProbeRaw","postResult","timerOverhead","durationProbe","shouldPerturbInput","OVERTAKE_PERTURB_INPUT","nonce","batchProbeSize","batchProbeStart","runTimedSync","runTimedAsync","runOnceSync","ctx","dataValue","runOnceAsync","preSync","preAsync","postSync","postAsync","durationPerRun","suggestedBatch","minBatchForFastOps","initialBatchSize","tuned","warmupStart","now","warmupRemaining","warmupWindow","warmupCap","runWarmup","warmupDone","global","gc","m2","outlierWindow","skipped","maxSkipped","disableFiltering","console","error","gcMarker","sampleStart","batchDuration","sampleEnd","gcNoise","seen","durationNumber","maxAllowed","meanNumber","delta","progress","meanNum","cov","e","stack"],"mappings":"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"}
package/build/types.cjs CHANGED
@@ -18,6 +18,9 @@ _export(exports, {
18
18
  get DEFAULT_CYCLES () {
19
19
  return DEFAULT_CYCLES;
20
20
  },
21
+ get DURATION_SCALE () {
22
+ return DURATION_SCALE;
23
+ },
21
24
  get REPORT_TYPES () {
22
25
  return REPORT_TYPES;
23
26
  },
@@ -44,5 +47,6 @@ var Control = /*#__PURE__*/ function(Control) {
44
47
  const CONTROL_SLOTS = Object.values(Control).length / 2;
45
48
  const DEFAULT_CYCLES = 1_000;
46
49
  const Z95 = 1.96;
50
+ const DURATION_SCALE = 1000n;
47
51
 
48
52
  //# sourceMappingURL=types.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/types.ts"],"sourcesContent":["export type MaybePromise<T> = Promise<T> | PromiseLike<T> | T;\n\nexport interface SetupFn<TContext> {\n (): MaybePromise<TContext>;\n}\n\nexport interface TeardownFn<TContext> {\n (ctx: TContext): MaybePromise<void>;\n}\n\nexport interface StepFn<TContext, TInput> {\n (ctx: TContext, input: TInput): MaybePromise<unknown>;\n}\n\nexport interface FeedFn<TInput> {\n (): MaybePromise<TInput>;\n}\n\ntype _Sequence<To extends number, R extends unknown[]> = R['length'] extends To ? R[number] : _Sequence<To, [R['length'], ...R]>;\nexport type Sequence<To extends number> = number extends To ? number : _Sequence<To, []>;\nexport type Between<From extends number, To extends number> = Exclude<Sequence<To>, Sequence<From>>;\n\nexport type ReportType = 'ops' | 'min' | 'max' | 'mean' | 'median' | 'mode' | `p${Between<1, 100>}`;\nexport type ReportTypeList = readonly ReportType[];\nexport const REPORT_TYPES: ReportTypeList = Array.from({ length: 99 }, (_, idx) => `p${idx + 1}` as ReportType).concat(['ops', 'mean', 'min', 'max', 'median', 'mode']);\n\nexport interface ReportOptions<R extends ReportTypeList> {\n reportTypes: R;\n}\n\nexport interface BenchmarkOptions {\n warmupCycles?: number;\n minCycles?: number;\n absThreshold?: number; // ns\n relThreshold?: number; // %\n gcObserver?: boolean;\n}\n\nexport interface RunOptions<TContext, TInput> {\n setup?: SetupFn<TContext>;\n teardown?: TeardownFn<TContext>;\n pre?: StepFn<TContext, TInput>;\n run: StepFn<TContext, TInput>;\n post?: StepFn<TContext, TInput>;\n data?: TInput;\n}\n\nexport interface WorkerOptions extends Required<BenchmarkOptions> {\n benchmarkUrl?: string;\n setupCode?: string;\n teardownCode?: string;\n preCode?: string;\n runCode: string;\n postCode?: string;\n data?: unknown;\n\n durationsSAB: SharedArrayBuffer;\n controlSAB: SharedArrayBuffer;\n}\n\nexport interface Options<TContext, TInput> extends RunOptions<TContext, TInput>, BenchmarkOptions {\n durationsSAB: SharedArrayBuffer;\n controlSAB: SharedArrayBuffer;\n}\n\nexport enum Control {\n INDEX,\n PROGRESS,\n COMPLETE,\n}\n\nexport const CONTROL_SLOTS = Object.values(Control).length / 2;\nexport const DEFAULT_CYCLES = 1_000;\nexport const Z95 = 1.96;\n"],"names":["CONTROL_SLOTS","Control","DEFAULT_CYCLES","REPORT_TYPES","Z95","Array","from","length","_","idx","concat","Object","values"],"mappings":";;;;;;;;;;;QAuEaA;eAAAA;;QANDC;eAAAA;;QAOCC;eAAAA;;QAhDAC;eAAAA;;QAiDAC;eAAAA;;;AAjDN,MAAMD,eAA+BE,MAAMC,IAAI,CAAC;IAAEC,QAAQ;AAAG,GAAG,CAACC,GAAGC,MAAQ,CAAC,CAAC,EAAEA,MAAM,GAAG,EAAgBC,MAAM,CAAC;IAAC;IAAO;IAAQ;IAAO;IAAO;IAAU;CAAO;AAyC/J,IAAA,AAAKT,iCAAAA;;;;WAAAA;;AAML,MAAMD,gBAAgBW,OAAOC,MAAM,CAACX,SAASM,MAAM,GAAG;AACtD,MAAML,iBAAiB;AACvB,MAAME,MAAM"}
1
+ {"version":3,"sources":["../src/types.ts"],"sourcesContent":["export type MaybePromise<T> = Promise<T> | PromiseLike<T> | T;\n\nexport interface SetupFn<TContext> {\n (): MaybePromise<TContext>;\n}\n\nexport interface TeardownFn<TContext> {\n (ctx: TContext): MaybePromise<void>;\n}\n\nexport interface StepFn<TContext, TInput> {\n (ctx: TContext, input: TInput): MaybePromise<unknown>;\n}\n\nexport interface FeedFn<TInput> {\n (): MaybePromise<TInput>;\n}\n\ntype _Sequence<To extends number, R extends unknown[]> = R['length'] extends To ? R[number] : _Sequence<To, [R['length'], ...R]>;\nexport type Sequence<To extends number> = number extends To ? number : _Sequence<To, []>;\nexport type Between<From extends number, To extends number> = Exclude<Sequence<To>, Sequence<From>>;\n\nexport type ReportType = 'ops' | 'min' | 'max' | 'mean' | 'median' | 'mode' | `p${Between<1, 100>}`;\nexport type ReportTypeList = readonly ReportType[];\nexport const REPORT_TYPES: ReportTypeList = Array.from({ length: 99 }, (_, idx) => `p${idx + 1}` as ReportType).concat(['ops', 'mean', 'min', 'max', 'median', 'mode']);\n\nexport interface ReportOptions<R extends ReportTypeList> {\n reportTypes: R;\n}\n\nexport interface BenchmarkOptions {\n warmupCycles?: number;\n minCycles?: number;\n absThreshold?: number; // ns\n relThreshold?: number; // %\n gcObserver?: boolean;\n}\n\nexport interface RunOptions<TContext, TInput> {\n setup?: SetupFn<TContext>;\n teardown?: TeardownFn<TContext>;\n pre?: StepFn<TContext, TInput>;\n run: StepFn<TContext, TInput>;\n post?: StepFn<TContext, TInput>;\n data?: TInput;\n}\n\nexport interface WorkerOptions extends Required<BenchmarkOptions> {\n benchmarkUrl?: string;\n setupCode?: string;\n teardownCode?: string;\n preCode?: string;\n runCode: string;\n postCode?: string;\n data?: unknown;\n\n durationsSAB: SharedArrayBuffer;\n controlSAB: SharedArrayBuffer;\n}\n\nexport interface Options<TContext, TInput> extends RunOptions<TContext, TInput>, BenchmarkOptions {\n durationsSAB: SharedArrayBuffer;\n controlSAB: SharedArrayBuffer;\n}\n\nexport enum Control {\n INDEX,\n PROGRESS,\n COMPLETE,\n}\n\nexport const CONTROL_SLOTS = Object.values(Control).length / 2;\nexport const DEFAULT_CYCLES = 1_000;\nexport const Z95 = 1.96;\nexport const DURATION_SCALE = 1000n;\n"],"names":["CONTROL_SLOTS","Control","DEFAULT_CYCLES","DURATION_SCALE","REPORT_TYPES","Z95","Array","from","length","_","idx","concat","Object","values"],"mappings":";;;;;;;;;;;QAuEaA;eAAAA;;QANDC;eAAAA;;QAOCC;eAAAA;;QAEAC;eAAAA;;QAlDAC;eAAAA;;QAiDAC;eAAAA;;;AAjDN,MAAMD,eAA+BE,MAAMC,IAAI,CAAC;IAAEC,QAAQ;AAAG,GAAG,CAACC,GAAGC,MAAQ,CAAC,CAAC,EAAEA,MAAM,GAAG,EAAgBC,MAAM,CAAC;IAAC;IAAO;IAAQ;IAAO;IAAO;IAAU;CAAO;AAyC/J,IAAA,AAAKV,iCAAAA;;;;WAAAA;;AAML,MAAMD,gBAAgBY,OAAOC,MAAM,CAACZ,SAASO,MAAM,GAAG;AACtD,MAAMN,iBAAiB;AACvB,MAAMG,MAAM;AACZ,MAAMF,iBAAiB,KAAK"}
package/build/types.d.ts CHANGED
@@ -58,4 +58,5 @@ export declare enum Control {
58
58
  export declare const CONTROL_SLOTS: number;
59
59
  export declare const DEFAULT_CYCLES = 1000;
60
60
  export declare const Z95 = 1.96;
61
+ export declare const DURATION_SCALE = 1000n;
61
62
  export {};
package/build/types.js CHANGED
@@ -17,5 +17,6 @@ export var Control = /*#__PURE__*/ function(Control) {
17
17
  export const CONTROL_SLOTS = Object.values(Control).length / 2;
18
18
  export const DEFAULT_CYCLES = 1_000;
19
19
  export const Z95 = 1.96;
20
+ export const DURATION_SCALE = 1000n;
20
21
 
21
22
  //# sourceMappingURL=types.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/types.ts"],"sourcesContent":["export type MaybePromise<T> = Promise<T> | PromiseLike<T> | T;\n\nexport interface SetupFn<TContext> {\n (): MaybePromise<TContext>;\n}\n\nexport interface TeardownFn<TContext> {\n (ctx: TContext): MaybePromise<void>;\n}\n\nexport interface StepFn<TContext, TInput> {\n (ctx: TContext, input: TInput): MaybePromise<unknown>;\n}\n\nexport interface FeedFn<TInput> {\n (): MaybePromise<TInput>;\n}\n\ntype _Sequence<To extends number, R extends unknown[]> = R['length'] extends To ? R[number] : _Sequence<To, [R['length'], ...R]>;\nexport type Sequence<To extends number> = number extends To ? number : _Sequence<To, []>;\nexport type Between<From extends number, To extends number> = Exclude<Sequence<To>, Sequence<From>>;\n\nexport type ReportType = 'ops' | 'min' | 'max' | 'mean' | 'median' | 'mode' | `p${Between<1, 100>}`;\nexport type ReportTypeList = readonly ReportType[];\nexport const REPORT_TYPES: ReportTypeList = Array.from({ length: 99 }, (_, idx) => `p${idx + 1}` as ReportType).concat(['ops', 'mean', 'min', 'max', 'median', 'mode']);\n\nexport interface ReportOptions<R extends ReportTypeList> {\n reportTypes: R;\n}\n\nexport interface BenchmarkOptions {\n warmupCycles?: number;\n minCycles?: number;\n absThreshold?: number; // ns\n relThreshold?: number; // %\n gcObserver?: boolean;\n}\n\nexport interface RunOptions<TContext, TInput> {\n setup?: SetupFn<TContext>;\n teardown?: TeardownFn<TContext>;\n pre?: StepFn<TContext, TInput>;\n run: StepFn<TContext, TInput>;\n post?: StepFn<TContext, TInput>;\n data?: TInput;\n}\n\nexport interface WorkerOptions extends Required<BenchmarkOptions> {\n benchmarkUrl?: string;\n setupCode?: string;\n teardownCode?: string;\n preCode?: string;\n runCode: string;\n postCode?: string;\n data?: unknown;\n\n durationsSAB: SharedArrayBuffer;\n controlSAB: SharedArrayBuffer;\n}\n\nexport interface Options<TContext, TInput> extends RunOptions<TContext, TInput>, BenchmarkOptions {\n durationsSAB: SharedArrayBuffer;\n controlSAB: SharedArrayBuffer;\n}\n\nexport enum Control {\n INDEX,\n PROGRESS,\n COMPLETE,\n}\n\nexport const CONTROL_SLOTS = Object.values(Control).length / 2;\nexport const DEFAULT_CYCLES = 1_000;\nexport const Z95 = 1.96;\n"],"names":["REPORT_TYPES","Array","from","length","_","idx","concat","Control","CONTROL_SLOTS","Object","values","DEFAULT_CYCLES","Z95"],"mappings":"AAwBA,OAAO,MAAMA,eAA+BC,MAAMC,IAAI,CAAC;IAAEC,QAAQ;AAAG,GAAG,CAACC,GAAGC,MAAQ,CAAC,CAAC,EAAEA,MAAM,GAAG,EAAgBC,MAAM,CAAC;IAAC;IAAO;IAAQ;IAAO;IAAO;IAAU;CAAO,EAAE;AAyCxK,OAAO,IAAA,AAAKC,iCAAAA;;;;WAAAA;MAIX;AAED,OAAO,MAAMC,gBAAgBC,OAAOC,MAAM,CAACH,SAASJ,MAAM,GAAG,EAAE;AAC/D,OAAO,MAAMQ,iBAAiB,MAAM;AACpC,OAAO,MAAMC,MAAM,KAAK"}
1
+ {"version":3,"sources":["../src/types.ts"],"sourcesContent":["export type MaybePromise<T> = Promise<T> | PromiseLike<T> | T;\n\nexport interface SetupFn<TContext> {\n (): MaybePromise<TContext>;\n}\n\nexport interface TeardownFn<TContext> {\n (ctx: TContext): MaybePromise<void>;\n}\n\nexport interface StepFn<TContext, TInput> {\n (ctx: TContext, input: TInput): MaybePromise<unknown>;\n}\n\nexport interface FeedFn<TInput> {\n (): MaybePromise<TInput>;\n}\n\ntype _Sequence<To extends number, R extends unknown[]> = R['length'] extends To ? R[number] : _Sequence<To, [R['length'], ...R]>;\nexport type Sequence<To extends number> = number extends To ? number : _Sequence<To, []>;\nexport type Between<From extends number, To extends number> = Exclude<Sequence<To>, Sequence<From>>;\n\nexport type ReportType = 'ops' | 'min' | 'max' | 'mean' | 'median' | 'mode' | `p${Between<1, 100>}`;\nexport type ReportTypeList = readonly ReportType[];\nexport const REPORT_TYPES: ReportTypeList = Array.from({ length: 99 }, (_, idx) => `p${idx + 1}` as ReportType).concat(['ops', 'mean', 'min', 'max', 'median', 'mode']);\n\nexport interface ReportOptions<R extends ReportTypeList> {\n reportTypes: R;\n}\n\nexport interface BenchmarkOptions {\n warmupCycles?: number;\n minCycles?: number;\n absThreshold?: number; // ns\n relThreshold?: number; // %\n gcObserver?: boolean;\n}\n\nexport interface RunOptions<TContext, TInput> {\n setup?: SetupFn<TContext>;\n teardown?: TeardownFn<TContext>;\n pre?: StepFn<TContext, TInput>;\n run: StepFn<TContext, TInput>;\n post?: StepFn<TContext, TInput>;\n data?: TInput;\n}\n\nexport interface WorkerOptions extends Required<BenchmarkOptions> {\n benchmarkUrl?: string;\n setupCode?: string;\n teardownCode?: string;\n preCode?: string;\n runCode: string;\n postCode?: string;\n data?: unknown;\n\n durationsSAB: SharedArrayBuffer;\n controlSAB: SharedArrayBuffer;\n}\n\nexport interface Options<TContext, TInput> extends RunOptions<TContext, TInput>, BenchmarkOptions {\n durationsSAB: SharedArrayBuffer;\n controlSAB: SharedArrayBuffer;\n}\n\nexport enum Control {\n INDEX,\n PROGRESS,\n COMPLETE,\n}\n\nexport const CONTROL_SLOTS = Object.values(Control).length / 2;\nexport const DEFAULT_CYCLES = 1_000;\nexport const Z95 = 1.96;\nexport const DURATION_SCALE = 1000n;\n"],"names":["REPORT_TYPES","Array","from","length","_","idx","concat","Control","CONTROL_SLOTS","Object","values","DEFAULT_CYCLES","Z95","DURATION_SCALE"],"mappings":"AAwBA,OAAO,MAAMA,eAA+BC,MAAMC,IAAI,CAAC;IAAEC,QAAQ;AAAG,GAAG,CAACC,GAAGC,MAAQ,CAAC,CAAC,EAAEA,MAAM,GAAG,EAAgBC,MAAM,CAAC;IAAC;IAAO;IAAQ;IAAO;IAAO;IAAU;CAAO,EAAE;AAyCxK,OAAO,IAAA,AAAKC,iCAAAA;;;;WAAAA;MAIX;AAED,OAAO,MAAMC,gBAAgBC,OAAOC,MAAM,CAACH,SAASJ,MAAM,GAAG,EAAE;AAC/D,OAAO,MAAMQ,iBAAiB,MAAM;AACpC,OAAO,MAAMC,MAAM,KAAK;AACxB,OAAO,MAAMC,iBAAiB,KAAK,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "overtake",
3
- "version": "1.1.3",
3
+ "version": "1.1.4",
4
4
  "description": "NodeJS performance benchmark",
5
5
  "type": "module",
6
6
  "types": "build/index.d.ts",
package/src/reporter.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { div, max, divs } from './utils.js';
2
- import { ReportType } from './types.js';
2
+ import { ReportType, DURATION_SCALE } from './types.js';
3
3
 
4
4
  const units = [
5
5
  { unit: 'ns', factor: 1 },
@@ -56,15 +56,15 @@ export const createReport = (durations: BigUint64Array, type: ReportType): Repor
56
56
  }
57
57
  switch (type) {
58
58
  case 'min': {
59
- return new Report(type, durations[0]);
59
+ return new Report(type, durations[0], 0, DURATION_SCALE);
60
60
  }
61
61
  case 'max': {
62
- return new Report(type, durations[n - 1]);
62
+ return new Report(type, durations[n - 1], 0, DURATION_SCALE);
63
63
  }
64
64
  case 'median': {
65
65
  const mid = Math.floor(n / 2);
66
66
  const med = n % 2 === 0 ? (durations[mid - 1] + durations[mid]) / 2n : durations[mid];
67
- return new Report(type, med);
67
+ return new Report(type, med, 0, DURATION_SCALE);
68
68
  }
69
69
 
70
70
  case 'mode': {
@@ -87,7 +87,7 @@ export const createReport = (durations: BigUint64Array, type: ReportType): Repor
87
87
  if (lastIdx < n - 1) upper = durations[lastIdx + 1];
88
88
  const gap = max(modeVal - lower, upper - modeVal);
89
89
  const uncertainty = modeVal > 0 ? Number(((gap / 2n) * 100n) / modeVal) : 0;
90
- return new Report(type, modeVal, uncertainty);
90
+ return new Report(type, modeVal, uncertainty, DURATION_SCALE);
91
91
  }
92
92
 
93
93
  case 'ops': {
@@ -95,18 +95,18 @@ export const createReport = (durations: BigUint64Array, type: ReportType): Repor
95
95
  for (const duration of durations) {
96
96
  sum += duration;
97
97
  }
98
- const avgNs = sum / BigInt(n);
99
- const nsPerSec = 1_000_000_000n;
100
- const raw = Number(nsPerSec) / Number(avgNs);
98
+ const avgScaled = sum / BigInt(n);
99
+ const nsPerSecScaled = 1_000_000_000n * DURATION_SCALE;
100
+ const raw = Number(nsPerSecScaled) / Number(avgScaled);
101
101
  const extra = raw < 1 ? Math.ceil(-Math.log10(raw)) : 0;
102
102
 
103
103
  const exp = raw > 100 ? 0 : 2 + extra;
104
104
 
105
105
  const scale = 10n ** BigInt(exp);
106
106
 
107
- const value = avgNs > 0n ? (nsPerSec * scale) / avgNs : 0n;
107
+ const value = avgScaled > 0n ? (nsPerSecScaled * scale) / avgScaled : 0n;
108
108
  const deviation = durations[n - 1] - durations[0];
109
- const uncertainty = avgNs > 0 ? Number(div(deviation * scale, 2n * avgNs)) : 0;
109
+ const uncertainty = avgScaled > 0 ? Number(div(deviation * scale, 2n * avgScaled)) : 0;
110
110
  return new Report(type, value, uncertainty, scale);
111
111
  }
112
112
  case 'mean': {
@@ -115,16 +115,16 @@ export const createReport = (durations: BigUint64Array, type: ReportType): Repor
115
115
  sum += duration;
116
116
  }
117
117
  const value = divs(sum, BigInt(n), 1n);
118
- return new Report(type, value);
118
+ return new Report(type, value, 0, DURATION_SCALE);
119
119
  }
120
120
 
121
121
  default: {
122
122
  const p = Number(type.slice(1));
123
123
  if (p === 0) {
124
- return new Report(type, durations[0]);
124
+ return new Report(type, durations[0], 0, DURATION_SCALE);
125
125
  }
126
126
  if (p === 100) {
127
- return new Report(type, durations[n - 1]);
127
+ return new Report(type, durations[n - 1], 0, DURATION_SCALE);
128
128
  }
129
129
  const idx = Math.ceil((p / 100) * n) - 1;
130
130
  const value = durations[Math.min(Math.max(idx, 0), n - 1)];
@@ -133,7 +133,7 @@ export const createReport = (durations: BigUint64Array, type: ReportType): Repor
133
133
  const gap = max(value - prev, next - value);
134
134
  const uncertainty = value > 0 ? Number(div(divs(gap, 2n, 100_00n), value)) / 100 : 0;
135
135
 
136
- return new Report(type, value, uncertainty);
136
+ return new Report(type, value, uncertainty, DURATION_SCALE);
137
137
  }
138
138
  }
139
139
  };
package/src/runner.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { performance, PerformanceObserver } from 'node:perf_hooks';
2
- import { Options, Control } from './types.js';
2
+ import { Options, Control, DURATION_SCALE } from './types.js';
3
3
  import { GCWatcher } from './gc-watcher.js';
4
4
  import { StepFn } from './types.js';
5
5
 
@@ -120,7 +120,7 @@ const collectSample = async <TContext, TInput>({
120
120
  consume(runRaw(context, data));
121
121
  }
122
122
  }
123
- return (hr() - batchStart) / BigInt(batchSize);
123
+ return ((hr() - batchStart) * DURATION_SCALE) / BigInt(batchSize);
124
124
  }
125
125
 
126
126
  let sampleDuration = 0n;
@@ -151,7 +151,7 @@ const collectSample = async <TContext, TInput>({
151
151
  }
152
152
  }
153
153
  }
154
- return sampleDuration / BigInt(batchSize);
154
+ return (sampleDuration * DURATION_SCALE) / BigInt(batchSize);
155
155
  };
156
156
 
157
157
  const tuneParameters = async <TContext, TInput>({
@@ -448,7 +448,7 @@ export const benchmark = async <TContext, TInput>({
448
448
  consume(runRaw(context, input));
449
449
  }
450
450
  }
451
- return (hr() - batchStart) / BigInt(batchSize);
451
+ return ((hr() - batchStart) * DURATION_SCALE) / BigInt(batchSize);
452
452
  }
453
453
 
454
454
  if (preSync) {
@@ -526,7 +526,7 @@ export const benchmark = async <TContext, TInput>({
526
526
  }
527
527
  }
528
528
  const batchDuration = hr() - batchStart;
529
- sampleDuration = batchDuration / BigInt(batchSize);
529
+ sampleDuration = (batchDuration * DURATION_SCALE) / BigInt(batchSize);
530
530
  } else {
531
531
  for (let b = 0; b < batchSize; b++) {
532
532
  if (preSync) {
@@ -544,7 +544,7 @@ export const benchmark = async <TContext, TInput>({
544
544
  await postAsync(context, input);
545
545
  }
546
546
  }
547
- sampleDuration /= BigInt(batchSize);
547
+ sampleDuration = (sampleDuration * DURATION_SCALE) / BigInt(batchSize);
548
548
  }
549
549
 
550
550
  const sampleEnd = performance.now();
package/src/types.ts CHANGED
@@ -72,3 +72,4 @@ export enum Control {
72
72
  export const CONTROL_SLOTS = Object.values(Control).length / 2;
73
73
  export const DEFAULT_CYCLES = 1_000;
74
74
  export const Z95 = 1.96;
75
+ export const DURATION_SCALE = 1000n;