@buoy-gg/benchmark 2.1.3 → 2.1.4-beta.1

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 (34) hide show
  1. package/lib/commonjs/benchmarking/BenchmarkComparator.js +221 -1
  2. package/lib/commonjs/benchmarking/BenchmarkRecorder.js +497 -1
  3. package/lib/commonjs/benchmarking/BenchmarkStorage.js +235 -1
  4. package/lib/commonjs/benchmarking/index.js +83 -1
  5. package/lib/commonjs/benchmarking/types.js +13 -1
  6. package/lib/commonjs/components/BenchmarkCompareView.js +475 -1
  7. package/lib/commonjs/components/BenchmarkDetailView.js +346 -1
  8. package/lib/commonjs/components/BenchmarkModal.js +505 -1
  9. package/lib/commonjs/components/BenchmarkSessionCard.js +193 -1
  10. package/lib/commonjs/index.js +62 -1
  11. package/lib/commonjs/preset.js +86 -1
  12. package/lib/module/benchmarking/BenchmarkComparator.js +216 -1
  13. package/lib/module/benchmarking/BenchmarkRecorder.js +493 -1
  14. package/lib/module/benchmarking/BenchmarkStorage.js +227 -1
  15. package/lib/module/benchmarking/index.js +48 -1
  16. package/lib/module/benchmarking/types.js +13 -1
  17. package/lib/module/components/BenchmarkCompareView.js +469 -1
  18. package/lib/module/components/BenchmarkDetailView.js +340 -1
  19. package/lib/module/components/BenchmarkModal.js +499 -1
  20. package/lib/module/components/BenchmarkSessionCard.js +187 -1
  21. package/lib/module/index.js +39 -1
  22. package/lib/module/preset.js +81 -1
  23. package/lib/typescript/benchmarking/BenchmarkComparator.d.ts.map +1 -0
  24. package/lib/typescript/benchmarking/BenchmarkRecorder.d.ts.map +1 -0
  25. package/lib/typescript/benchmarking/BenchmarkStorage.d.ts.map +1 -0
  26. package/lib/typescript/benchmarking/index.d.ts.map +1 -0
  27. package/lib/typescript/benchmarking/types.d.ts.map +1 -0
  28. package/lib/typescript/components/BenchmarkCompareView.d.ts.map +1 -0
  29. package/lib/typescript/components/BenchmarkDetailView.d.ts.map +1 -0
  30. package/lib/typescript/components/BenchmarkModal.d.ts.map +1 -0
  31. package/lib/typescript/components/BenchmarkSessionCard.d.ts.map +1 -0
  32. package/lib/typescript/index.d.ts.map +1 -0
  33. package/lib/typescript/preset.d.ts.map +1 -0
  34. package/package.json +2 -2
@@ -1 +1,193 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.BenchmarkSessionCard=BenchmarkSessionCard,exports.default=void 0;var _react=_interopRequireDefault(require("react")),_reactNative=require("react-native"),_sharedUi=require("@buoy-gg/shared-ui"),_jsxRuntime=require("react/jsx-runtime");function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e}}function formatDuration(e){return e<1e3?`${e.toFixed(0)}ms`:e<6e4?`${(e/1e3).toFixed(1)}s`:`${Math.floor(e/6e4)}m ${(e%6e4/1e3).toFixed(0)}s`}function formatDate(e){const t=new Date(e),r=(new Date).getTime()-t.getTime(),s=Math.floor(r/6e4),a=Math.floor(r/36e5),o=Math.floor(r/864e5);return s<1?"Just now":s<60?`${s}m ago`:a<24?`${a}h ago`:o<7?`${o}d ago`:t.toLocaleDateString(void 0,{month:"short",day:"numeric"})}function BenchmarkSessionCard({metadata:e,isSelected:t=!1,onPress:r,onLongPress:s,selectionMode:a=!1}){return(0,_jsxRuntime.jsxs)(_reactNative.TouchableOpacity,{onPress:r,onLongPress:s,style:[styles.card,t&&styles.cardSelected],activeOpacity:.7,children:[a&&(0,_jsxRuntime.jsx)(_reactNative.View,{style:[styles.checkbox,t&&styles.checkboxSelected],children:t&&(0,_jsxRuntime.jsx)(_sharedUi.Check,{size:12,color:"#fff"})}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.content,children:[(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.header,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.name,numberOfLines:1,children:e.name}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.date,children:formatDate(e.createdAt)})]}),e.description&&(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.description,numberOfLines:1,children:e.description}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.statsRow,children:[(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.stat,children:[(0,_jsxRuntime.jsx)(_sharedUi.Clock,{size:12,color:_sharedUi.macOSColors.text.secondary}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.statValue,children:formatDuration(e.duration)})]}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.stat,children:[(0,_jsxRuntime.jsx)(_sharedUi.Layers,{size:12,color:_sharedUi.macOSColors.text.secondary}),(0,_jsxRuntime.jsxs)(_reactNative.Text,{style:styles.statValue,children:[e.batchCount," batch",1!==e.batchCount?"es":""]})]}),(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.stat,children:(0,_jsxRuntime.jsx)(_sharedUi.Zap,{size:12,color:e.duration<1e4?_sharedUi.macOSColors.semantic.success:e.duration<3e4?_sharedUi.macOSColors.semantic.warning:_sharedUi.macOSColors.semantic.error})})]})]})]})}const styles=_reactNative.StyleSheet.create({card:{flexDirection:"row",alignItems:"center",backgroundColor:_sharedUi.macOSColors.background.card,borderRadius:8,padding:12,marginHorizontal:16,borderWidth:1,borderColor:_sharedUi.macOSColors.border.default},cardSelected:{borderColor:_sharedUi.macOSColors.semantic.info,backgroundColor:_sharedUi.macOSColors.semantic.infoBackground},checkbox:{width:20,height:20,borderRadius:4,borderWidth:1.5,borderColor:_sharedUi.macOSColors.border.hover,marginRight:12,alignItems:"center",justifyContent:"center"},checkboxSelected:{backgroundColor:_sharedUi.macOSColors.semantic.info,borderColor:_sharedUi.macOSColors.semantic.info},content:{flex:1},header:{flexDirection:"row",justifyContent:"space-between",alignItems:"center",marginBottom:4},name:{fontSize:14,fontWeight:"600",color:_sharedUi.macOSColors.text.primary,fontFamily:"monospace",flex:1,marginRight:8},date:{fontSize:11,color:_sharedUi.macOSColors.text.muted,fontFamily:"monospace"},description:{fontSize:12,color:_sharedUi.macOSColors.text.secondary,fontFamily:"monospace",marginBottom:8},statsRow:{flexDirection:"row",alignItems:"center",gap:16},stat:{flexDirection:"row",alignItems:"center",gap:4},statValue:{fontSize:11,color:_sharedUi.macOSColors.text.secondary,fontFamily:"monospace"}});var _default=exports.default=BenchmarkSessionCard;
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.BenchmarkSessionCard = BenchmarkSessionCard;
7
+ exports.default = void 0;
8
+ var _react = _interopRequireDefault(require("react"));
9
+ var _reactNative = require("react-native");
10
+ var _sharedUi = require("@buoy-gg/shared-ui");
11
+ var _jsxRuntime = require("react/jsx-runtime");
12
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
13
+ /**
14
+ * BenchmarkSessionCard
15
+ *
16
+ * Displays a single benchmark report as a card with key metrics.
17
+ * Shows name, duration, batch count, and timing stats.
18
+ * Supports selection for comparison.
19
+ */
20
+
21
+ /**
22
+ * Format duration in human-readable form
23
+ */
24
+ function formatDuration(ms) {
25
+ if (ms < 1000) {
26
+ return `${ms.toFixed(0)}ms`;
27
+ }
28
+ if (ms < 60000) {
29
+ return `${(ms / 1000).toFixed(1)}s`;
30
+ }
31
+ const minutes = Math.floor(ms / 60000);
32
+ const seconds = (ms % 60000 / 1000).toFixed(0);
33
+ return `${minutes}m ${seconds}s`;
34
+ }
35
+
36
+ /**
37
+ * Format date in compact form
38
+ */
39
+ function formatDate(timestamp) {
40
+ const date = new Date(timestamp);
41
+ const now = new Date();
42
+ const diffMs = now.getTime() - date.getTime();
43
+ const diffMins = Math.floor(diffMs / 60000);
44
+ const diffHours = Math.floor(diffMs / 3600000);
45
+ const diffDays = Math.floor(diffMs / 86400000);
46
+ if (diffMins < 1) return "Just now";
47
+ if (diffMins < 60) return `${diffMins}m ago`;
48
+ if (diffHours < 24) return `${diffHours}h ago`;
49
+ if (diffDays < 7) return `${diffDays}d ago`;
50
+ return date.toLocaleDateString(undefined, {
51
+ month: "short",
52
+ day: "numeric"
53
+ });
54
+ }
55
+ function BenchmarkSessionCard({
56
+ metadata,
57
+ isSelected = false,
58
+ onPress,
59
+ onLongPress,
60
+ selectionMode = false
61
+ }) {
62
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
63
+ onPress: onPress,
64
+ onLongPress: onLongPress,
65
+ style: [styles.card, isSelected && styles.cardSelected],
66
+ activeOpacity: 0.7,
67
+ children: [selectionMode && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
68
+ style: [styles.checkbox, isSelected && styles.checkboxSelected],
69
+ children: isSelected && /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Check, {
70
+ size: 12,
71
+ color: "#fff"
72
+ })
73
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
74
+ style: styles.content,
75
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
76
+ style: styles.header,
77
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
78
+ style: styles.name,
79
+ numberOfLines: 1,
80
+ children: metadata.name
81
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
82
+ style: styles.date,
83
+ children: formatDate(metadata.createdAt)
84
+ })]
85
+ }), metadata.description && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
86
+ style: styles.description,
87
+ numberOfLines: 1,
88
+ children: metadata.description
89
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
90
+ style: styles.statsRow,
91
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
92
+ style: styles.stat,
93
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Clock, {
94
+ size: 12,
95
+ color: _sharedUi.macOSColors.text.secondary
96
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
97
+ style: styles.statValue,
98
+ children: formatDuration(metadata.duration)
99
+ })]
100
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
101
+ style: styles.stat,
102
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Layers, {
103
+ size: 12,
104
+ color: _sharedUi.macOSColors.text.secondary
105
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Text, {
106
+ style: styles.statValue,
107
+ children: [metadata.batchCount, " batch", metadata.batchCount !== 1 ? "es" : ""]
108
+ })]
109
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
110
+ style: styles.stat,
111
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.Zap, {
112
+ size: 12,
113
+ color: metadata.duration < 10000 ? _sharedUi.macOSColors.semantic.success : metadata.duration < 30000 ? _sharedUi.macOSColors.semantic.warning : _sharedUi.macOSColors.semantic.error
114
+ })
115
+ })]
116
+ })]
117
+ })]
118
+ });
119
+ }
120
+ const styles = _reactNative.StyleSheet.create({
121
+ card: {
122
+ flexDirection: "row",
123
+ alignItems: "center",
124
+ backgroundColor: _sharedUi.macOSColors.background.card,
125
+ borderRadius: 8,
126
+ padding: 12,
127
+ marginHorizontal: 16,
128
+ borderWidth: 1,
129
+ borderColor: _sharedUi.macOSColors.border.default
130
+ },
131
+ cardSelected: {
132
+ borderColor: _sharedUi.macOSColors.semantic.info,
133
+ backgroundColor: _sharedUi.macOSColors.semantic.infoBackground
134
+ },
135
+ checkbox: {
136
+ width: 20,
137
+ height: 20,
138
+ borderRadius: 4,
139
+ borderWidth: 1.5,
140
+ borderColor: _sharedUi.macOSColors.border.hover,
141
+ marginRight: 12,
142
+ alignItems: "center",
143
+ justifyContent: "center"
144
+ },
145
+ checkboxSelected: {
146
+ backgroundColor: _sharedUi.macOSColors.semantic.info,
147
+ borderColor: _sharedUi.macOSColors.semantic.info
148
+ },
149
+ content: {
150
+ flex: 1
151
+ },
152
+ header: {
153
+ flexDirection: "row",
154
+ justifyContent: "space-between",
155
+ alignItems: "center",
156
+ marginBottom: 4
157
+ },
158
+ name: {
159
+ fontSize: 14,
160
+ fontWeight: "600",
161
+ color: _sharedUi.macOSColors.text.primary,
162
+ fontFamily: "monospace",
163
+ flex: 1,
164
+ marginRight: 8
165
+ },
166
+ date: {
167
+ fontSize: 11,
168
+ color: _sharedUi.macOSColors.text.muted,
169
+ fontFamily: "monospace"
170
+ },
171
+ description: {
172
+ fontSize: 12,
173
+ color: _sharedUi.macOSColors.text.secondary,
174
+ fontFamily: "monospace",
175
+ marginBottom: 8
176
+ },
177
+ statsRow: {
178
+ flexDirection: "row",
179
+ alignItems: "center",
180
+ gap: 16
181
+ },
182
+ stat: {
183
+ flexDirection: "row",
184
+ alignItems: "center",
185
+ gap: 4
186
+ },
187
+ statValue: {
188
+ fontSize: 11,
189
+ color: _sharedUi.macOSColors.text.secondary,
190
+ fontFamily: "monospace"
191
+ }
192
+ });
193
+ var _default = exports.default = BenchmarkSessionCard;
@@ -1 +1,62 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),Object.defineProperty(exports,"BenchmarkComparator",{enumerable:!0,get:function(){return _benchmarking.BenchmarkComparator}}),Object.defineProperty(exports,"BenchmarkModal",{enumerable:!0,get:function(){return _BenchmarkModal.BenchmarkModal}}),Object.defineProperty(exports,"BenchmarkRecorder",{enumerable:!0,get:function(){return _benchmarking.BenchmarkRecorder}}),Object.defineProperty(exports,"BenchmarkStorage",{enumerable:!0,get:function(){return _benchmarking.BenchmarkStorage}}),Object.defineProperty(exports,"benchmarkPreset",{enumerable:!0,get:function(){return _preset.benchmarkPreset}}),Object.defineProperty(exports,"benchmarkRecorder",{enumerable:!0,get:function(){return _benchmarking.benchmarkRecorder}}),Object.defineProperty(exports,"createAsyncStorageAdapter",{enumerable:!0,get:function(){return _benchmarking.createAsyncStorageAdapter}}),Object.defineProperty(exports,"createBenchmarkTool",{enumerable:!0,get:function(){return _preset.createBenchmarkTool}}),Object.defineProperty(exports,"createMemoryStorageAdapter",{enumerable:!0,get:function(){return _benchmarking.createMemoryStorageAdapter}});var _preset=require("./preset"),_benchmarking=require("./benchmarking"),_BenchmarkModal=require("./components/BenchmarkModal");
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ Object.defineProperty(exports, "BenchmarkComparator", {
7
+ enumerable: true,
8
+ get: function () {
9
+ return _benchmarking.BenchmarkComparator;
10
+ }
11
+ });
12
+ Object.defineProperty(exports, "BenchmarkModal", {
13
+ enumerable: true,
14
+ get: function () {
15
+ return _BenchmarkModal.BenchmarkModal;
16
+ }
17
+ });
18
+ Object.defineProperty(exports, "BenchmarkRecorder", {
19
+ enumerable: true,
20
+ get: function () {
21
+ return _benchmarking.BenchmarkRecorder;
22
+ }
23
+ });
24
+ Object.defineProperty(exports, "BenchmarkStorage", {
25
+ enumerable: true,
26
+ get: function () {
27
+ return _benchmarking.BenchmarkStorage;
28
+ }
29
+ });
30
+ Object.defineProperty(exports, "benchmarkPreset", {
31
+ enumerable: true,
32
+ get: function () {
33
+ return _preset.benchmarkPreset;
34
+ }
35
+ });
36
+ Object.defineProperty(exports, "benchmarkRecorder", {
37
+ enumerable: true,
38
+ get: function () {
39
+ return _benchmarking.benchmarkRecorder;
40
+ }
41
+ });
42
+ Object.defineProperty(exports, "createAsyncStorageAdapter", {
43
+ enumerable: true,
44
+ get: function () {
45
+ return _benchmarking.createAsyncStorageAdapter;
46
+ }
47
+ });
48
+ Object.defineProperty(exports, "createBenchmarkTool", {
49
+ enumerable: true,
50
+ get: function () {
51
+ return _preset.createBenchmarkTool;
52
+ }
53
+ });
54
+ Object.defineProperty(exports, "createMemoryStorageAdapter", {
55
+ enumerable: true,
56
+ get: function () {
57
+ return _benchmarking.createMemoryStorageAdapter;
58
+ }
59
+ });
60
+ var _preset = require("./preset");
61
+ var _benchmarking = require("./benchmarking");
62
+ var _BenchmarkModal = require("./components/BenchmarkModal");
@@ -1 +1,86 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.benchmarkPreset=void 0,exports.createBenchmarkTool=createBenchmarkTool;var _react=_interopRequireDefault(require("react")),_sharedUi=require("@buoy-gg/shared-ui"),_BenchmarkModal=require("./components/BenchmarkModal"),_jsxRuntime=require("react/jsx-runtime");function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e}}const benchmarkPreset=exports.benchmarkPreset={id:"benchmark",name:"BENCH",description:"Performance benchmarking",slot:"both",icon:({size:e})=>(0,_jsxRuntime.jsx)(_sharedUi.BenchmarkIcon,{size:e,color:"#F59E0B"}),component:_BenchmarkModal.BenchmarkModal,props:{enableSharedModalDimensions:!1}};function createBenchmarkTool(e){const r=e?.iconColor||"#F59E0B";return{id:e?.id||"benchmark",name:e?.name||"BENCH",description:e?.description||"Performance benchmarking",slot:"both",icon:({size:e})=>(0,_jsxRuntime.jsx)(_sharedUi.BenchmarkIcon,{size:e,color:r}),component:_BenchmarkModal.BenchmarkModal,props:{enableSharedModalDimensions:!0}}}
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.benchmarkPreset = void 0;
7
+ exports.createBenchmarkTool = createBenchmarkTool;
8
+ var _react = _interopRequireDefault(require("react"));
9
+ var _sharedUi = require("@buoy-gg/shared-ui");
10
+ var _BenchmarkModal = require("./components/BenchmarkModal");
11
+ var _jsxRuntime = require("react/jsx-runtime");
12
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
13
+ /**
14
+ * Pre-configured benchmark tool for FloatingDevTools
15
+ *
16
+ * This preset provides performance benchmarking functionality.
17
+ * Record, save, and compare performance metrics.
18
+ *
19
+ * @example
20
+ * ```tsx
21
+ * import { benchmarkPreset } from '@buoy-gg/benchmark';
22
+ *
23
+ * <FloatingDevTools apps={[benchmarkPreset]} />
24
+ * ```
25
+ */
26
+
27
+ /**
28
+ * Pre-configured benchmark tool for FloatingDevTools.
29
+ * Provides performance benchmarking with recording, saving, and comparison features.
30
+ *
31
+ * Features:
32
+ * - Start/Stop recording sessions
33
+ * - View saved benchmark reports
34
+ * - Compare two benchmarks side-by-side
35
+ * - Delete individual or all benchmarks
36
+ */
37
+ const benchmarkPreset = exports.benchmarkPreset = {
38
+ id: "benchmark",
39
+ name: "BENCH",
40
+ description: "Performance benchmarking",
41
+ slot: "both",
42
+ icon: ({
43
+ size
44
+ }) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.BenchmarkIcon, {
45
+ size: size,
46
+ color: "#F59E0B"
47
+ }),
48
+ component: _BenchmarkModal.BenchmarkModal,
49
+ props: {
50
+ enableSharedModalDimensions: false
51
+ }
52
+ };
53
+
54
+ /**
55
+ * Create a custom benchmark tool configuration.
56
+ * Use this if you want to override default settings.
57
+ *
58
+ * @example
59
+ * ```tsx
60
+ * import { createBenchmarkTool } from '@buoy-gg/benchmark';
61
+ *
62
+ * const myBenchmarkTool = createBenchmarkTool({
63
+ * name: "PERF",
64
+ * iconColor: "#059669",
65
+ * });
66
+ * ```
67
+ */
68
+ function createBenchmarkTool(options) {
69
+ const iconColor = options?.iconColor || "#F59E0B";
70
+ return {
71
+ id: options?.id || "benchmark",
72
+ name: options?.name || "BENCH",
73
+ description: options?.description || "Performance benchmarking",
74
+ slot: "both",
75
+ icon: ({
76
+ size
77
+ }) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.BenchmarkIcon, {
78
+ size: size,
79
+ color: iconColor
80
+ }),
81
+ component: _BenchmarkModal.BenchmarkModal,
82
+ props: {
83
+ enableSharedModalDimensions: true
84
+ }
85
+ };
86
+ }
@@ -1 +1,216 @@
1
- "use strict";function calculateImprovement(e,t){return 0===e?0:(e-t)/e*100}function formatPercent(e){return`${e>=0?"+":""}${e.toFixed(1)}%`}function formatMs(e){return`${e.toFixed(1)}ms`}function formatBytes(e){const t=e/1024/1024;return`${t>=0?"+":""}${t.toFixed(2)}MB`}function getIndicator(e,t=5){return e>t?"✅":e<-t?"❌":"➖"}export class BenchmarkComparator{static compare(e,t){const a=e.stats,r=t.stats,m=t.duration-e.duration,o=calculateImprovement(e.duration,t.duration),n=calculateImprovement(a.avgFilterTime,r.avgFilterTime),s=calculateImprovement(a.avgMeasureTime,r.avgMeasureTime),i=calculateImprovement(a.avgTrackTime,r.avgTrackTime),l=calculateImprovement(a.avgTotalTime,r.avgTotalTime),p=calculateImprovement(a.avgOverlayRenderTime,r.avgOverlayRenderTime);let u=null;null!=e.memoryDelta&&null!=t.memoryDelta&&(u=t.memoryDelta-e.memoryDelta);let c=.4*s+.3*l+.2*p;null!=e.memoryDelta&&null!=t.memoryDelta&&0!==e.memoryDelta&&(c+=.1*calculateImprovement(e.memoryDelta,t.memoryDelta));const d=c>0,v=this.generateSummary({baseline:e,comparison:t,durationDelta:m,durationImprovement:o,measureTimeImprovement:s,pipelineTimeImprovement:l,overlayRenderImprovement:p,memoryDeltaChange:u,overallImprovement:c,isImproved:d});return{baselineId:e.id,baselineName:e.name,comparisonId:t.id,comparisonName:t.name,comparedAt:Date.now(),durationDelta:m,durationImprovement:o,filterTimeImprovement:n,measureTimeImprovement:s,trackTimeImprovement:i,pipelineTimeImprovement:l,overlayRenderImprovement:p,memoryDeltaChange:u,overallImprovement:c,isImproved:d,summary:v}}static generateSummary(e){const{baseline:t,comparison:a,measureTimeImprovement:r,pipelineTimeImprovement:m,overlayRenderImprovement:o,memoryDeltaChange:n,overallImprovement:s,isImproved:i}=e,l=[];if(l.push("╔══════════════════════════════════════════════════════════════╗"),l.push("║ BENCHMARK COMPARISON ║"),l.push("╠══════════════════════════════════════════════════════════════╣"),l.push(`║ Baseline: ${t.name.substring(0,50).padEnd(50)} ║`),l.push(`║ ${new Date(t.createdAt).toLocaleString().substring(0,58).padEnd(58)} ║`),l.push(`║ Comparison: ${a.name.substring(0,48).padEnd(48)} ║`),l.push(`║ ${new Date(a.createdAt).toLocaleString().substring(0,58).padEnd(58)} ║`),l.push("╠══════════════════════════════════════════════════════════════╣"),l.push("║ TIMING COMPARISON ║"),l.push("║ Baseline After Change ║"),l.push(`║ Measurement Time: ${formatMs(t.stats.avgMeasureTime).padStart(8)} → ${formatMs(a.stats.avgMeasureTime).padStart(8)} ${formatPercent(r).padStart(7)} ${getIndicator(r)} ║`),l.push(`║ Pipeline Time: ${formatMs(t.stats.avgTotalTime).padStart(8)} → ${formatMs(a.stats.avgTotalTime).padStart(8)} ${formatPercent(m).padStart(7)} ${getIndicator(m)} ║`),l.push(`║ Overlay Render: ${formatMs(t.stats.avgOverlayRenderTime).padStart(8)} → ${formatMs(a.stats.avgOverlayRenderTime).padStart(8)} ${formatPercent(o).padStart(7)} ${getIndicator(o)} ║`),null!=n&&null!=t.memoryDelta&&null!=a.memoryDelta){const e=calculateImprovement(t.memoryDelta,a.memoryDelta);l.push("╠══════════════════════════════════════════════════════════════╣"),l.push("║ MEMORY ║"),l.push(`║ Delta: ${formatBytes(t.memoryDelta).padStart(8)} → ${formatBytes(a.memoryDelta).padStart(8)} ${formatPercent(e).padStart(7)} ${getIndicator(e)} ║`)}l.push("╠══════════════════════════════════════════════════════════════╣"),l.push("║ PERCENTILES (P95) ║");const p=calculateImprovement(t.stats.p95TotalTime,a.stats.p95TotalTime);l.push(`║ P95 Pipeline: ${formatMs(t.stats.p95TotalTime).padStart(8)} → ${formatMs(a.stats.p95TotalTime).padStart(8)} ${formatPercent(p).padStart(7)} ${getIndicator(p)} ║`),l.push("╠══════════════════════════════════════════════════════════════╣");const u=i?"🎉":"⚠️",c=i?"IMPROVED":"REGRESSED";return l.push(`║ ${u} OVERALL: ${formatPercent(s).padStart(7)} ${c.padEnd(40)} ║`),l.push("╚══════════════════════════════════════════════════════════════╝"),l.join("\n")}static logComparison(e){console.log("\n"+e.summary+"\n")}static quickCompare(e,t){const a=this.compare(e,t);return this.logComparison(a),a}static getBriefSummary(e){const t=e.isImproved?"faster":"slower";return`${e.isImproved?"✅":"❌"} ${Math.abs(e.overallImprovement).toFixed(1)}% ${t} (measurement: ${formatPercent(e.measureTimeImprovement)}, pipeline: ${formatPercent(e.pipelineTimeImprovement)})`}}export default BenchmarkComparator;
1
+ /**
2
+ * BenchmarkComparator
3
+ *
4
+ * Compares two benchmark reports and generates a detailed comparison result.
5
+ * Calculates improvements/regressions across all metrics and provides
6
+ * human-readable summaries.
7
+ *
8
+ * Usage:
9
+ * const comparison = BenchmarkComparator.compare(baselineReport, comparisonReport);
10
+ * console.log(comparison.summary);
11
+ * console.log(`Overall improvement: ${comparison.overallImprovement.toFixed(1)}%`);
12
+ *
13
+ * @packageDocumentation
14
+ */
15
+
16
+ "use strict";
17
+
18
+ /**
19
+ * Calculate percentage improvement (positive = better)
20
+ * @param baseline - The baseline value
21
+ * @param comparison - The comparison value
22
+ * @returns Percentage improvement (positive = faster/better, negative = slower/worse)
23
+ */
24
+ function calculateImprovement(baseline, comparison) {
25
+ if (baseline === 0) return 0;
26
+ return (baseline - comparison) / baseline * 100;
27
+ }
28
+
29
+ /**
30
+ * Format a percentage with sign
31
+ */
32
+ function formatPercent(value) {
33
+ const sign = value >= 0 ? "+" : "";
34
+ return `${sign}${value.toFixed(1)}%`;
35
+ }
36
+
37
+ /**
38
+ * Format milliseconds
39
+ */
40
+ function formatMs(value) {
41
+ return `${value.toFixed(1)}ms`;
42
+ }
43
+
44
+ /**
45
+ * Format bytes as MB
46
+ */
47
+ function formatBytes(bytes) {
48
+ const mb = bytes / 1024 / 1024;
49
+ const sign = mb >= 0 ? "+" : "";
50
+ return `${sign}${mb.toFixed(2)}MB`;
51
+ }
52
+
53
+ /**
54
+ * Get an emoji indicator for improvement
55
+ */
56
+ function getIndicator(improvement, threshold = 5) {
57
+ if (improvement > threshold) return "✅";
58
+ if (improvement < -threshold) return "❌";
59
+ return "➖";
60
+ }
61
+
62
+ /**
63
+ * BenchmarkComparator - Compares two benchmark reports
64
+ */
65
+ export class BenchmarkComparator {
66
+ /**
67
+ * Compare two benchmark reports
68
+ * @param baseline - The baseline (before) report
69
+ * @param comparison - The comparison (after) report
70
+ * @returns Detailed comparison result
71
+ */
72
+ static compare(baseline, comparison) {
73
+ const baselineStats = baseline.stats;
74
+ const comparisonStats = comparison.stats;
75
+
76
+ // Duration changes
77
+ const durationDelta = comparison.duration - baseline.duration;
78
+ const durationImprovement = calculateImprovement(baseline.duration, comparison.duration);
79
+
80
+ // Pipeline timing improvements
81
+ const filterTimeImprovement = calculateImprovement(baselineStats.avgFilterTime, comparisonStats.avgFilterTime);
82
+ const measureTimeImprovement = calculateImprovement(baselineStats.avgMeasureTime, comparisonStats.avgMeasureTime);
83
+ const trackTimeImprovement = calculateImprovement(baselineStats.avgTrackTime, comparisonStats.avgTrackTime);
84
+ const pipelineTimeImprovement = calculateImprovement(baselineStats.avgTotalTime, comparisonStats.avgTotalTime);
85
+
86
+ // Overlay render improvement
87
+ const overlayRenderImprovement = calculateImprovement(baselineStats.avgOverlayRenderTime, comparisonStats.avgOverlayRenderTime);
88
+
89
+ // Memory changes
90
+ let memoryDeltaChange = null;
91
+ if (baseline.memoryDelta != null && comparison.memoryDelta != null) {
92
+ memoryDeltaChange = comparison.memoryDelta - baseline.memoryDelta;
93
+ }
94
+
95
+ // Overall improvement (weighted average of key metrics)
96
+ // Weights: measurement time (40%), pipeline time (30%), overlay render (20%), memory (10%)
97
+ const weights = {
98
+ measure: 0.4,
99
+ pipeline: 0.3,
100
+ overlay: 0.2,
101
+ memory: 0.1
102
+ };
103
+ let overallImprovement = measureTimeImprovement * weights.measure + pipelineTimeImprovement * weights.pipeline + overlayRenderImprovement * weights.overlay;
104
+
105
+ // Add memory improvement if available
106
+ if (baseline.memoryDelta != null && comparison.memoryDelta != null && baseline.memoryDelta !== 0) {
107
+ const memoryImprovement = calculateImprovement(baseline.memoryDelta, comparison.memoryDelta);
108
+ overallImprovement += memoryImprovement * weights.memory;
109
+ }
110
+ const isImproved = overallImprovement > 0;
111
+
112
+ // Generate summary
113
+ const summary = this.generateSummary({
114
+ baseline,
115
+ comparison,
116
+ durationDelta,
117
+ durationImprovement,
118
+ measureTimeImprovement,
119
+ pipelineTimeImprovement,
120
+ overlayRenderImprovement,
121
+ memoryDeltaChange,
122
+ overallImprovement,
123
+ isImproved
124
+ });
125
+ return {
126
+ baselineId: baseline.id,
127
+ baselineName: baseline.name,
128
+ comparisonId: comparison.id,
129
+ comparisonName: comparison.name,
130
+ comparedAt: Date.now(),
131
+ durationDelta,
132
+ durationImprovement,
133
+ filterTimeImprovement,
134
+ measureTimeImprovement,
135
+ trackTimeImprovement,
136
+ pipelineTimeImprovement,
137
+ overlayRenderImprovement,
138
+ memoryDeltaChange,
139
+ overallImprovement,
140
+ isImproved,
141
+ summary
142
+ };
143
+ }
144
+
145
+ /**
146
+ * Generate a human-readable summary
147
+ */
148
+ static generateSummary(data) {
149
+ const {
150
+ baseline,
151
+ comparison,
152
+ measureTimeImprovement,
153
+ pipelineTimeImprovement,
154
+ overlayRenderImprovement,
155
+ memoryDeltaChange,
156
+ overallImprovement,
157
+ isImproved
158
+ } = data;
159
+ const lines = [];
160
+ lines.push("╔══════════════════════════════════════════════════════════════╗");
161
+ lines.push("║ BENCHMARK COMPARISON ║");
162
+ lines.push("╠══════════════════════════════════════════════════════════════╣");
163
+ lines.push(`║ Baseline: ${baseline.name.substring(0, 50).padEnd(50)} ║`);
164
+ lines.push(`║ ${new Date(baseline.createdAt).toLocaleString().substring(0, 58).padEnd(58)} ║`);
165
+ lines.push(`║ Comparison: ${comparison.name.substring(0, 48).padEnd(48)} ║`);
166
+ lines.push(`║ ${new Date(comparison.createdAt).toLocaleString().substring(0, 58).padEnd(58)} ║`);
167
+ lines.push("╠══════════════════════════════════════════════════════════════╣");
168
+ lines.push("║ TIMING COMPARISON ║");
169
+ lines.push("║ Baseline After Change ║");
170
+ lines.push(`║ Measurement Time: ${formatMs(baseline.stats.avgMeasureTime).padStart(8)} → ` + `${formatMs(comparison.stats.avgMeasureTime).padStart(8)} ` + `${formatPercent(measureTimeImprovement).padStart(7)} ${getIndicator(measureTimeImprovement)} ║`);
171
+ lines.push(`║ Pipeline Time: ${formatMs(baseline.stats.avgTotalTime).padStart(8)} → ` + `${formatMs(comparison.stats.avgTotalTime).padStart(8)} ` + `${formatPercent(pipelineTimeImprovement).padStart(7)} ${getIndicator(pipelineTimeImprovement)} ║`);
172
+ lines.push(`║ Overlay Render: ${formatMs(baseline.stats.avgOverlayRenderTime).padStart(8)} → ` + `${formatMs(comparison.stats.avgOverlayRenderTime).padStart(8)} ` + `${formatPercent(overlayRenderImprovement).padStart(7)} ${getIndicator(overlayRenderImprovement)} ║`);
173
+ if (memoryDeltaChange != null && baseline.memoryDelta != null && comparison.memoryDelta != null) {
174
+ const memoryImprovement = calculateImprovement(baseline.memoryDelta, comparison.memoryDelta);
175
+ lines.push("╠══════════════════════════════════════════════════════════════╣");
176
+ lines.push("║ MEMORY ║");
177
+ lines.push(`║ Delta: ${formatBytes(baseline.memoryDelta).padStart(8)} → ` + `${formatBytes(comparison.memoryDelta).padStart(8)} ` + `${formatPercent(memoryImprovement).padStart(7)} ${getIndicator(memoryImprovement)} ║`);
178
+ }
179
+ lines.push("╠══════════════════════════════════════════════════════════════╣");
180
+ lines.push("║ PERCENTILES (P95) ║");
181
+ const p95Improvement = calculateImprovement(baseline.stats.p95TotalTime, comparison.stats.p95TotalTime);
182
+ lines.push(`║ P95 Pipeline: ${formatMs(baseline.stats.p95TotalTime).padStart(8)} → ` + `${formatMs(comparison.stats.p95TotalTime).padStart(8)} ` + `${formatPercent(p95Improvement).padStart(7)} ${getIndicator(p95Improvement)} ║`);
183
+ lines.push("╠══════════════════════════════════════════════════════════════╣");
184
+ const resultEmoji = isImproved ? "🎉" : "⚠️";
185
+ const resultText = isImproved ? "IMPROVED" : "REGRESSED";
186
+ lines.push(`║ ${resultEmoji} OVERALL: ${formatPercent(overallImprovement).padStart(7)} ${resultText.padEnd(40)} ║`);
187
+ lines.push("╚══════════════════════════════════════════════════════════════╝");
188
+ return lines.join("\n");
189
+ }
190
+
191
+ /**
192
+ * Log a comparison to the console
193
+ */
194
+ static logComparison(comparison) {
195
+ console.log("\n" + comparison.summary + "\n");
196
+ }
197
+
198
+ /**
199
+ * Quick compare: compare baseline vs comparison and log results
200
+ */
201
+ static quickCompare(baseline, comparison) {
202
+ const result = this.compare(baseline, comparison);
203
+ this.logComparison(result);
204
+ return result;
205
+ }
206
+
207
+ /**
208
+ * Generate a brief one-line summary
209
+ */
210
+ static getBriefSummary(comparison) {
211
+ const direction = comparison.isImproved ? "faster" : "slower";
212
+ const emoji = comparison.isImproved ? "✅" : "❌";
213
+ return `${emoji} ${Math.abs(comparison.overallImprovement).toFixed(1)}% ${direction} (measurement: ${formatPercent(comparison.measureTimeImprovement)}, pipeline: ${formatPercent(comparison.pipelineTimeImprovement)})`;
214
+ }
215
+ }
216
+ export default BenchmarkComparator;