benchforge 0.1.11 → 0.2.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.
Files changed (253) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +99 -294
  3. package/bin/benchforge +1 -2
  4. package/dist/AnalyzeArchive-8NCJhmhS.mjs +145 -0
  5. package/dist/AnalyzeArchive-8NCJhmhS.mjs.map +1 -0
  6. package/dist/BenchMatrix-BZVrBB_h.mjs +1050 -0
  7. package/dist/BenchMatrix-BZVrBB_h.mjs.map +1 -0
  8. package/dist/{BenchRunner-BzyUfiyB.d.mts → BenchRunner-DglX1NOn.d.mts} +119 -66
  9. package/dist/CoverageSampler-D5T9DRqe.mjs +27 -0
  10. package/dist/CoverageSampler-D5T9DRqe.mjs.map +1 -0
  11. package/dist/Formatters-BWj3d4sv.mjs +95 -0
  12. package/dist/Formatters-BWj3d4sv.mjs.map +1 -0
  13. package/dist/{HeapSampler-B8dtKHn1.mjs → HeapSampler-Dq-hpXem.mjs} +4 -4
  14. package/dist/HeapSampler-Dq-hpXem.mjs.map +1 -0
  15. package/dist/RunBenchCLI-C17DrJz8.mjs +3075 -0
  16. package/dist/RunBenchCLI-C17DrJz8.mjs.map +1 -0
  17. package/dist/StatisticalUtils-BD92crgM.mjs +255 -0
  18. package/dist/StatisticalUtils-BD92crgM.mjs.map +1 -0
  19. package/dist/TimeSampler-Ds8n7l2B.mjs +29 -0
  20. package/dist/TimeSampler-Ds8n7l2B.mjs.map +1 -0
  21. package/dist/ViewerServer-BJhdnxlN.mjs +639 -0
  22. package/dist/ViewerServer-BJhdnxlN.mjs.map +1 -0
  23. package/dist/ViewerServer-CuMNdNBz.mjs +2 -0
  24. package/dist/bin/benchforge.mjs +4 -5
  25. package/dist/bin/benchforge.mjs.map +1 -1
  26. package/dist/index.d.mts +711 -558
  27. package/dist/index.mjs +98 -3
  28. package/dist/index.mjs.map +1 -0
  29. package/dist/runners/WorkerScript.d.mts +12 -4
  30. package/dist/runners/WorkerScript.mjs +77 -105
  31. package/dist/runners/WorkerScript.mjs.map +1 -1
  32. package/dist/viewer/assets/CIPlot-BkOvMoMa.js +1 -0
  33. package/dist/viewer/assets/HistogramKde-CmSyUFY0.js +1 -0
  34. package/dist/viewer/assets/LegendUtils-BJpbn_jr.js +55 -0
  35. package/dist/viewer/assets/SampleTimeSeries-C4VBhXr3.js +1 -0
  36. package/dist/viewer/assets/index-Br9bp_cX.js +153 -0
  37. package/dist/viewer/assets/index-NzXXe_CC.css +1 -0
  38. package/dist/viewer/index.html +19 -0
  39. package/dist/viewer/speedscope/LICENSE +21 -0
  40. package/dist/viewer/speedscope/SourceCodePro-Regular.ttf-ILST5JV6.woff2 +0 -0
  41. package/dist/viewer/speedscope/favicon-16x16-V2DMIAZS.js +2 -0
  42. package/dist/viewer/speedscope/favicon-16x16-V2DMIAZS.js.map +7 -0
  43. package/dist/viewer/speedscope/favicon-16x16-VSI62OPJ.png +0 -0
  44. package/dist/viewer/speedscope/favicon-32x32-3EB2YCUY.png +0 -0
  45. package/dist/viewer/speedscope/favicon-32x32-THY3JDJL.js +2 -0
  46. package/dist/viewer/speedscope/favicon-32x32-THY3JDJL.js.map +7 -0
  47. package/dist/viewer/speedscope/favicon-FOKUP5Y5.ico +0 -0
  48. package/dist/viewer/speedscope/favicon-M34RF7BI.js +2 -0
  49. package/dist/viewer/speedscope/favicon-M34RF7BI.js.map +7 -0
  50. package/dist/viewer/speedscope/file-format-schema.json +274 -0
  51. package/dist/viewer/speedscope/index.html +19 -0
  52. package/dist/viewer/speedscope/jfrview_bg-BLJXNNQB.wasm +0 -0
  53. package/dist/viewer/speedscope/perf-vertx-stacks-01-collapsed-all-ZNUIGAJL.txt +199 -0
  54. package/dist/viewer/speedscope/release.txt +3 -0
  55. package/dist/viewer/speedscope/source-code-pro.LICENSE.md +93 -0
  56. package/dist/viewer/speedscope/speedscope-GHPHNKXC.css +2 -0
  57. package/dist/viewer/speedscope/speedscope-GHPHNKXC.css.map +7 -0
  58. package/dist/viewer/speedscope/speedscope-QZFMJ7VP.js +212 -0
  59. package/dist/viewer/speedscope/speedscope-QZFMJ7VP.js.map +7 -0
  60. package/package.json +52 -27
  61. package/src/bin/benchforge.ts +2 -2
  62. package/src/cli/AnalyzeArchive.ts +232 -0
  63. package/src/cli/BrowserBench.ts +322 -0
  64. package/src/cli/CliArgs.ts +164 -51
  65. package/src/cli/CliExport.ts +179 -0
  66. package/src/cli/CliOptions.ts +147 -0
  67. package/src/cli/CliReport.ts +197 -0
  68. package/src/cli/FilterBenchmarks.ts +18 -30
  69. package/src/cli/RunBenchCLI.ts +132 -866
  70. package/src/cli/SuiteRunner.ts +160 -0
  71. package/src/cli/ViewerServer.ts +282 -0
  72. package/src/export/AllocExport.ts +121 -0
  73. package/src/export/ArchiveExport.ts +146 -0
  74. package/src/export/ArchiveFormat.ts +50 -0
  75. package/src/export/CoverageExport.ts +148 -0
  76. package/src/export/EditorUri.ts +10 -0
  77. package/src/export/PerfettoExport.ts +64 -99
  78. package/src/export/SpeedscopeTypes.ts +98 -0
  79. package/src/export/TimeExport.ts +115 -0
  80. package/src/index.ts +86 -67
  81. package/src/matrix/BenchMatrix.ts +230 -0
  82. package/src/matrix/CaseLoader.ts +8 -6
  83. package/src/matrix/MatrixDirRunner.ts +153 -0
  84. package/src/matrix/MatrixFilter.ts +49 -47
  85. package/src/matrix/MatrixInlineRunner.ts +50 -0
  86. package/src/matrix/MatrixReport.ts +90 -250
  87. package/src/matrix/VariantLoader.ts +5 -5
  88. package/src/profiling/browser/BenchLoop.ts +51 -0
  89. package/src/profiling/browser/BrowserCDP.ts +133 -0
  90. package/src/profiling/browser/BrowserGcStats.ts +33 -0
  91. package/src/profiling/browser/BrowserProfiler.ts +160 -0
  92. package/src/profiling/browser/CdpClient.ts +82 -0
  93. package/src/profiling/browser/CdpPage.ts +138 -0
  94. package/src/profiling/browser/ChromeLauncher.ts +158 -0
  95. package/src/profiling/browser/ChromeTraceEvent.ts +28 -0
  96. package/src/profiling/browser/PageLoadMode.ts +61 -0
  97. package/src/profiling/node/CoverageSampler.ts +27 -0
  98. package/src/profiling/node/CoverageTypes.ts +23 -0
  99. package/src/profiling/node/HeapSampleReport.ts +261 -0
  100. package/src/{heap-sample → profiling/node}/HeapSampler.ts +1 -2
  101. package/src/{heap-sample → profiling/node}/ResolvedProfile.ts +18 -9
  102. package/src/profiling/node/TimeSampler.ts +57 -0
  103. package/src/report/BenchmarkReport.ts +146 -0
  104. package/src/report/Colors.ts +9 -0
  105. package/src/report/Formatters.ts +110 -0
  106. package/src/report/GcSections.ts +151 -0
  107. package/src/{GitUtils.ts → report/GitUtils.ts} +18 -19
  108. package/src/report/HtmlReport.ts +223 -0
  109. package/src/report/ParseStats.ts +73 -0
  110. package/src/report/StandardSections.ts +147 -0
  111. package/src/report/ViewerSections.ts +286 -0
  112. package/src/report/text/TableReport.ts +253 -0
  113. package/src/report/text/TextReport.ts +123 -0
  114. package/src/runners/AdaptiveWrapper.ts +116 -236
  115. package/src/runners/BenchRunner.ts +20 -15
  116. package/src/{Benchmark.ts → runners/BenchmarkSpec.ts} +5 -6
  117. package/src/runners/CreateRunner.ts +5 -7
  118. package/src/runners/GcStats.ts +47 -50
  119. package/src/{MeasuredResults.ts → runners/MeasuredResults.ts} +43 -37
  120. package/src/runners/MergeBatches.ts +123 -0
  121. package/src/{NodeGC.ts → runners/NodeGC.ts} +2 -3
  122. package/src/runners/RunnerOrchestrator.ts +127 -243
  123. package/src/runners/RunnerUtils.ts +75 -1
  124. package/src/runners/SampleStats.ts +100 -0
  125. package/src/runners/TimingRunner.ts +244 -0
  126. package/src/runners/TimingUtils.ts +3 -2
  127. package/src/runners/WorkerScript.ts +135 -151
  128. package/src/stats/BootstrapDifference.ts +282 -0
  129. package/src/{PermutationTest.ts → stats/PermutationTest.ts} +8 -17
  130. package/src/stats/StatisticalUtils.ts +445 -0
  131. package/src/{tests → test}/AdaptiveConvergence.test.ts +10 -10
  132. package/src/test/AdaptiveRunner.test.ts +39 -41
  133. package/src/{tests → test}/AdaptiveSampling.test.ts +9 -9
  134. package/src/test/AdaptiveStatistics.integration.ts +2 -2
  135. package/src/{tests → test}/BenchMatrix.test.ts +19 -16
  136. package/src/test/BenchmarkReport.test.ts +63 -13
  137. package/src/test/BrowserBench.e2e.test.ts +186 -17
  138. package/src/test/BrowserBench.test.ts +10 -5
  139. package/src/test/BuildTimeSection.test.ts +130 -0
  140. package/src/test/CapSamples.test.ts +82 -0
  141. package/src/test/CoverageExport.test.ts +115 -0
  142. package/src/test/CoverageSampler.test.ts +33 -0
  143. package/src/test/HeapAttribution.test.ts +14 -14
  144. package/src/{tests → test}/MatrixFilter.test.ts +1 -1
  145. package/src/{tests → test}/MatrixReport.test.ts +1 -1
  146. package/src/test/PermutationTest.test.ts +1 -1
  147. package/src/{tests → test}/RealDataValidation.test.ts +6 -6
  148. package/src/test/RunBenchCLI.test.ts +39 -38
  149. package/src/test/RunnerOrchestrator.test.ts +12 -12
  150. package/src/test/StatisticalUtils.test.ts +48 -12
  151. package/src/{table-util/test → test}/TableReport.test.ts +2 -2
  152. package/src/test/TestUtils.ts +12 -7
  153. package/src/test/TimeExport.test.ts +139 -0
  154. package/src/test/TimeSampler.test.ts +37 -0
  155. package/src/test/ViewerLive.e2e.test.ts +159 -0
  156. package/src/test/ViewerStatic.static.e2e.test.ts +137 -0
  157. package/src/{tests → test}/fixtures/baseline/impl.ts +1 -1
  158. package/src/{tests → test}/fixtures/bevy30-samples.ts +3 -1
  159. package/src/test/fixtures/cases/asyncCases.ts +9 -0
  160. package/src/{tests → test}/fixtures/cases/cases.ts +5 -2
  161. package/src/test/fixtures/cases/variants/product.ts +2 -0
  162. package/src/test/fixtures/cases/variants/sum.ts +2 -0
  163. package/src/test/fixtures/discover/fast.ts +1 -0
  164. package/src/{tests → test}/fixtures/discover/slow.ts +1 -1
  165. package/src/test/fixtures/invalid/bad.ts +1 -0
  166. package/src/test/fixtures/loader/fast.ts +1 -0
  167. package/src/{tests → test}/fixtures/loader/slow.ts +1 -1
  168. package/src/test/fixtures/loader/stateful.ts +2 -0
  169. package/src/test/fixtures/stateful/stateful.ts +2 -0
  170. package/src/test/fixtures/variants/extra.ts +1 -0
  171. package/src/test/fixtures/variants/impl.ts +1 -0
  172. package/src/test/fixtures/worker/fast.ts +1 -0
  173. package/src/{tests → test}/fixtures/worker/slow.ts +1 -1
  174. package/src/viewer/DateFormat.ts +30 -0
  175. package/src/viewer/Helpers.ts +23 -0
  176. package/src/viewer/LineData.ts +120 -0
  177. package/src/viewer/Providers.ts +191 -0
  178. package/src/viewer/ReportData.ts +123 -0
  179. package/src/viewer/State.ts +49 -0
  180. package/src/viewer/Theme.ts +15 -0
  181. package/src/viewer/components/App.tsx +73 -0
  182. package/src/viewer/components/DropZone.tsx +71 -0
  183. package/src/viewer/components/LazyPlot.ts +33 -0
  184. package/src/viewer/components/SamplesPanel.tsx +214 -0
  185. package/src/viewer/components/Shell.tsx +26 -0
  186. package/src/viewer/components/SourcePanel.tsx +216 -0
  187. package/src/viewer/components/SummaryPanel.tsx +332 -0
  188. package/src/viewer/components/TabBar.tsx +131 -0
  189. package/src/viewer/components/TabContent.tsx +46 -0
  190. package/src/viewer/components/ThemeToggle.tsx +50 -0
  191. package/src/viewer/index.html +20 -0
  192. package/src/viewer/main.tsx +4 -0
  193. package/src/viewer/plots/CIPlot.ts +313 -0
  194. package/src/{html/browser → viewer/plots}/HistogramKde.ts +33 -38
  195. package/src/viewer/plots/LegendUtils.ts +134 -0
  196. package/src/viewer/plots/PlotTypes.ts +85 -0
  197. package/src/viewer/plots/RenderPlots.ts +230 -0
  198. package/src/viewer/plots/SampleTimeSeries.ts +306 -0
  199. package/src/viewer/plots/SvgHelpers.ts +136 -0
  200. package/src/viewer/plots/TimeSeriesMarks.ts +319 -0
  201. package/src/viewer/report.css +427 -0
  202. package/src/viewer/shell.css +357 -0
  203. package/src/viewer/tsconfig.json +11 -0
  204. package/dist/BrowserHeapSampler-B6asLKWQ.mjs +0 -202
  205. package/dist/BrowserHeapSampler-B6asLKWQ.mjs.map +0 -1
  206. package/dist/GcStats-wX7Xyblu.mjs +0 -77
  207. package/dist/GcStats-wX7Xyblu.mjs.map +0 -1
  208. package/dist/HeapSampler-B8dtKHn1.mjs.map +0 -1
  209. package/dist/TimingUtils-DwOwkc8G.mjs +0 -597
  210. package/dist/TimingUtils-DwOwkc8G.mjs.map +0 -1
  211. package/dist/browser/index.js +0 -914
  212. package/dist/src-B-DDaCa9.mjs +0 -3108
  213. package/dist/src-B-DDaCa9.mjs.map +0 -1
  214. package/src/BenchMatrix.ts +0 -380
  215. package/src/BenchmarkReport.ts +0 -161
  216. package/src/HtmlDataPrep.ts +0 -148
  217. package/src/StandardSections.ts +0 -261
  218. package/src/StatisticalUtils.ts +0 -175
  219. package/src/TypeUtil.ts +0 -8
  220. package/src/browser/BrowserGcStats.ts +0 -44
  221. package/src/browser/BrowserHeapSampler.ts +0 -271
  222. package/src/export/JsonExport.ts +0 -103
  223. package/src/export/JsonFormat.ts +0 -91
  224. package/src/export/SpeedscopeExport.ts +0 -202
  225. package/src/heap-sample/HeapSampleReport.ts +0 -269
  226. package/src/html/HtmlReport.ts +0 -131
  227. package/src/html/HtmlTemplate.ts +0 -284
  228. package/src/html/Types.ts +0 -88
  229. package/src/html/browser/CIPlot.ts +0 -287
  230. package/src/html/browser/LegendUtils.ts +0 -163
  231. package/src/html/browser/RenderPlots.ts +0 -263
  232. package/src/html/browser/SampleTimeSeries.ts +0 -389
  233. package/src/html/browser/Types.ts +0 -96
  234. package/src/html/browser/index.ts +0 -1
  235. package/src/html/index.ts +0 -17
  236. package/src/runners/BasicRunner.ts +0 -364
  237. package/src/table-util/ConvergenceFormatters.ts +0 -19
  238. package/src/table-util/Formatters.ts +0 -157
  239. package/src/table-util/README.md +0 -70
  240. package/src/table-util/TableReport.ts +0 -293
  241. package/src/tests/fixtures/cases/asyncCases.ts +0 -7
  242. package/src/tests/fixtures/cases/variants/product.ts +0 -2
  243. package/src/tests/fixtures/cases/variants/sum.ts +0 -2
  244. package/src/tests/fixtures/discover/fast.ts +0 -1
  245. package/src/tests/fixtures/invalid/bad.ts +0 -1
  246. package/src/tests/fixtures/loader/fast.ts +0 -1
  247. package/src/tests/fixtures/loader/stateful.ts +0 -2
  248. package/src/tests/fixtures/stateful/stateful.ts +0 -2
  249. package/src/tests/fixtures/variants/extra.ts +0 -1
  250. package/src/tests/fixtures/variants/impl.ts +0 -1
  251. package/src/tests/fixtures/worker/fast.ts +0 -1
  252. /package/src/{table-util/test → test}/TableValueExtractor.test.ts +0 -0
  253. /package/src/{table-util/test → test}/TableValueExtractor.ts +0 -0
package/src/index.ts CHANGED
@@ -1,3 +1,36 @@
1
+ export type { Configure, DefaultCliArgs } from "./cli/CliArgs.ts";
2
+ export { browserCliArgs, defaultCliArgs, parseCliArgs } from "./cli/CliArgs.ts";
3
+ export type { ExportOptions, MatrixExportOptions } from "./cli/CliExport.ts";
4
+ export { exportReports } from "./cli/CliExport.ts";
5
+ export { cliToMatrixOptions } from "./cli/CliOptions.ts";
6
+ export {
7
+ defaultMatrixReport,
8
+ defaultReport,
9
+ matrixToReportGroups,
10
+ printHeapReports,
11
+ reportOptStatus,
12
+ } from "./cli/CliReport.ts";
13
+ export {
14
+ benchExports,
15
+ dispatchCli,
16
+ matrixBenchExports,
17
+ parseBenchArgs,
18
+ runDefaultBench,
19
+ runDefaultMatrixBench,
20
+ runMatrixSuite,
21
+ } from "./cli/RunBenchCLI.ts";
22
+ export { runBenchmarks } from "./cli/SuiteRunner.ts";
23
+ export {
24
+ buildSpeedscopeFile,
25
+ exportSpeedscope,
26
+ heapProfileToSpeedscope,
27
+ } from "./export/AllocExport.ts";
28
+ export { archiveBenchmark } from "./export/ArchiveExport.ts";
29
+ export type {
30
+ ArchiveMetadata,
31
+ BenchforgeArchive,
32
+ } from "./export/ArchiveFormat.ts";
33
+ export { exportPerfettoTrace } from "./export/PerfettoExport.ts";
1
34
  export type {
2
35
  AnyVariant,
3
36
  BenchMatrix,
@@ -11,88 +44,74 @@ export type {
11
44
  Variant,
12
45
  VariantFn,
13
46
  VariantResult,
14
- } from "./BenchMatrix.ts";
15
- export { isStatefulVariant, runMatrix } from "./BenchMatrix.ts";
16
- export type { BenchGroup, BenchmarkSpec, BenchSuite } from "./Benchmark.ts";
47
+ } from "./matrix/BenchMatrix.ts";
48
+ export { isStatefulVariant, runMatrix } from "./matrix/BenchMatrix.ts";
49
+ export type { CasesModule } from "./matrix/CaseLoader.ts";
50
+ export { loadCaseData, loadCasesModule } from "./matrix/CaseLoader.ts";
51
+ export type { FilteredMatrix, MatrixFilter } from "./matrix/MatrixFilter.ts";
52
+ export { filterMatrix, parseMatrixFilter } from "./matrix/MatrixFilter.ts";
53
+ export type { MatrixReportOptions } from "./matrix/MatrixReport.ts";
54
+ export { reportMatrixResults } from "./matrix/MatrixReport.ts";
17
55
  export type {
18
56
  BenchmarkReport,
19
- ReportColumnGroup,
57
+ ComparisonOptions,
58
+ ReportColumn,
20
59
  ReportGroup,
21
- ResultsMapper,
60
+ ReportSection,
22
61
  UnknownRecord,
23
- } from "./BenchmarkReport.ts";
24
- export { reportResults } from "./BenchmarkReport.ts";
25
- export type { Configure, DefaultCliArgs } from "./cli/CliArgs.ts";
26
- export { defaultCliArgs, parseCliArgs } from "./cli/CliArgs.ts";
27
- export type { ExportOptions, MatrixExportOptions } from "./cli/RunBenchCLI.ts";
62
+ } from "./report/BenchmarkReport.ts";
28
63
  export {
29
- benchExports,
30
- cliToMatrixOptions,
31
- defaultMatrixReport,
32
- defaultReport,
33
- exportReports,
64
+ computeColumnValues,
34
65
  hasField,
35
- matrixBenchExports,
36
- matrixToReportGroups,
37
- parseBenchArgs,
38
- printHeapReports,
39
- reportOptStatus,
40
- runBenchmarks,
41
- runDefaultBench,
42
- runDefaultMatrixBench,
43
- runMatrixSuite,
44
- } from "./cli/RunBenchCLI.ts";
45
- export * from "./export/JsonFormat.ts";
46
- export { exportPerfettoTrace } from "./export/PerfettoExport.ts";
66
+ } from "./report/BenchmarkReport.ts";
47
67
  export {
48
- exportAndLaunchSpeedscope,
49
- exportSpeedscope,
50
- heapProfileToSpeedscope,
51
- launchSpeedscope,
52
- } from "./export/SpeedscopeExport.ts";
53
- export type { GitVersion } from "./GitUtils.ts";
68
+ formatBytes,
69
+ formatConvergence,
70
+ integer,
71
+ timeMs,
72
+ truncate,
73
+ } from "./report/Formatters.ts";
74
+ export {
75
+ gcSection,
76
+ gcSections,
77
+ gcStatsSection,
78
+ } from "./report/GcSections.ts";
79
+ export type { GitVersion } from "./report/GitUtils.ts";
54
80
  export {
55
- formatDateWithTimezone,
56
81
  formatGitVersion,
57
82
  getBaselineVersion,
58
83
  getCurrentGitVersion,
59
- } from "./GitUtils.ts";
60
- export type { PrepareHtmlOptions } from "./HtmlDataPrep.ts";
61
- export { prepareHtmlData } from "./HtmlDataPrep.ts";
62
- export type { HtmlReportOptions, ReportData } from "./html/index.ts";
63
- export { generateHtmlReport } from "./html/index.ts";
64
- export type { MeasuredResults } from "./MeasuredResults.ts";
65
- export type { CasesModule } from "./matrix/CaseLoader.ts";
66
- export { loadCaseData, loadCasesModule } from "./matrix/CaseLoader.ts";
67
- export type { FilteredMatrix, MatrixFilter } from "./matrix/MatrixFilter.ts";
68
- export { filterMatrix, parseMatrixFilter } from "./matrix/MatrixFilter.ts";
69
- export type {
70
- ExtraColumn,
71
- MatrixReportOptions,
72
- } from "./matrix/MatrixReport.ts";
84
+ } from "./report/GitUtils.ts";
85
+ export type { PrepareHtmlOptions } from "./report/HtmlReport.ts";
86
+ export { prepareHtmlData } from "./report/HtmlReport.ts";
73
87
  export {
74
- gcPauseColumn,
75
- gcStatsColumns,
76
- heapTotalColumn,
77
- reportMatrixResults,
78
- } from "./matrix/MatrixReport.ts";
79
- export type { RunnerOptions } from "./runners/BenchRunner.ts";
80
- export {
81
- adaptiveSection,
88
+ adaptiveSections,
82
89
  buildGenericSections,
83
- cpuSection,
84
- gcSection,
85
- gcStatsSection,
90
+ buildTimeSection,
86
91
  optSection,
87
92
  runsSection,
88
93
  timeSection,
89
94
  totalTimeSection,
90
- } from "./StandardSections.ts";
91
- export { average } from "./StatisticalUtils.ts";
92
- export { formatConvergence } from "./table-util/ConvergenceFormatters.ts";
95
+ } from "./report/StandardSections.ts";
96
+ export { reportResults } from "./report/text/TextReport.ts";
97
+ export type {
98
+ BenchGroup,
99
+ BenchmarkSpec,
100
+ BenchSuite,
101
+ } from "./runners/BenchmarkSpec.ts";
102
+ export type { RunnerOptions } from "./runners/BenchRunner.ts";
103
+ export type { MeasuredResults } from "./runners/MeasuredResults.ts";
93
104
  export {
94
- formatBytes,
95
- integer,
96
- timeMs,
97
- truncate,
98
- } from "./table-util/Formatters.ts";
105
+ average,
106
+ computeStat,
107
+ isBootstrappable,
108
+ maxBootstrapInput,
109
+ median,
110
+ percentile,
111
+ type StatKind,
112
+ } from "./stats/StatisticalUtils.ts";
113
+ export {
114
+ formatDateWithTimezone,
115
+ formatRelativeTime,
116
+ } from "./viewer/DateFormat.ts";
117
+ export type { ReportData } from "./viewer/ReportData.ts";
@@ -0,0 +1,230 @@
1
+ import type { RunnerOptions } from "../runners/BenchRunner.ts";
2
+ import type { MeasuredResults } from "../runners/MeasuredResults.ts";
3
+ import { average } from "../stats/StatisticalUtils.ts";
4
+ import type { CasesModule } from "./CaseLoader.ts";
5
+ import { loadCasesModule } from "./CaseLoader.ts";
6
+ import { runMatrixWithDir } from "./MatrixDirRunner.ts";
7
+ import { runMatrixInline } from "./MatrixInlineRunner.ts";
8
+
9
+ /** Stateless variant - called each iteration with case data */
10
+ export type VariantFn<T = unknown> = (caseData: T) => void;
11
+
12
+ /** Stateful variant - setup once, run many */
13
+ export interface StatefulVariant<T = unknown, S = unknown> {
14
+ setup: (caseData: T) => S | Promise<S>;
15
+ run: (state: S) => void;
16
+ }
17
+
18
+ /** A variant is either a plain function or a stateful setup+run pair */
19
+ export type Variant<T = unknown, S = unknown> =
20
+ | VariantFn<T>
21
+ | StatefulVariant<T, S>;
22
+
23
+ /** Variant with any state type, allowing mixed variants in a matrix */
24
+ export type AnyVariant<T = unknown> = VariantFn<T> | StatefulVariant<T, any>;
25
+
26
+ /** Case data and optional metadata returned by a cases module */
27
+ export interface LoadedCase<T = unknown> {
28
+ data: T;
29
+ metadata?: Record<string, unknown>;
30
+ }
31
+
32
+ /** Default runner settings applied to all matrix benchmarks */
33
+ export interface MatrixDefaults {
34
+ warmup?: number;
35
+ maxTime?: number;
36
+ iterations?: number;
37
+ }
38
+
39
+ /** Configuration for a cases x variants benchmark matrix */
40
+ export interface BenchMatrix<T = unknown> {
41
+ name: string;
42
+ variantDir?: string;
43
+ variants?: Record<string, AnyVariant<T>>;
44
+ cases?: string[];
45
+ casesModule?: string;
46
+ baselineDir?: string;
47
+ baselineVariant?: string;
48
+ defaults?: MatrixDefaults;
49
+ }
50
+
51
+ /** Named collection of benchmark matrices */
52
+ export interface MatrixSuite {
53
+ name: string;
54
+ matrices: BenchMatrix<any>[];
55
+ }
56
+
57
+ /** Results for a single variant across all cases */
58
+ export interface VariantResult {
59
+ id: string;
60
+ cases: CaseResult[];
61
+ }
62
+
63
+ /** Results for a single (variant, case) pair */
64
+ export interface CaseResult {
65
+ caseId: string;
66
+ measured: MeasuredResults;
67
+ metadata?: Record<string, unknown>;
68
+ baseline?: MeasuredResults;
69
+ deltaPercent?: number;
70
+ }
71
+
72
+ /** Aggregated results from running a benchmark matrix */
73
+ export interface MatrixResults {
74
+ name: string;
75
+ variants: VariantResult[];
76
+ }
77
+
78
+ /** Options for {@link runMatrix} */
79
+ export interface RunMatrixOptions {
80
+ /** Maximum iterations per benchmark */
81
+ iterations?: number;
82
+ /** Maximum time in ms per benchmark */
83
+ maxTime?: number;
84
+ /** Number of warmup iterations before measurement */
85
+ warmup?: number;
86
+ /** Use worker process isolation (default: true for variantDir) */
87
+ useWorker?: boolean;
88
+ /** Number of interleaved batches for baseline comparison */
89
+ batches?: number;
90
+ /** Include first batch in results (normally dropped for OS cache warmup) */
91
+ warmupBatch?: boolean;
92
+ /** Run only these cases (from --filter) */
93
+ filteredCases?: string[];
94
+ /** Run only these variants (from --filter) */
95
+ filteredVariants?: string[];
96
+ /** Force garbage collection between iterations */
97
+ gcForce?: boolean;
98
+ /** Track V8 optimization/deoptimization events */
99
+ traceOpt?: boolean;
100
+ /** Pause duration in ms before warmup begins */
101
+ pauseWarmup?: number;
102
+ /** Pause duration in ms before first measurement */
103
+ pauseFirst?: number;
104
+ /** Pause every N iterations during measurement */
105
+ pauseInterval?: number;
106
+ /** Duration of each pause in ms */
107
+ pauseDuration?: number;
108
+ /** Collect GC statistics via --trace-gc-nvp */
109
+ gcStats?: boolean;
110
+ /** Enable heap allocation profiling */
111
+ alloc?: boolean;
112
+ /** Heap sampling interval in bytes */
113
+ allocInterval?: number;
114
+ /** Maximum stack depth for allocation traces */
115
+ allocDepth?: number;
116
+ /** Enable CPU time profiling */
117
+ profile?: boolean;
118
+ /** CPU profiling sample interval in microseconds */
119
+ profileInterval?: number;
120
+ /** Track function call counts via V8 coverage */
121
+ callCounts?: boolean;
122
+ }
123
+
124
+ /** Run a BenchMatrix with inline variants or variantDir */
125
+ export async function runMatrix<T>(
126
+ matrix: BenchMatrix<T>,
127
+ options: RunMatrixOptions = {},
128
+ ): Promise<MatrixResults> {
129
+ if (matrix.baselineDir && matrix.baselineVariant)
130
+ throw new Error(
131
+ "BenchMatrix cannot have both 'baselineDir' and 'baselineVariant'",
132
+ );
133
+ if (!matrix.variantDir && !matrix.variants)
134
+ throw new Error("BenchMatrix requires either 'variants' or 'variantDir'");
135
+
136
+ const effectiveOptions = { ...matrix.defaults, ...options };
137
+ const result = matrix.variantDir
138
+ ? await runMatrixWithDir(matrix, effectiveOptions)
139
+ : await runMatrixInline(matrix, effectiveOptions);
140
+
141
+ if (matrix.baselineVariant) {
142
+ applyBaselineVariant(result.variants, matrix.baselineVariant);
143
+ }
144
+ return result;
145
+ }
146
+
147
+ /** Prepare a benchmark function from a variant, calling setup if stateful. */
148
+ export async function prepareBenchFn<T>(
149
+ variant: Variant<T>,
150
+ data: T,
151
+ ): Promise<() => void> {
152
+ if (isStatefulVariant(variant)) {
153
+ const state = await variant.setup(data);
154
+ return () => variant.run(state);
155
+ }
156
+ return () => variant(data);
157
+ }
158
+
159
+ /** Type guard for StatefulVariant */
160
+ export function isStatefulVariant<T, S>(
161
+ v: Variant<T, S>,
162
+ ): v is StatefulVariant<T, S> {
163
+ return typeof v === "object" && "setup" in v && "run" in v;
164
+ }
165
+
166
+ /** Apply baselineVariant comparison - one variant is the reference for all others */
167
+ export function applyBaselineVariant(
168
+ variants: VariantResult[],
169
+ baselineVariantId: string,
170
+ ): void {
171
+ const baselineVariant = variants.find(v => v.id === baselineVariantId);
172
+ if (!baselineVariant) return;
173
+
174
+ const baselineByCase = new Map(
175
+ baselineVariant.cases.map(c => [c.caseId, c.measured]),
176
+ );
177
+
178
+ for (const variant of variants) {
179
+ if (variant.id === baselineVariantId) continue;
180
+ for (const cr of variant.cases) {
181
+ const base = baselineByCase.get(cr.caseId);
182
+ if (base) {
183
+ cr.baseline = base;
184
+ cr.deltaPercent = computeDeltaPercent(base, cr.measured);
185
+ }
186
+ }
187
+ }
188
+ }
189
+
190
+ /** Load cases module and resolve filtered case IDs */
191
+ export async function resolveCases<T>(
192
+ matrix: BenchMatrix<T>,
193
+ options: RunMatrixOptions,
194
+ ): Promise<{ casesModule: CasesModule<T> | undefined; caseIds: string[] }> {
195
+ const casesModule = matrix.casesModule
196
+ ? await loadCasesModule<T>(matrix.casesModule)
197
+ : undefined;
198
+ const allCaseIds = casesModule?.cases ?? matrix.cases ?? ["default"];
199
+ const caseIds = options.filteredCases ?? allCaseIds;
200
+ return { casesModule, caseIds };
201
+ }
202
+
203
+ /** Map matrix options to runner options, applying defaults for maxTime and warmup */
204
+ export function buildRunnerOptions(opts: RunMatrixOptions): RunnerOptions {
205
+ const {
206
+ filteredCases,
207
+ filteredVariants,
208
+ useWorker,
209
+ batches,
210
+ warmupBatch,
211
+ ...base
212
+ } = opts;
213
+ const { iterations, maxTime, warmup, ...rest } = base;
214
+ return {
215
+ maxIterations: iterations,
216
+ maxTime: maxTime ?? (iterations ? undefined : 1000),
217
+ warmup: warmup ?? 0,
218
+ ...rest,
219
+ };
220
+ }
221
+
222
+ /** Compute percentage change of current vs baseline mean */
223
+ export function computeDeltaPercent(
224
+ base: MeasuredResults,
225
+ cur: MeasuredResults,
226
+ ): number {
227
+ const avg = average(base.samples);
228
+ if (avg === 0) return 0;
229
+ return ((average(cur.samples) - avg) / avg) * 100;
230
+ }
@@ -1,14 +1,16 @@
1
- import type { LoadedCase } from "../BenchMatrix.ts";
1
+ import type { LoadedCase } from "./BenchMatrix.ts";
2
2
 
3
- /** Module that exports case definitions */
3
+ /** Module exporting case IDs and an optional loader for case data */
4
4
  export interface CasesModule<T = unknown> {
5
5
  cases: string[];
6
- defaultCases?: string[]; // subset for quick runs
7
- defaultVariants?: string[]; // subset for quick runs
6
+ /** Subset of cases for quick runs */
7
+ defaultCases?: string[];
8
+ /** Subset of variants for quick runs */
9
+ defaultVariants?: string[];
8
10
  loadCase?: (id: string) => LoadedCase<T> | Promise<LoadedCase<T>>;
9
11
  }
10
12
 
11
- /** Load a cases module by URL */
13
+ /** Import and validate a cases module, which must export a `cases` array */
12
14
  export async function loadCasesModule<T = unknown>(
13
15
  moduleUrl: string,
14
16
  ): Promise<CasesModule<T>> {
@@ -24,7 +26,7 @@ export async function loadCasesModule<T = unknown>(
24
26
  };
25
27
  }
26
28
 
27
- /** Load case data from a CasesModule or pass through the caseId */
29
+ /** Load case data from a CasesModule, or use the caseId as data if no module */
28
30
  export async function loadCaseData<T>(
29
31
  casesModule: CasesModule<T> | undefined,
30
32
  caseId: string,
@@ -0,0 +1,153 @@
1
+ import type { RunnerOptions } from "../runners/BenchRunner.ts";
2
+ import type { MeasuredResults } from "../runners/MeasuredResults.ts";
3
+ import { runBatched } from "../runners/MergeBatches.ts";
4
+ import { runMatrixVariant } from "../runners/RunnerOrchestrator.ts";
5
+ import type {
6
+ BenchMatrix,
7
+ CaseResult,
8
+ RunMatrixOptions,
9
+ VariantResult,
10
+ } from "./BenchMatrix.ts";
11
+ import {
12
+ buildRunnerOptions,
13
+ computeDeltaPercent,
14
+ resolveCases,
15
+ } from "./BenchMatrix.ts";
16
+ import type { CasesModule } from "./CaseLoader.ts";
17
+ import { loadCaseData } from "./CaseLoader.ts";
18
+ import { discoverVariants } from "./VariantLoader.ts";
19
+
20
+ type VariantArgs = Parameters<typeof runMatrixVariant>[0];
21
+
22
+ /** Shared state for directory-based matrix execution */
23
+ interface DirMatrixContext<T> {
24
+ matrix: BenchMatrix<T>;
25
+ casesModule?: CasesModule<T>;
26
+ baselineIds: string[];
27
+ caseIds: string[];
28
+ runnerOpts: RunnerOptions;
29
+ batches: number;
30
+ warmupBatch: boolean;
31
+ useWorker: boolean;
32
+ }
33
+
34
+ /** Run matrix using variant files from a directory, each in a worker process */
35
+ export async function runMatrixWithDir<T>(
36
+ matrix: BenchMatrix<T>,
37
+ options: RunMatrixOptions,
38
+ ): Promise<{ name: string; variants: VariantResult[] }> {
39
+ const allVariantIds = await discoverVariants(matrix.variantDir!);
40
+ if (allVariantIds.length === 0) {
41
+ throw new Error(`No variants found in ${matrix.variantDir}`);
42
+ }
43
+ const variantIds = options.filteredVariants ?? allVariantIds;
44
+
45
+ const ctx = await createDirContext(matrix, options);
46
+ const variants = await runDirVariants(variantIds, ctx);
47
+ return { name: matrix.name, variants };
48
+ }
49
+
50
+ /** Create context for directory-based matrix execution */
51
+ async function createDirContext<T>(
52
+ matrix: BenchMatrix<T>,
53
+ options: RunMatrixOptions,
54
+ ): Promise<DirMatrixContext<T>> {
55
+ const baselineIds = matrix.baselineDir
56
+ ? await discoverVariants(matrix.baselineDir)
57
+ : [];
58
+ const { casesModule, caseIds } = await resolveCases(matrix, options);
59
+ const runnerOpts = buildRunnerOptions(options);
60
+ const { batches = 1, warmupBatch = false, useWorker = true } = options;
61
+ return {
62
+ matrix,
63
+ casesModule,
64
+ baselineIds,
65
+ caseIds,
66
+ runnerOpts,
67
+ batches,
68
+ warmupBatch,
69
+ useWorker,
70
+ };
71
+ }
72
+
73
+ /** Run all variants sequentially, collecting per-case results */
74
+ async function runDirVariants<T>(
75
+ variantIds: string[],
76
+ ctx: DirMatrixContext<T>,
77
+ ): Promise<VariantResult[]> {
78
+ const variants: VariantResult[] = [];
79
+ for (const id of variantIds) {
80
+ const cases = await runDirVariantCases(id, ctx);
81
+ variants.push({ id, cases });
82
+ }
83
+ return variants;
84
+ }
85
+
86
+ /** Run all cases for a single variant */
87
+ async function runDirVariantCases<T>(
88
+ variantId: string,
89
+ ctx: DirMatrixContext<T>,
90
+ ): Promise<CaseResult[]> {
91
+ const { matrix, casesModule, caseIds, runnerOpts, batches } = ctx;
92
+ const cases: CaseResult[] = [];
93
+
94
+ for (const caseId of caseIds) {
95
+ const caseData = matrix.cases && !matrix.casesModule ? caseId : undefined;
96
+ const variantArgs: VariantArgs = {
97
+ variantDir: matrix.variantDir!,
98
+ variantId,
99
+ caseId,
100
+ caseData,
101
+ casesModule: matrix.casesModule,
102
+ runner: "timing" as const,
103
+ options: runnerOpts,
104
+ useWorker: ctx.useWorker,
105
+ };
106
+ const baselineArgs =
107
+ matrix.baselineDir && ctx.baselineIds.includes(variantId)
108
+ ? { ...variantArgs, variantDir: matrix.baselineDir! }
109
+ : undefined;
110
+
111
+ const { metadata } = await loadCaseData(casesModule, caseId);
112
+ const { measured, baseline } =
113
+ batches > 1
114
+ ? await runCaseBatched(variantArgs, baselineArgs, ctx)
115
+ : await runCaseSingle(variantArgs, baselineArgs);
116
+ const deltaPercent = baseline
117
+ ? computeDeltaPercent(baseline, measured)
118
+ : undefined;
119
+ cases.push({ caseId, measured, metadata, baseline, deltaPercent });
120
+ }
121
+ return cases;
122
+ }
123
+
124
+ /** Run a batched measurement for a case, alternating current/baseline order. */
125
+ async function runCaseBatched<T>(
126
+ variantArgs: VariantArgs,
127
+ baselineArgs: VariantArgs | undefined,
128
+ ctx: DirMatrixContext<T>,
129
+ ): Promise<{ measured: MeasuredResults; baseline?: MeasuredResults }> {
130
+ const runCurrent = async () => (await runMatrixVariant(variantArgs))[0];
131
+ const runBase = baselineArgs
132
+ ? async () => (await runMatrixVariant(baselineArgs))[0]
133
+ : undefined;
134
+ const { results, baseline } = await runBatched(
135
+ [runCurrent],
136
+ runBase,
137
+ ctx.batches,
138
+ ctx.warmupBatch,
139
+ );
140
+ return { measured: results[0], baseline };
141
+ }
142
+
143
+ /** Run a single unbatched measurement for a case. */
144
+ async function runCaseSingle(
145
+ variantArgs: VariantArgs,
146
+ baselineArgs: VariantArgs | undefined,
147
+ ): Promise<{ measured: MeasuredResults; baseline?: MeasuredResults }> {
148
+ const [measured] = await runMatrixVariant(variantArgs);
149
+ const baseline = baselineArgs
150
+ ? (await runMatrixVariant(baselineArgs))[0]
151
+ : undefined;
152
+ return { measured, baseline };
153
+ }