性能预算
本页概括 scripts/bench-budgets.json 的 115 条 p99 性能预算。CI 在 pnpm bench 后调用 scripts/check-bench-budget.mjs,任何未注册 bench 或超预算 bench 都会让检查失败。
文件位置
| 路径 | 作用 |
|---|---|
scripts/bench-budgets.json | 预算表,CI 的唯一数据源 |
scripts/check-bench-budget.mjs | fail-closed 校验脚本 |
bench-results.json | pnpm bench --outputJson bench-results.json 的临时输出 |
当前预算
json
{
"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
}
}1
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
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 分组
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 命名约定
命名规范
- 必须以衡量对象开头:
<algorithm> — <input description>,例如full stitch — 100-lane chain。 - 数字直接出现:避免 vague 的 small/medium/large;写
100-lane才便于扫表。 - 必须与
bench-budgets.json完全一致:脚本按字符串精确匹配。
跨平台波动
CI 跑在 GitHub ubuntu-latest(虚拟机,性能波动 ±20%)。所以预算要:
- 留 30% 左右缓冲;对 < 1ms 的 bench 留更高比例缓冲。
- 连续复现的失败按真实回退处理;单次偶发失败先 rerun。
- 新增 bench 必须同步更新
scripts/bench-budgets.json和本文。
覆盖范围
为什么现在是 115 条 bench
预算覆盖以下会导致主线程卡顿、worker 队列堆积、或大图复杂度退化的路径:
- geometry hot path:offset、snap、hit-test、boundary brush、polygon validation。
- map derivation:lane junction、lane topology、overlap reconcile。
- worker and layer path:spatial worker cold pipeline、cold source diff/updateData、hot/overlay/grid builders、主线程 chunk 切片。
- panel data builders:MapOutline 统计、LayerTree 建树、SearchPanel 全量扫描。
- store and entity operations:mapStore 写事务、batchImport、cascade delete、reparent 全表扫描。
- IO path:Apollo proto bridge、bounds、projection、roundtrip、binary codec、text codec。
MapLibre 自身的 setData/updateData/queryRenderedFeatures 内部实现不在 Node bench 中执行;这里用 mock source 和 worker/helper bench 守住应用侧构造、diff、chunk 和协议成本。
p99 与 mean 的关系
CI 用 p99 是因为尾延迟才是用户体验的天花板。一个 mean 很低但偶尔抖到几十毫秒的路径,会在 60fps 拖拽或点击中被感知;p99 能直接暴露这种抖动。