11import { createBench , latencyMeanMs , latencyP99Ms , throughputHz } from "./codspeed.mjs" ;
22import { createDeterministicLookups , setFailureExitCode } from "./workload.mjs" ;
3+ import assert from "node:assert/strict" ;
34import { readFileSync , existsSync } from "node:fs" ;
45import { dirname , join } from "node:path" ;
56import { fileURLToPath } from "node:url" ;
@@ -27,6 +28,49 @@ const createOrderedLookups = (count, maxLine, descending) =>
2728 } ;
2829 } ) ;
2930
31+ const createLookupPatterns = ( maxLine ) => {
32+ const midLine = Math . floor ( maxLine / 2 ) ;
33+ return [
34+ { name : "ascending" , lookups : createOrderedLookups ( LOOKUP_COUNT , maxLine , false ) } ,
35+ { name : "descending" , lookups : createOrderedLookups ( LOOKUP_COUNT , maxLine , true ) } ,
36+ {
37+ name : "repeated" ,
38+ lookups : Array . from ( { length : LOOKUP_COUNT } , ( ) => ( { line : midLine , column : 20 } ) ) ,
39+ } ,
40+ {
41+ name : "randomized" ,
42+ lookups : createDeterministicLookups ( LOOKUP_COUNT , maxLine , LOOKUP_MAX_COLUMN , LOOKUP_SEED ) ,
43+ } ,
44+ ] ;
45+ } ;
46+
47+ const assertLazyMatchesEager = ( eager , lazy , lookups , context ) => {
48+ for ( const { line, column } of lookups ) {
49+ assert . deepEqual (
50+ lazy . originalPositionFor ( line , column ) ,
51+ eager . originalPositionFor ( line , column ) ,
52+ `${ context } at ${ line } :${ column } ` ,
53+ ) ;
54+ }
55+ } ;
56+
57+ const consumeLookups = ( map , lookups ) => {
58+ let checksum = 2_166_136_261 ;
59+
60+ for ( const { line, column } of lookups ) {
61+ const result = map . originalPositionFor ( line , column ) ;
62+ const value =
63+ result === null
64+ ? 0
65+ : result . line ^ result . column ^ ( result . source ?. length ?? 0 ) ^ ( result . name ?. length ?? 0 ) ;
66+ checksum = Math . imul ( checksum ^ value , 16_777_619 ) >>> 0 ;
67+ }
68+
69+ return checksum ;
70+ } ;
71+
72+ let lookupChecksum = 0 ;
73+
3074// ── Load fixtures ────────────────────────────────────────────────
3175
3276const FIXTURES = [
@@ -181,39 +225,78 @@ for (const { name, json, size } of maps) {
181225 ) ;
182226}
183227
184- // ── Fast-lazy lookup order ────────── ─────────────────────────────
228+ // ── Fast-lazy cold map lookup order ─────────────────────────────
185229
186- console . log ( "\n--- Fast-Lazy Lookup Order ---\n" ) ;
230+ console . log ( "\n--- Fast-Lazy Cold Map: Construct and First Lookup Pass ---\n" ) ;
187231
188232for ( const { name, json, size, lines } of maps ) {
189233 console . log ( `### ${ name } \n` ) ;
190234
191- const midLine = Math . floor ( lines / 2 ) ;
192- const patterns = [
193- { name : "ascending" , lookups : createOrderedLookups ( LOOKUP_COUNT , lines , false ) } ,
194- { name : "descending" , lookups : createOrderedLookups ( LOOKUP_COUNT , lines , true ) } ,
195- {
196- name : "repeated" ,
197- lookups : Array . from ( { length : LOOKUP_COUNT } , ( ) => ( { line : midLine , column : 20 } ) ) ,
198- } ,
199- {
200- name : "randomized" ,
201- lookups : createDeterministicLookups ( LOOKUP_COUNT , lines , LOOKUP_MAX_COLUMN , LOOKUP_SEED ) ,
202- } ,
203- ] . map ( ( pattern ) => ( { ...pattern , map : new FastSourceMap ( json ) } ) ) ;
235+ const eager = new SourceMap ( json ) ;
236+ const patterns = createLookupPatterns ( lines ) ;
237+
238+ for ( const pattern of patterns ) {
239+ const lazy = new FastSourceMap ( json ) ;
240+ assertLazyMatchesEager ( eager , lazy , pattern . lookups , `${ name } ${ pattern . name } ` ) ;
241+ lazy . free ( ) ;
242+ }
243+ eager . free ( ) ;
244+
245+ const isLargeMap = size > 1024 * 1024 ;
246+ const bench = createBench ( {
247+ warmupIterations : isLargeMap ? 2 : 5 ,
248+ iterations : isLargeMap ? 10 : 50 ,
249+ } ) ;
250+ const prefix = `real_world_lazy_lookup_cold_1000x[${ name } ]` ;
251+
252+ for ( const pattern of patterns ) {
253+ bench . add ( `${ prefix } ${ pattern . name } ` , ( ) => {
254+ const lazy = new FastSourceMap ( json ) ;
255+ lookupChecksum = ( lookupChecksum + consumeLookups ( lazy , pattern . lookups ) ) >>> 0 ;
256+ lazy . free ( ) ;
257+ } ) ;
258+ }
259+
260+ await bench . run ( ) ;
261+
262+ console . table (
263+ bench . tasks . map ( ( task ) => ( {
264+ Name : task . name ,
265+ "ops/sec" : Math . round ( throughputHz ( task ) ) . toLocaleString ( ) ,
266+ "avg (μs)" : ( latencyMeanMs ( task ) * 1000 ) . toFixed ( 1 ) ,
267+ "per lookup (ns)" : Math . round (
268+ ( latencyMeanMs ( task ) * 1_000_000 ) / LOOKUP_COUNT ,
269+ ) . toLocaleString ( ) ,
270+ } ) ) ,
271+ ) ;
272+ }
273+
274+ // ── Fast-lazy warm cache lookup order ────────────────────────────
275+
276+ console . log ( "\n--- Fast-Lazy Warm Cache: Reuse Decoded Lines ---\n" ) ;
277+
278+ for ( const { name, json, size, lines } of maps ) {
279+ console . log ( `### ${ name } \n` ) ;
280+
281+ const patterns = createLookupPatterns ( lines ) . map ( ( pattern ) => ( {
282+ ...pattern ,
283+ map : new FastSourceMap ( json ) ,
284+ } ) ) ;
285+
286+ for ( const pattern of patterns ) {
287+ lookupChecksum = ( lookupChecksum + consumeLookups ( pattern . map , pattern . lookups ) ) >>> 0 ;
288+ }
204289
205290 const isLargeMap = size > 1024 * 1024 ;
206291 const bench = createBench ( {
207292 warmupIterations : isLargeMap ? 5 : 20 ,
208293 iterations : isLargeMap ? 50 : 200 ,
209294 } ) ;
210- const prefix = `real_world_lazy_lookup_1000x [${ name } ]` ;
295+ const prefix = `real_world_lazy_lookup_warm_1000x [${ name } ]` ;
211296
212297 for ( const pattern of patterns ) {
213298 bench . add ( `${ prefix } ${ pattern . name } ` , ( ) => {
214- for ( const { line, column } of pattern . lookups ) {
215- pattern . map . originalPositionFor ( line , column ) ;
216- }
299+ lookupChecksum = ( lookupChecksum + consumeLookups ( pattern . map , pattern . lookups ) ) >>> 0 ;
217300 } ) ;
218301 }
219302
@@ -235,6 +318,8 @@ for (const { name, json, size, lines } of maps) {
235318 }
236319}
237320
321+ console . log ( `Lookup checksum: ${ lookupChecksum } ` ) ;
322+
238323// ── Single lookup ────────────────────────────────────────────────
239324
240325console . log ( "\n--- Single Lookup ---\n" ) ;
0 commit comments