Skip to content

Commit 13f9472

Browse files
fix: deduplicate codspeed benchmarks
1 parent 51a44d8 commit 13f9472

7 files changed

Lines changed: 253 additions & 31 deletions

File tree

.github/scripts/generate-benchmark-matrix.mjs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ const SHARDS = {
3939
label: "codec vlq parallel",
4040
cacheKey: "codec-vlq-parallel",
4141
packageName: "srcmap-codec",
42-
bench: "vlq",
42+
bench: "vlq_parallel",
4343
features: "codspeed,parallel",
4444
}),
4545
sourcemap: rustShard({
@@ -59,7 +59,7 @@ const SHARDS = {
5959
label: "generator parallel",
6060
cacheKey: "generator-parallel",
6161
packageName: "srcmap-generator",
62-
bench: "generate",
62+
bench: "generate_parallel",
6363
features: "codspeed,parallel",
6464
}),
6565
remapping: rustShard({

benchmarks/fallow-cloud-coverage.mjs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ console.log("\n--- Cached Coverage Lookup ---\n");
271271
const bench = createBench({ warmupIterations: 20, iterations: 200 });
272272

273273
bench
274-
.add("trace-mapping individual lookup", () => {
274+
.add("fallow_cloud_coverage trace-mapping individual lookup", () => {
275275
for (const beacon of beacons) {
276276
const positions = cachedMaps.offsetLookup.generatedPositionsFor(beacon.offsets);
277277
for (let i = 0; i < positions.length; i += 2) {
@@ -282,28 +282,28 @@ bench
282282
}
283283
}
284284
})
285-
.add("srcmap WASM individual lookup", () => {
285+
.add("fallow_cloud_coverage srcmap WASM individual lookup", () => {
286286
for (const beacon of beacons) {
287287
const positions = cachedMaps.offsetLookup.generatedPositionsFor(beacon.offsets);
288288
for (let i = 0; i < positions.length; i += 2) {
289289
cachedMaps.wasm.originalPositionFor(positions[i], positions[i + 1]);
290290
}
291291
}
292292
})
293-
.add("srcmap NAPI individual lookup", () => {
293+
.add("fallow_cloud_coverage srcmap NAPI individual lookup", () => {
294294
for (const beacon of beacons) {
295295
const positions = cachedMaps.offsetLookup.generatedPositionsFor(beacon.offsets);
296296
for (let i = 0; i < positions.length; i += 2) {
297297
cachedMaps.napi.originalPositionFor(positions[i], positions[i + 1]);
298298
}
299299
}
300300
})
301-
.add("srcmap WASM batch lookup", () => {
301+
.add("fallow_cloud_coverage srcmap WASM batch lookup", () => {
302302
for (const beacon of beacons) {
303303
cachedMaps.offsetLookup.originalPositionsFor(cachedMaps.wasm, beacon.offsets);
304304
}
305305
})
306-
.add("srcmap NAPI batch lookup", () => {
306+
.add("fallow_cloud_coverage srcmap NAPI batch lookup", () => {
307307
for (const beacon of beacons) {
308308
cachedMaps.offsetLookup.originalPositionsFor(cachedMaps.napi, beacon.offsets);
309309
}

benchmarks/real-world.mjs

Lines changed: 39 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,10 @@ for (const fixture of FIXTURES) {
5555

5656
console.log("=== Real-World Source Map Benchmarks ===\n");
5757
console.log("Libraries:");
58-
console.log(" @jridgewell/trace-mapping de facto standard JS source map consumer");
59-
console.log(" source-map-js Mozilla source-map fork (used by Vite, PostCSS)");
60-
console.log(" srcmap WASM srcmap Rust core via WebAssembly");
61-
console.log(" srcmap NAPI srcmap Rust core via N-API\n");
58+
console.log(" @jridgewell/trace-mapping - de facto standard JS source map consumer");
59+
console.log(" source-map-js - Mozilla source-map fork (used by Vite, PostCSS)");
60+
console.log(" srcmap WASM - srcmap Rust core via WebAssembly");
61+
console.log(" srcmap NAPI - srcmap Rust core via N-API\n");
6262

6363
console.log("Source maps:");
6464
for (const m of maps) {
@@ -142,13 +142,14 @@ for (const { name, json, size } of maps) {
142142
// Fewer iterations for large maps
143143
const iterations = size > 1024 * 1024 ? 50 : 200;
144144
const bench = createBench({ warmupIterations: 10, iterations });
145+
const prefix = `real_world_parse[${name}]`;
145146

146147
bench
147-
.add("trace-mapping", () => new TraceMap(json))
148-
.add("source-map-js", () => new SourceMapConsumer(json))
149-
.add("srcmap WASM", () => new SourceMap(json))
150-
.add("srcmap WASM (fast)", () => new FastSourceMap(json))
151-
.add("srcmap NAPI", () => new NapiSourceMap(json));
148+
.add(`${prefix} trace-mapping`, () => new TraceMap(json))
149+
.add(`${prefix} source-map-js`, () => new SourceMapConsumer(json))
150+
.add(`${prefix} srcmap WASM`, () => new SourceMap(json))
151+
.add(`${prefix} srcmap WASM fast`, () => new FastSourceMap(json))
152+
.add(`${prefix} srcmap NAPI`, () => new NapiSourceMap(json));
152153

153154
await bench.run();
154155

@@ -166,7 +167,7 @@ for (const { name, json, size } of maps) {
166167

167168
console.log("\n--- Single Lookup ---\n");
168169

169-
for (const { name, json } of maps) {
170+
for (const { name, json, size } of maps) {
170171
console.log(`### ${name}\n`);
171172

172173
const trace = new TraceMap(json);
@@ -177,17 +178,26 @@ for (const { name, json } of maps) {
177178
// Pick a lookup position roughly in the middle of the map
178179
const midLine = Math.floor(wasm.lineCount / 2);
179180

180-
const bench = createBench({ warmupIterations: 500, iterations: 5000 });
181+
const isLargeMap = size > 1024 * 1024;
182+
const bench = createBench({
183+
warmupIterations: isLargeMap ? 50 : 500,
184+
iterations: isLargeMap ? 500 : 5000,
185+
});
186+
const prefix = `real_world_lookup_single[${name}]`;
181187

182188
bench
183-
.add("trace-mapping", () => originalPositionFor(trace, { line: midLine + 1, column: 20 }))
184-
.add("source-map-js", () => smjs.originalPositionFor({ line: midLine + 1, column: 20 }))
185-
.add("srcmap WASM", () => wasm.originalPositionFor(midLine, 20))
186-
.add("srcmap WASM (flat)", () => wasm.originalPositionFlat(midLine, 20))
187-
.add("srcmap WASM (buf)", () => {
189+
.add(`${prefix} trace-mapping`, () =>
190+
originalPositionFor(trace, { line: midLine + 1, column: 20 }),
191+
)
192+
.add(`${prefix} source-map-js`, () =>
193+
smjs.originalPositionFor({ line: midLine + 1, column: 20 }),
194+
)
195+
.add(`${prefix} srcmap WASM`, () => wasm.originalPositionFor(midLine, 20))
196+
.add(`${prefix} srcmap WASM flat`, () => wasm.originalPositionFlat(midLine, 20))
197+
.add(`${prefix} srcmap WASM buf`, () => {
188198
wasm.originalPositionBuf(midLine, 20);
189199
})
190-
.add("srcmap NAPI", () => napi.originalPositionFor(midLine, 20));
200+
.add(`${prefix} srcmap NAPI`, () => napi.originalPositionFor(midLine, 20));
191201

192202
await bench.run();
193203

@@ -205,7 +215,7 @@ for (const { name, json } of maps) {
205215

206216
console.log("\n--- 1000x Lookup ---\n");
207217

208-
for (const { name, json } of maps) {
218+
for (const { name, json, size } of maps) {
209219
console.log(`### ${name}\n`);
210220

211221
const trace = new TraceMap(json);
@@ -225,23 +235,28 @@ for (const { name, json } of maps) {
225235
}
226236
const posArray = new Int32Array(flatPositions);
227237

228-
const bench = createBench({ warmupIterations: 20, iterations: 200 });
238+
const isLargeMap = size > 1024 * 1024;
239+
const bench = createBench({
240+
warmupIterations: isLargeMap ? 5 : 20,
241+
iterations: isLargeMap ? 50 : 200,
242+
});
243+
const prefix = `real_world_lookup_1000x[${name}]`;
229244

230245
bench
231-
.add("trace-mapping", () => {
246+
.add(`${prefix} trace-mapping`, () => {
232247
for (const { line, column } of lookups)
233248
originalPositionFor(trace, { line: line + 1, column });
234249
})
235-
.add("source-map-js", () => {
250+
.add(`${prefix} source-map-js`, () => {
236251
for (const { line, column } of lookups) smjs.originalPositionFor({ line: line + 1, column });
237252
})
238-
.add("srcmap WASM (individual)", () => {
253+
.add(`${prefix} srcmap WASM individual`, () => {
239254
for (const { line, column } of lookups) wasm.originalPositionFor(line, column);
240255
})
241-
.add("srcmap WASM (batch)", () => {
256+
.add(`${prefix} srcmap WASM batch`, () => {
242257
wasm.originalPositionsFor(posArray);
243258
})
244-
.add("srcmap NAPI (batch)", () => {
259+
.add(`${prefix} srcmap NAPI batch`, () => {
245260
napi.originalPositionsFor(flatPositions);
246261
});
247262

crates/codec/Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,8 @@ criterion2 = { workspace = true }
3131
[[bench]]
3232
name = "vlq"
3333
harness = false
34+
35+
[[bench]]
36+
name = "vlq_parallel"
37+
harness = false
38+
required-features = ["parallel"]
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
use std::hint::black_box;
2+
3+
use criterion::{BatchSize, Criterion, criterion_group, criterion_main};
4+
use srcmap_codec::{Segment, encode, encode_parallel};
5+
6+
fn make_large_realistic_mappings() -> srcmap_codec::SourceMapMappings {
7+
let mut mappings = Vec::with_capacity(5000);
8+
let mut src: i64 = 0;
9+
let mut src_line: i64 = 0;
10+
let mut src_col: i64 = 0;
11+
let mut name: i64 = 0;
12+
13+
for line_idx in 0..5000_i64 {
14+
let segments_per_line = 10 + (line_idx % 40) as usize;
15+
let mut line = Vec::with_capacity(segments_per_line);
16+
let mut gen_col: i64 = 0;
17+
18+
for seg in 0..segments_per_line {
19+
let seg = seg as i64;
20+
gen_col += 2 + (seg * 3) % 28;
21+
if seg % 15 == 0 {
22+
src += 1;
23+
}
24+
src_line += if seg % 7 == 0 { -3 } else { 1 };
25+
src_line = src_line.max(0);
26+
src_col += (seg * 7 + 3) % 50 - 10;
27+
src_col = src_col.max(0);
28+
29+
if seg % 5 == 0 {
30+
name += 1;
31+
line.push(Segment::five(gen_col, src, src_line, src_col, name));
32+
} else {
33+
line.push(Segment::four(gen_col, src, src_line, src_col));
34+
}
35+
}
36+
mappings.push(line);
37+
}
38+
mappings
39+
}
40+
41+
fn make_very_large_realistic_mappings() -> srcmap_codec::SourceMapMappings {
42+
let mut mappings = Vec::with_capacity(50000);
43+
let mut src: i64 = 0;
44+
let mut src_line: i64 = 0;
45+
let mut src_col: i64 = 0;
46+
let mut name: i64 = 0;
47+
48+
for line_idx in 0..50000_i64 {
49+
let segments_per_line = 5 + (line_idx % 20) as usize;
50+
let mut line = Vec::with_capacity(segments_per_line);
51+
let mut gen_col: i64 = 0;
52+
53+
for seg in 0..segments_per_line {
54+
let seg = seg as i64;
55+
gen_col += 2 + (seg * 3) % 28;
56+
if seg % 15 == 0 {
57+
src += 1;
58+
}
59+
src_line += if seg % 7 == 0 { -3 } else { 1 };
60+
src_line = src_line.max(0);
61+
src_col += (seg * 7 + 3) % 50 - 10;
62+
src_col = src_col.max(0);
63+
64+
if seg % 5 == 0 {
65+
name += 1;
66+
line.push(Segment::five(gen_col, src, src_line, src_col, name));
67+
} else {
68+
line.push(Segment::four(gen_col, src, src_line, src_col));
69+
}
70+
}
71+
mappings.push(line);
72+
}
73+
mappings
74+
}
75+
76+
fn bench_parallel_encode(criterion: &mut Criterion) {
77+
criterion.bench_function("parallel_feature_encode_sequential_5k_lines", |b| {
78+
b.iter_batched_ref(
79+
make_large_realistic_mappings,
80+
|mappings| encode(black_box(mappings)),
81+
BatchSize::LargeInput,
82+
);
83+
});
84+
85+
criterion.bench_function("parallel_feature_encode_parallel_5k_lines", |b| {
86+
b.iter_batched_ref(
87+
make_large_realistic_mappings,
88+
|mappings| encode_parallel(black_box(mappings)),
89+
BatchSize::LargeInput,
90+
);
91+
});
92+
93+
criterion.bench_function("parallel_feature_encode_sequential_50k_lines", |b| {
94+
b.iter_batched_ref(
95+
make_very_large_realistic_mappings,
96+
|mappings| encode(black_box(mappings)),
97+
BatchSize::LargeInput,
98+
);
99+
});
100+
101+
criterion.bench_function("parallel_feature_encode_parallel_50k_lines", |b| {
102+
b.iter_batched_ref(
103+
make_very_large_realistic_mappings,
104+
|mappings| encode_parallel(black_box(mappings)),
105+
BatchSize::LargeInput,
106+
);
107+
});
108+
}
109+
110+
criterion_group!(benches, bench_parallel_encode);
111+
criterion_main!(benches);

crates/generator/Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,8 @@ criterion2 = { workspace = true }
3535
[[bench]]
3636
name = "generate"
3737
harness = false
38+
39+
[[bench]]
40+
name = "generate_parallel"
41+
harness = false
42+
required-features = ["parallel"]
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
use std::hint::black_box;
2+
3+
use criterion::{BatchSize, Criterion, criterion_group, criterion_main};
4+
use srcmap_generator::SourceMapGenerator;
5+
6+
fn build_generator(lines: u32, cols_per_line: u32, with_content: bool) -> SourceMapGenerator {
7+
let mut builder = SourceMapGenerator::new(Some("bundle.js".to_string()));
8+
9+
for i in 0..10 {
10+
let src = builder.add_source(&format!("src/file{i}.js"));
11+
if with_content {
12+
builder.set_source_content(
13+
src,
14+
format!("// source file {i}\n{}", "const x = 1;\n".repeat(500)),
15+
);
16+
}
17+
}
18+
19+
for i in 0..20 {
20+
builder.add_name(&format!("var{i}"));
21+
}
22+
23+
for line in 0..lines {
24+
for col in 0..cols_per_line {
25+
let src = (line * cols_per_line + col) % 10;
26+
if col % 3 == 0 {
27+
let name = col % 20;
28+
builder.add_named_mapping(line, col * 10, src, line, col * 5, name);
29+
} else {
30+
builder.add_mapping(line, col * 10, src, line, col * 5);
31+
}
32+
}
33+
}
34+
35+
builder
36+
}
37+
38+
fn build_sorted_generator(lines: u32, cols_per_line: u32) -> SourceMapGenerator {
39+
let mut builder = build_generator(lines, cols_per_line, false);
40+
builder.set_assume_sorted(true);
41+
builder
42+
}
43+
44+
fn bench_parallel_generate(criterion: &mut Criterion) {
45+
criterion.bench_function("parallel_feature_generate_100000_mappings", |b| {
46+
b.iter_batched_ref(
47+
|| build_generator(5000, 20, false),
48+
|builder| black_box(builder.to_json()),
49+
BatchSize::LargeInput,
50+
);
51+
});
52+
53+
criterion.bench_function("parallel_feature_generate_100000_mappings_assume_sorted", |b| {
54+
b.iter_batched_ref(
55+
|| build_sorted_generator(5000, 20),
56+
|builder| black_box(builder.to_json()),
57+
BatchSize::LargeInput,
58+
);
59+
});
60+
61+
criterion.bench_function(
62+
"parallel_feature_generate_100000_mappings_with_sources_content",
63+
|b| {
64+
b.iter_batched_ref(
65+
|| build_generator(5000, 20, true),
66+
|builder| black_box(builder.to_json()),
67+
BatchSize::LargeInput,
68+
);
69+
},
70+
);
71+
72+
criterion.bench_function("parallel_feature_generate_100000_mappings_to_writer", |b| {
73+
b.iter_batched_ref(
74+
|| build_generator(5000, 20, false),
75+
|builder| {
76+
let mut out = Vec::new();
77+
builder.to_writer(&mut out).unwrap();
78+
black_box(out);
79+
},
80+
BatchSize::LargeInput,
81+
);
82+
});
83+
}
84+
85+
criterion_group!(benches, bench_parallel_generate);
86+
criterion_main!(benches);

0 commit comments

Comments
 (0)