Benchmark Budgets
This page summarizes the 115 p99 performance budgets in scripts/bench-budgets.json. CI runs scripts/check-bench-budget.mjs after pnpm bench; any unregistered bench or over-budget bench fails the check.
File Locations
| Path | Role |
|---|---|
scripts/bench-budgets.json | Budget table, the single CI data source |
scripts/check-bench-budget.mjs | Fail-closed guard script |
bench-results.json | Scratch output from pnpm bench --outputJson bench-results.json |
Current Budgets
{
"10-point polyline, 3.5m offset": {
"p99Ms": 1
},
"100-point polyline, 3.5m offset": {
"p99Ms": 3
},
"1000-point polyline, 3.5m offset": {
"p99Ms": 40
},
"full stitch — 10-lane linear chain": {
"p99Ms": 3
},
"full stitch — 100-lane linear chain": {
"p99Ms": 6
},
"full stitch — 100 lanes / 50 isolated junctions": {
"p99Ms": 6
},
"incremental — 100-lane chain, 1 lane decorated": {
"p99Ms": 5
},
"incremental — 100-lane chain, 3 lanes decorated": {
"p99Ms": 5
},
"topology 100 lanes — full reconcile": {
"p99Ms": 2
},
"topology 100 lanes — incremental (1 dirty lane)": {
"p99Ms": 1
},
"topology 500 lanes — full reconcile": {
"p99Ms": 5
},
"topology 500 lanes — incremental (1 dirty lane)": {
"p99Ms": 2
},
"topology 1000 lanes — full reconcile": {
"p99Ms": 10
},
"topology 1000 lanes — incremental (1 dirty lane)": {
"p99Ms": 4
},
"overlap 5k — full mode (cold)": {
"p99Ms": 25
},
"overlap 5k — incremental (1 dirty lane, warm index)": {
"p99Ms": 0.5
},
"overlap 5k — incremental (1 dirty crosswalk, warm index)": {
"p99Ms": 0.5
},
"overlap 5k — syncDirty (1 dirty)": {
"p99Ms": 0.05
},
"overlap 10k — full mode (cold)": {
"p99Ms": 50
},
"overlap 10k — incremental (1 dirty lane, warm index)": {
"p99Ms": 0.5
},
"overlap 10k — incremental (1 dirty crosswalk, warm index)": {
"p99Ms": 0.5
},
"overlap 10k — syncDirty (1 dirty)": {
"p99Ms": 0.05
},
"overlap 25k — full mode (cold)": {
"p99Ms": 150
},
"overlap 25k — incremental (1 dirty lane, warm index)": {
"p99Ms": 0.5
},
"overlap 25k — incremental (1 dirty crosswalk, warm index)": {
"p99Ms": 0.5
},
"overlap 25k — syncDirty (1 dirty)": {
"p99Ms": 0.05
},
"snap 1k entities — find target": {
"p99Ms": 0.8
},
"snap 5k entities — find target": {
"p99Ms": 2.5
},
"snap 10k entities — find target": {
"p99Ms": 6
},
"snap applySnap 1k entities — editingPoint": {
"p99Ms": 0.8
},
"snap applySnap 5k entities — editingPoint": {
"p99Ms": 4
},
"hitTest polyline 1000 segments — distance": {
"p99Ms": 0.1
},
"hitTest polyline 5000 segments — distance": {
"p99Ms": 0.25
},
"hitTest polygon 1000 vertices — distance": {
"p99Ms": 0.1
},
"hitTest polygon 5000 vertices — distance": {
"p99Ms": 0.4
},
"boundary brush 1k lanes — find paint hit": {
"p99Ms": 4
},
"boundary brush 5k lanes — find paint hit": {
"p99Ms": 16
},
"boundary brush 100 pts — paint lane type": {
"p99Ms": 0.1
},
"boundary brush 1000 pts — paint lane type": {
"p99Ms": 0.5
},
"validation 100 vertices — append edge": {
"p99Ms": 0.01
},
"validation 100 vertices — full self-intersection": {
"p99Ms": 0.1
},
"validation 500 vertices — append edge": {
"p99Ms": 0.01
},
"validation 500 vertices — full self-intersection": {
"p99Ms": 0.8
},
"validation 1000 vertices — append edge": {
"p99Ms": 0.01
},
"validation 1000 vertices — full self-intersection": {
"p99Ms": 3
},
"spatial 1k — syncEntities": {
"p99Ms": 60
},
"spatial 1k — buildFeatureCollection full": {
"p99Ms": 10
},
"spatial 1k — buildFeatureCollection incremental 1 lane": {
"p99Ms": 6
},
"spatial 1k — featureGroupsForState": {
"p99Ms": 1
},
"spatial 1k — HIT_TEST dense query": {
"p99Ms": 1
},
"spatial 1k — INCREMENTAL request 1 dirty lane": {
"p99Ms": 5
},
"spatial 5k — syncEntities": {
"p99Ms": 80
},
"spatial 5k — buildFeatureCollection full": {
"p99Ms": 50
},
"spatial 5k — buildFeatureCollection incremental 1 lane": {
"p99Ms": 30
},
"spatial 5k — featureGroupsForState": {
"p99Ms": 10
},
"spatial 5k — HIT_TEST dense query": {
"p99Ms": 10
},
"spatial 5k — INCREMENTAL request 1 dirty lane": {
"p99Ms": 60
},
"cold layer 5k — groupsToFeatureMap": {
"p99Ms": 0.6
},
"cold layer 5k — flattenEntityFeatures": {
"p99Ms": 1
},
"cold layer 5k — diffEntities one update one remove": {
"p99Ms": 0.5
},
"cold source 5k — rebuild from cache": {
"p99Ms": 1.2
},
"cold source 5k — apply delta 100 changed": {
"p99Ms": 0.05
},
"cold layer 25k — groupsToFeatureMap": {
"p99Ms": 6
},
"cold layer 25k — flattenEntityFeatures": {
"p99Ms": 5
},
"cold layer 25k — diffEntities one update one remove": {
"p99Ms": 3
},
"cold source 25k — rebuild from cache": {
"p99Ms": 4
},
"cold source 25k — apply delta 100 changed": {
"p99Ms": 0.05
},
"hot layer lane 100 pts — entityToHotFeatures": {
"p99Ms": 0.05
},
"hot layer lane 100 pts — applyDrag and features": {
"p99Ms": 0.1
},
"hot layer lane 1000 pts — entityToHotFeatures": {
"p99Ms": 0.15
},
"hot layer lane 1000 pts — applyDrag and features": {
"p99Ms": 1.5
},
"hot layer lane 5000 pts — entityToHotFeatures": {
"p99Ms": 1.5
},
"hot layer lane 5000 pts — applyDrag and features": {
"p99Ms": 2
},
"overlay polyline 100 pts — buildOverlayFeatures": {
"p99Ms": 0.05
},
"overlay catmull 100 pts — buildOverlayFeatures": {
"p99Ms": 0.8
},
"overlay bezier 100 anchors — buildOverlayFeatures": {
"p99Ms": 0.3
},
"overlay polyline 1000 pts — buildOverlayFeatures": {
"p99Ms": 0.5
},
"overlay catmull 1000 pts — buildOverlayFeatures": {
"p99Ms": 8
},
"overlay bezier 1000 anchors — buildOverlayFeatures": {
"p99Ms": 4
},
"grid max-density viewport — buildGrid": {
"p99Ms": 0.05
},
"panel 10k — build layer tree": {
"p99Ms": 1
},
"panel 10k — compute outline stats": {
"p99Ms": 0.5
},
"panel 10k — search miss scan": {
"p99Ms": 0.5
},
"panel 50k — build layer tree": {
"p99Ms": 8
},
"panel 50k — compute outline stats": {
"p99Ms": 6
},
"panel 50k — search miss scan": {
"p99Ms": 4
},
"entityOps 10k — cascadeDeleteRefsFull one lane": {
"p99Ms": 3
},
"entityOps 10k — cascadeDeleteRefsFull 100 lanes": {
"p99Ms": 4
},
"entityOps 10k — reparent lane to road section": {
"p99Ms": 0.5
},
"entityOps 50k — cascadeDeleteRefsFull one lane": {
"p99Ms": 20
},
"entityOps 50k — cascadeDeleteRefsFull 100 lanes": {
"p99Ms": 25
},
"entityOps 50k — reparent lane to road section": {
"p99Ms": 2
},
"mapStore 10k — update lane transaction": {
"p99Ms": 90
},
"mapStore 10k — remove lane transaction": {
"p99Ms": 70
},
"mapStore 10k — batchImport transaction": {
"p99Ms": 90
},
"mapStore 25k — update lane transaction": {
"p99Ms": 130
},
"mapStore 25k — remove lane transaction": {
"p99Ms": 120
},
"mapStore 25k — batchImport transaction": {
"p99Ms": 240
},
"chunking 10k entities — slice 2k chunks": {
"p99Ms": 0.05
},
"chunking 50k entities — slice 2k chunks": {
"p99Ms": 0.1
},
"proto bridge 1k — apolloMapToEntities": {
"p99Ms": 5
},
"proto bridge 1k — entitiesToApolloMap": {
"p99Ms": 3
},
"proto bounds 1k — computeApolloMapBounds": {
"p99Ms": 0.5
},
"proto projection 1k — to lonlat": {
"p99Ms": 45
},
"proto projection 1k — from lonlat": {
"p99Ms": 60
},
"proto bridge 5k — apolloMapToEntities": {
"p99Ms": 12
},
"proto bridge 5k — entitiesToApolloMap": {
"p99Ms": 16
},
"proto bounds 5k — computeApolloMapBounds": {
"p99Ms": 2
},
"proto projection 5k — to lonlat": {
"p99Ms": 150
},
"proto projection 5k — from lonlat": {
"p99Ms": 150
},
"proto bin 1k lanes — encode": {
"p99Ms": 30
},
"proto bin 1k lanes — decode": {
"p99Ms": 16
},
"proto text 100 lanes — encode": {
"p99Ms": 12
},
"proto text 100 lanes — decode": {
"p99Ms": 8
},
"proto roundtrip 1k lanes — bridge project encode": {
"p99Ms": 60
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
Bench Groups
offset polyline geometry
| Bench | File | p99 ceiling | Guarded path |
|---|---|---|---|
10-point polyline, 3.5m offset | src/core/geometry/__tests__/offsetPolyline.bench.ts | 1 ms | polyline offset used by lane polygon and boundary rendering |
100-point polyline, 3.5m offset | src/core/geometry/__tests__/offsetPolyline.bench.ts | 3 ms | polyline offset used by lane polygon and boundary rendering |
1000-point polyline, 3.5m offset | src/core/geometry/__tests__/offsetPolyline.bench.ts | 40 ms | polyline offset used by lane polygon and boundary rendering |
lane junction derivation
| Bench | File | p99 ceiling | Guarded path |
|---|---|---|---|
full stitch — 10-lane linear chain | src/core/geometry/__tests__/laneJunctions.bench.ts | 3 ms | lane junction stitching and incremental boundary decoration |
full stitch — 100-lane linear chain | src/core/geometry/__tests__/laneJunctions.bench.ts | 6 ms | lane junction stitching and incremental boundary decoration |
full stitch — 100 lanes / 50 isolated junctions | src/core/geometry/__tests__/laneJunctions.bench.ts | 6 ms | lane junction stitching and incremental boundary decoration |
incremental — 100-lane chain, 1 lane decorated | src/core/geometry/__tests__/laneJunctions.bench.ts | 5 ms | lane junction stitching and incremental boundary decoration |
incremental — 100-lane chain, 3 lanes decorated | src/core/geometry/__tests__/laneJunctions.bench.ts | 5 ms | lane junction stitching and incremental boundary decoration |
lane topology reconcile
| Bench | File | p99 ceiling | Guarded path |
|---|---|---|---|
topology 100 lanes — full reconcile | src/core/geometry/__tests__/laneTopology.bench.ts | 2 ms | pred/succ/neighbor/junction topology derivation |
topology 100 lanes — incremental (1 dirty lane) | src/core/geometry/__tests__/laneTopology.bench.ts | 1 ms | pred/succ/neighbor/junction topology derivation |
topology 500 lanes — full reconcile | src/core/geometry/__tests__/laneTopology.bench.ts | 5 ms | pred/succ/neighbor/junction topology derivation |
topology 500 lanes — incremental (1 dirty lane) | src/core/geometry/__tests__/laneTopology.bench.ts | 2 ms | pred/succ/neighbor/junction topology derivation |
topology 1000 lanes — full reconcile | src/core/geometry/__tests__/laneTopology.bench.ts | 10 ms | pred/succ/neighbor/junction topology derivation |
topology 1000 lanes — incremental (1 dirty lane) | src/core/geometry/__tests__/laneTopology.bench.ts | 4 ms | pred/succ/neighbor/junction topology derivation |
overlap reconcile and spatial index
| Bench | File | p99 ceiling | Guarded path |
|---|---|---|---|
overlap 5k — full mode (cold) | src/core/elements/overlap/__tests__/overlap.bench.ts | 25 ms | full and dirty overlap reconciliation plus index maintenance |
overlap 5k — incremental (1 dirty lane, warm index) | src/core/elements/overlap/__tests__/overlap.bench.ts | 0.5 ms | full and dirty overlap reconciliation plus index maintenance |
overlap 5k — incremental (1 dirty crosswalk, warm index) | src/core/elements/overlap/__tests__/overlap.bench.ts | 0.5 ms | full and dirty overlap reconciliation plus index maintenance |
overlap 5k — syncDirty (1 dirty) | src/core/elements/overlap/__tests__/overlap.bench.ts | 0.05 ms | full and dirty overlap reconciliation plus index maintenance |
overlap 10k — full mode (cold) | src/core/elements/overlap/__tests__/overlap.bench.ts | 50 ms | full and dirty overlap reconciliation plus index maintenance |
overlap 10k — incremental (1 dirty lane, warm index) | src/core/elements/overlap/__tests__/overlap.bench.ts | 0.5 ms | full and dirty overlap reconciliation plus index maintenance |
overlap 10k — incremental (1 dirty crosswalk, warm index) | src/core/elements/overlap/__tests__/overlap.bench.ts | 0.5 ms | full and dirty overlap reconciliation plus index maintenance |
overlap 10k — syncDirty (1 dirty) | src/core/elements/overlap/__tests__/overlap.bench.ts | 0.05 ms | full and dirty overlap reconciliation plus index maintenance |
overlap 25k — full mode (cold) | src/core/elements/overlap/__tests__/overlap.bench.ts | 150 ms | full and dirty overlap reconciliation plus index maintenance |
overlap 25k — incremental (1 dirty lane, warm index) | src/core/elements/overlap/__tests__/overlap.bench.ts | 0.5 ms | full and dirty overlap reconciliation plus index maintenance |
overlap 25k — incremental (1 dirty crosswalk, warm index) | src/core/elements/overlap/__tests__/overlap.bench.ts | 0.5 ms | full and dirty overlap reconciliation plus index maintenance |
overlap 25k — syncDirty (1 dirty) | src/core/elements/overlap/__tests__/overlap.bench.ts | 0.05 ms | full and dirty overlap reconciliation plus index maintenance |
interaction geometry and snap integration
| Bench | File | p99 ceiling | Guarded path |
|---|---|---|---|
snap 1k entities — find target | src/core/geometry/__tests__/interactionGeometry.bench.ts / src/hooks/__tests__/snapIntegration.bench.ts | 0.8 ms | mousemove snap scan over visible entities |
snap 5k entities — find target | src/core/geometry/__tests__/interactionGeometry.bench.ts / src/hooks/__tests__/snapIntegration.bench.ts | 2.5 ms | mousemove snap scan over visible entities |
snap 10k entities — find target | src/core/geometry/__tests__/interactionGeometry.bench.ts / src/hooks/__tests__/snapIntegration.bench.ts | 6 ms | mousemove snap scan over visible entities |
snap applySnap 1k entities — editingPoint | src/core/geometry/__tests__/interactionGeometry.bench.ts / src/hooks/__tests__/snapIntegration.bench.ts | 0.8 ms | mousemove snap integration through map, UI store, and entity store |
snap applySnap 5k entities — editingPoint | src/core/geometry/__tests__/interactionGeometry.bench.ts / src/hooks/__tests__/snapIntegration.bench.ts | 4 ms | mousemove snap integration through map, UI store, and entity store |
hitTest polyline 1000 segments — distance | src/core/geometry/__tests__/interactionGeometry.bench.ts / src/hooks/__tests__/snapIntegration.bench.ts | 0.1 ms | worker hit-test distance primitives |
hitTest polyline 5000 segments — distance | src/core/geometry/__tests__/interactionGeometry.bench.ts / src/hooks/__tests__/snapIntegration.bench.ts | 0.25 ms | worker hit-test distance primitives |
hitTest polygon 1000 vertices — distance | src/core/geometry/__tests__/interactionGeometry.bench.ts / src/hooks/__tests__/snapIntegration.bench.ts | 0.1 ms | worker hit-test distance primitives |
hitTest polygon 5000 vertices — distance | src/core/geometry/__tests__/interactionGeometry.bench.ts / src/hooks/__tests__/snapIntegration.bench.ts | 0.4 ms | worker hit-test distance primitives |
validation 100 vertices — append edge | src/core/geometry/__tests__/interactionGeometry.bench.ts / src/hooks/__tests__/snapIntegration.bench.ts | 0.01 ms | polygon self-intersection checks in draw/edit flows |
validation 100 vertices — full self-intersection | src/core/geometry/__tests__/interactionGeometry.bench.ts / src/hooks/__tests__/snapIntegration.bench.ts | 0.1 ms | polygon self-intersection checks in draw/edit flows |
validation 500 vertices — append edge | src/core/geometry/__tests__/interactionGeometry.bench.ts / src/hooks/__tests__/snapIntegration.bench.ts | 0.01 ms | polygon self-intersection checks in draw/edit flows |
validation 500 vertices — full self-intersection | src/core/geometry/__tests__/interactionGeometry.bench.ts / src/hooks/__tests__/snapIntegration.bench.ts | 0.8 ms | polygon self-intersection checks in draw/edit flows |
validation 1000 vertices — append edge | src/core/geometry/__tests__/interactionGeometry.bench.ts / src/hooks/__tests__/snapIntegration.bench.ts | 0.01 ms | polygon self-intersection checks in draw/edit flows |
validation 1000 vertices — full self-intersection | src/core/geometry/__tests__/interactionGeometry.bench.ts / src/hooks/__tests__/snapIntegration.bench.ts | 3 ms | polygon self-intersection checks in draw/edit flows |
lane boundary brush
| Bench | File | p99 ceiling | Guarded path |
|---|---|---|---|
boundary brush 1k lanes — find paint hit | src/core/geometry/__tests__/laneBoundaryPaint.bench.ts | 4 ms | mousemove lane-boundary brush scan over lane boundaries |
boundary brush 5k lanes — find paint hit | src/core/geometry/__tests__/laneBoundaryPaint.bench.ts | 16 ms | mousemove lane-boundary brush scan over lane boundaries |
boundary brush 100 pts — paint lane type | src/core/geometry/__tests__/laneBoundaryPaint.bench.ts | 0.1 ms | lane boundary type insertion and normalization |
boundary brush 1000 pts — paint lane type | src/core/geometry/__tests__/laneBoundaryPaint.bench.ts | 0.5 ms | lane boundary type insertion and normalization |
spatial worker pipeline
| Bench | File | p99 ceiling | Guarded path |
|---|---|---|---|
spatial 1k — syncEntities | src/core/workers/__tests__/spatialPipeline.bench.ts | 60 ms | worker sync, cold feature rebuild, delta, and hit-test protocol |
spatial 1k — buildFeatureCollection full | src/core/workers/__tests__/spatialPipeline.bench.ts | 10 ms | worker sync, cold feature rebuild, delta, and hit-test protocol |
spatial 1k — buildFeatureCollection incremental 1 lane | src/core/workers/__tests__/spatialPipeline.bench.ts | 6 ms | worker sync, cold feature rebuild, delta, and hit-test protocol |
spatial 1k — featureGroupsForState | src/core/workers/__tests__/spatialPipeline.bench.ts | 1 ms | worker sync, cold feature rebuild, delta, and hit-test protocol |
spatial 1k — HIT_TEST dense query | src/core/workers/__tests__/spatialPipeline.bench.ts | 1 ms | worker sync, cold feature rebuild, delta, and hit-test protocol |
spatial 1k — INCREMENTAL request 1 dirty lane | src/core/workers/__tests__/spatialPipeline.bench.ts | 5 ms | worker sync, cold feature rebuild, delta, and hit-test protocol |
spatial 5k — syncEntities | src/core/workers/__tests__/spatialPipeline.bench.ts | 80 ms | worker sync, cold feature rebuild, delta, and hit-test protocol |
spatial 5k — buildFeatureCollection full | src/core/workers/__tests__/spatialPipeline.bench.ts | 50 ms | worker sync, cold feature rebuild, delta, and hit-test protocol |
spatial 5k — buildFeatureCollection incremental 1 lane | src/core/workers/__tests__/spatialPipeline.bench.ts | 30 ms | worker sync, cold feature rebuild, delta, and hit-test protocol |
spatial 5k — featureGroupsForState | src/core/workers/__tests__/spatialPipeline.bench.ts | 10 ms | worker sync, cold feature rebuild, delta, and hit-test protocol |
spatial 5k — HIT_TEST dense query | src/core/workers/__tests__/spatialPipeline.bench.ts | 10 ms | worker sync, cold feature rebuild, delta, and hit-test protocol |
spatial 5k — INCREMENTAL request 1 dirty lane | src/core/workers/__tests__/spatialPipeline.bench.ts | 60 ms | worker sync, cold feature rebuild, delta, and hit-test protocol |
cold, hot, overlay, and grid layers
| Bench | File | p99 ceiling | Guarded path |
|---|---|---|---|
cold layer 5k — groupsToFeatureMap | src/hooks/__tests__/layerBuilders.bench.ts | 0.6 ms | main-thread cold source cache, diff, and updateData helpers |
cold layer 5k — flattenEntityFeatures | src/hooks/__tests__/layerBuilders.bench.ts | 1 ms | main-thread cold source cache, diff, and updateData helpers |
cold layer 5k — diffEntities one update one remove | src/hooks/__tests__/layerBuilders.bench.ts | 0.5 ms | main-thread cold source cache, diff, and updateData helpers |
cold source 5k — rebuild from cache | src/hooks/__tests__/layerBuilders.bench.ts | 1.2 ms | main-thread cold source cache, diff, and updateData helpers |
cold source 5k — apply delta 100 changed | src/hooks/__tests__/layerBuilders.bench.ts | 0.05 ms | main-thread cold source cache, diff, and updateData helpers |
cold layer 25k — groupsToFeatureMap | src/hooks/__tests__/layerBuilders.bench.ts | 6 ms | main-thread cold source cache, diff, and updateData helpers |
cold layer 25k — flattenEntityFeatures | src/hooks/__tests__/layerBuilders.bench.ts | 5 ms | main-thread cold source cache, diff, and updateData helpers |
cold layer 25k — diffEntities one update one remove | src/hooks/__tests__/layerBuilders.bench.ts | 3 ms | main-thread cold source cache, diff, and updateData helpers |
cold source 25k — rebuild from cache | src/hooks/__tests__/layerBuilders.bench.ts | 4 ms | main-thread cold source cache, diff, and updateData helpers |
cold source 25k — apply delta 100 changed | src/hooks/__tests__/layerBuilders.bench.ts | 0.05 ms | main-thread cold source cache, diff, and updateData helpers |
hot layer lane 100 pts — entityToHotFeatures | src/hooks/__tests__/layerBuilders.bench.ts | 0.05 ms | selected entity drag display and hot feature generation |
hot layer lane 100 pts — applyDrag and features | src/hooks/__tests__/layerBuilders.bench.ts | 0.1 ms | selected entity drag display and hot feature generation |
hot layer lane 1000 pts — entityToHotFeatures | src/hooks/__tests__/layerBuilders.bench.ts | 0.15 ms | selected entity drag display and hot feature generation |
hot layer lane 1000 pts — applyDrag and features | src/hooks/__tests__/layerBuilders.bench.ts | 1.5 ms | selected entity drag display and hot feature generation |
hot layer lane 5000 pts — entityToHotFeatures | src/hooks/__tests__/layerBuilders.bench.ts | 1.5 ms | selected entity drag display and hot feature generation |
hot layer lane 5000 pts — applyDrag and features | src/hooks/__tests__/layerBuilders.bench.ts | 2 ms | selected entity drag display and hot feature generation |
overlay polyline 100 pts — buildOverlayFeatures | src/hooks/__tests__/layerBuilders.bench.ts | 0.05 ms | draw preview feature generation |
overlay catmull 100 pts — buildOverlayFeatures | src/hooks/__tests__/layerBuilders.bench.ts | 0.8 ms | draw preview feature generation |
overlay bezier 100 anchors — buildOverlayFeatures | src/hooks/__tests__/layerBuilders.bench.ts | 0.3 ms | draw preview feature generation |
overlay polyline 1000 pts — buildOverlayFeatures | src/hooks/__tests__/layerBuilders.bench.ts | 0.5 ms | draw preview feature generation |
overlay catmull 1000 pts — buildOverlayFeatures | src/hooks/__tests__/layerBuilders.bench.ts | 8 ms | draw preview feature generation |
overlay bezier 1000 anchors — buildOverlayFeatures | src/hooks/__tests__/layerBuilders.bench.ts | 4 ms | draw preview feature generation |
grid max-density viewport — buildGrid | src/hooks/__tests__/layerBuilders.bench.ts | 0.05 ms | grid viewport feature generation |
panel data builders
| Bench | File | p99 ceiling | Guarded path |
|---|---|---|---|
panel 10k — build layer tree | src/components/layout/panels/__tests__/panelData.bench.ts | 1 ms | layer tree build over all entities |
panel 10k — compute outline stats | src/components/layout/panels/__tests__/panelData.bench.ts | 0.5 ms | outline scan and orphan checks |
panel 10k — search miss scan | src/components/layout/panels/__tests__/panelData.bench.ts | 0.5 ms | search linear scan over all entities |
panel 50k — build layer tree | src/components/layout/panels/__tests__/panelData.bench.ts | 8 ms | layer tree build over all entities |
panel 50k — compute outline stats | src/components/layout/panels/__tests__/panelData.bench.ts | 6 ms | outline scan and orphan checks |
panel 50k — search miss scan | src/components/layout/panels/__tests__/panelData.bench.ts | 4 ms | search linear scan over all entities |
entity reference operations
| Bench | File | p99 ceiling | Guarded path |
|---|---|---|---|
entityOps 10k — cascadeDeleteRefsFull one lane | src/lib/entityOps/__tests__/entityOps.bench.ts | 3 ms | whole-map reference cleanup and reparent scans |
entityOps 10k — cascadeDeleteRefsFull 100 lanes | src/lib/entityOps/__tests__/entityOps.bench.ts | 4 ms | whole-map reference cleanup and reparent scans |
entityOps 10k — reparent lane to road section | src/lib/entityOps/__tests__/entityOps.bench.ts | 0.5 ms | whole-map reference cleanup and reparent scans |
entityOps 50k — cascadeDeleteRefsFull one lane | src/lib/entityOps/__tests__/entityOps.bench.ts | 20 ms | whole-map reference cleanup and reparent scans |
entityOps 50k — cascadeDeleteRefsFull 100 lanes | src/lib/entityOps/__tests__/entityOps.bench.ts | 25 ms | whole-map reference cleanup and reparent scans |
entityOps 50k — reparent lane to road section | src/lib/entityOps/__tests__/entityOps.bench.ts | 2 ms | whole-map reference cleanup and reparent scans |
map store write transactions
| Bench | File | p99 ceiling | Guarded path |
|---|---|---|---|
mapStore 10k — update lane transaction | src/store/__tests__/mapStore.bench.ts | 90 ms | store add/update/remove/import transaction with topology and overlap patches |
mapStore 10k — remove lane transaction | src/store/__tests__/mapStore.bench.ts | 70 ms | store add/update/remove/import transaction with topology and overlap patches |
mapStore 10k — batchImport transaction | src/store/__tests__/mapStore.bench.ts | 90 ms | store add/update/remove/import transaction with topology and overlap patches |
mapStore 25k — update lane transaction | src/store/__tests__/mapStore.bench.ts | 130 ms | store add/update/remove/import transaction with topology and overlap patches |
mapStore 25k — remove lane transaction | src/store/__tests__/mapStore.bench.ts | 120 ms | store add/update/remove/import transaction with topology and overlap patches |
mapStore 25k — batchImport transaction | src/store/__tests__/mapStore.bench.ts | 240 ms | store add/update/remove/import transaction with topology and overlap patches |
main-thread chunking
| Bench | File | p99 ceiling | Guarded path |
|---|---|---|---|
chunking 10k entities — slice 2k chunks | src/lib/__tests__/chunking.bench.ts | 0.05 ms | main-thread worker/IO chunk slice loop before postMessage |
chunking 50k entities — slice 2k chunks | src/lib/__tests__/chunking.bench.ts | 0.1 ms | main-thread worker/IO chunk slice loop before postMessage |
Apollo proto pipeline
| Bench | File | p99 ceiling | Guarded path |
|---|---|---|---|
proto bridge 1k — apolloMapToEntities | src/io/proto/__tests__/protoPipeline.bench.ts | 5 ms | import/export bridge, projection, binary, and text codec work |
proto bridge 1k — entitiesToApolloMap | src/io/proto/__tests__/protoPipeline.bench.ts | 3 ms | import/export bridge, projection, binary, and text codec work |
proto bounds 1k — computeApolloMapBounds | src/io/proto/__tests__/protoPipeline.bench.ts | 0.5 ms | import auto-fit bounds traversal |
proto projection 1k — to lonlat | src/io/proto/__tests__/protoPipeline.bench.ts | 45 ms | import/export bridge, projection, binary, and text codec work |
proto projection 1k — from lonlat | src/io/proto/__tests__/protoPipeline.bench.ts | 60 ms | import/export bridge, projection, binary, and text codec work |
proto bridge 5k — apolloMapToEntities | src/io/proto/__tests__/protoPipeline.bench.ts | 12 ms | import/export bridge, projection, binary, and text codec work |
proto bridge 5k — entitiesToApolloMap | src/io/proto/__tests__/protoPipeline.bench.ts | 16 ms | import/export bridge, projection, binary, and text codec work |
proto bounds 5k — computeApolloMapBounds | src/io/proto/__tests__/protoPipeline.bench.ts | 2 ms | import auto-fit bounds traversal |
proto projection 5k — to lonlat | src/io/proto/__tests__/protoPipeline.bench.ts | 150 ms | import/export bridge, projection, binary, and text codec work |
proto projection 5k — from lonlat | src/io/proto/__tests__/protoPipeline.bench.ts | 150 ms | import/export bridge, projection, binary, and text codec work |
proto bin 1k lanes — encode | src/io/proto/__tests__/protoPipeline.bench.ts | 30 ms | import/export bridge, projection, binary, and text codec work |
proto bin 1k lanes — decode | src/io/proto/__tests__/protoPipeline.bench.ts | 16 ms | import/export bridge, projection, binary, and text codec work |
proto text 100 lanes — encode | src/io/proto/__tests__/protoPipeline.bench.ts | 12 ms | import/export bridge, projection, binary, and text codec work |
proto text 100 lanes — decode | src/io/proto/__tests__/protoPipeline.bench.ts | 8 ms | import/export bridge, projection, binary, and text codec work |
proto roundtrip 1k lanes — bridge project encode | src/io/proto/__tests__/protoPipeline.bench.ts | 60 ms | export-style bridge, projection, and binary encode pipeline |
Bench Naming
Naming rules
- Start with the measured object:
<algorithm> — <input description>. - Put the scale in the name; avoid vague small/medium/large labels.
- The name must exactly match
scripts/bench-budgets.json; the guard uses exact string matching.
Cross-Platform Variance
CI runs on GitHub ubuntu-latest, where VM jitter is normal. Budgets should:
- Keep roughly 30% headroom; sub-1ms benches need larger relative headroom.
- Treat repeated failures as real regressions; rerun one-off outliers first.
- Update
scripts/bench-budgets.jsonand this page whenever a bench is added.
Coverage Scope
Why there are 115 benches now
The budget set covers code that can stall the main thread, pile work onto workers, or regress on large-map complexity:
- Geometry hot paths: offset, snap, hit-test, boundary brush, polygon validation.
- Map derivation: lane junctions, lane topology, overlap reconcile.
- Worker and layer paths: spatial worker cold pipeline, cold source diff/updateData helpers, hot/overlay/grid builders, main-thread chunk slicing.
- Panel data builders: MapOutline stats, LayerTree construction, and SearchPanel whole-map scans.
- Store and entity operations: mapStore write transactions, batchImport, cascade delete, whole-map reparent scans.
- IO paths: Apollo proto bridge, bounds, projection, roundtrip, binary codec, and text codec.
MapLibre's internal setData/updateData/queryRenderedFeatures implementation is not executed in Node benches. These benches guard the app-side construction, diff, chunking, and protocol costs around those calls.
Why p99 Instead Of Mean
CI gates on p99 because tail latency, not average speed, governs perceived stutter. A path with a low mean but occasional multi-frame spikes is still visible during 60fps drag and click workflows.