From 30a8f00f000c3fcac65f57cbfd38e816c14e7f60 Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Sat, 30 Apr 2022 01:45:08 -0400 Subject: [PATCH 1/4] Add ability to set content while adding marking --- src/gen-mapping.ts | 30 ++++++++++++++++++++++++++---- test/gen-mapping.test.js | 27 +++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 4 deletions(-) diff --git a/src/gen-mapping.ts b/src/gen-mapping.ts index 44a87cc..601c745 100644 --- a/src/gen-mapping.ts +++ b/src/gen-mapping.ts @@ -36,6 +36,7 @@ export let addSegment: { sourceLine?: null, sourceColumn?: null, name?: null, + content?: null, ): void; ( map: GenMapping, @@ -45,6 +46,7 @@ export let addSegment: { sourceLine: number, sourceColumn: number, name?: null, + content?: string | null, ): void; ( map: GenMapping, @@ -54,6 +56,7 @@ export let addSegment: { sourceLine: number, sourceColumn: number, name: string, + content?: string | null, ): void; }; @@ -69,6 +72,7 @@ export let addMapping: { source?: null; original?: null; name?: null; + content?: null; }, ): void; ( @@ -78,6 +82,7 @@ export let addMapping: { source: string; original: Pos; name?: null; + content?: string | null; }, ): void; ( @@ -87,6 +92,7 @@ export let addMapping: { source: string; original: Pos; name: string; + content?: string | null; }, ): void; }; @@ -143,6 +149,7 @@ let addSegmentInternal: ( sourceLine: S extends string ? number : null | undefined, sourceColumn: S extends string ? number : null | undefined, name: S extends string ? string | null | undefined : null | undefined, + content: S extends string ? string | null | undefined : null | undefined, ) => void; /** @@ -162,7 +169,7 @@ export class GenMapping { } static { - addSegment = (map, genLine, genColumn, source, sourceLine, sourceColumn, name) => { + addSegment = (map, genLine, genColumn, source, sourceLine, sourceColumn, name, content) => { return addSegmentInternal( false, map, @@ -172,10 +179,20 @@ export class GenMapping { sourceLine, sourceColumn, name, + content, ); }; - maybeAddSegment = (map, genLine, genColumn, source, sourceLine, sourceColumn, name) => { + maybeAddSegment = ( + map, + genLine, + genColumn, + source, + sourceLine, + sourceColumn, + name, + content, + ) => { return addSegmentInternal( true, map, @@ -185,6 +202,7 @@ export class GenMapping { sourceLine, sourceColumn, name, + content, ); }; @@ -281,6 +299,7 @@ export class GenMapping { sourceLine, sourceColumn, name, + content, ) => { const { _mappings: mappings, @@ -303,7 +322,7 @@ export class GenMapping { const sourcesIndex = put(sources, source); const namesIndex = name ? put(names, name) : NO_NAME; - if (sourcesIndex === sourcesContent.length) sourcesContent[sourcesIndex] = null; + if (sourcesIndex === sourcesContent.length) sourcesContent[sourcesIndex] = content ?? null; if (skipable && skipSource(line, index, sourcesIndex, sourceLine, sourceColumn, namesIndex)) { return; @@ -406,9 +425,10 @@ function addMappingInternal( source: S; original: S extends string ? Pos : null | undefined; name: S extends string ? string | null | undefined : null | undefined; + content: S extends string ? string | null | undefined : null | undefined; }, ) { - const { generated, source, original, name } = mapping; + const { generated, source, original, name, content } = mapping; if (!source) { return addSegmentInternal( skipable, @@ -419,6 +439,7 @@ function addMappingInternal( null, null, null, + null, ); } const s: string = source; @@ -432,5 +453,6 @@ function addMappingInternal( original.line - 1, original.column, name, + content, ); } diff --git a/test/gen-mapping.test.js b/test/gen-mapping.test.js index c461d9b..f6ca875 100644 --- a/test/gen-mapping.test.js +++ b/test/gen-mapping.test.js @@ -316,6 +316,33 @@ describe('GenMapping', () => { assert.deepEqual(toDecodedMap(map).sourcesContent, ['input', null, 'bar']); }); + + it('can set content when adding', () => { + const map = new GenMapping(); + + addSegment(map, 0, 0, 'input.js', 0, 0, '', 'input'); + addSegment(map, 1, 0, 'foo.js', 0, 0, '', undefined); + + assert.deepEqual(toDecodedMap(map).sourcesContent, ['input', null]); + }); + + it('only sets content during initial source add', () => { + const map = new GenMapping(); + + addSegment(map, 0, 0, 'input.js', 0, 0, '', 'first'); + addSegment(map, 1, 0, 'input.js', 0, 0, '', 'second'); + + assert.deepEqual(toDecodedMap(map).sourcesContent, ['first']); + }); + + it('ignores content when sourceless', () => { + const map = new GenMapping(); + + addSegment(map, 0, 0, 'input.js', 0, 0); + addSegment(map, 0, 1, '', 0, 0, '', 'foo'); + + assert.deepEqual(toDecodedMap(map).sourcesContent, [null]); + }); }); describe('addMapping', () => { From 9e355196094556635ad40e7ebb4bdaeade4559cc Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Sat, 30 Apr 2022 18:27:24 -0400 Subject: [PATCH 2/4] Add memory usage --- README.md | 126 ++++++++++++++++++++---------- benchmark/index.mjs | 181 +++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 257 insertions(+), 50 deletions(-) diff --git a/README.md b/README.md index 707f0e2..4066cdb 100644 --- a/README.md +++ b/README.md @@ -111,69 +111,115 @@ assert.deepEqual(toEncodedMap(map), { node v18.0.0 amp.js.map -gen-mapping: addSegment x 450 ops/sec ±1.16% (87 runs sampled) -gen-mapping: addMapping x 430 ops/sec ±0.90% (90 runs sampled) -source-map-js: addMapping x 178 ops/sec ±1.06% (84 runs sampled) -source-map-0.6.1: addMapping x 177 ops/sec ±1.07% (84 runs sampled) -source-map-0.8.0: addMapping x 178 ops/sec ±0.98% (84 runs sampled) +Memory Usage: +gen-mapping: addSegment 5852872 bytes +gen-mapping: addMapping 7716042 bytes +source-map-js 6143250 bytes +source-map-0.6.1 6124102 bytes +source-map-0.8.0 6121173 bytes +Smallest memory usage is gen-mapping: addSegment + +Adding speed: +gen-mapping: addSegment x 441 ops/sec ±2.07% (90 runs sampled) +gen-mapping: addMapping x 350 ops/sec ±2.40% (86 runs sampled) +source-map-js: addMapping x 169 ops/sec ±2.42% (80 runs sampled) +source-map-0.6.1: addMapping x 167 ops/sec ±2.56% (80 runs sampled) +source-map-0.8.0: addMapping x 168 ops/sec ±2.52% (80 runs sampled) Fastest is gen-mapping: addSegment -gen-mapping: decoded output x 157,549,649 ops/sec ±0.14% (97 runs sampled) -gen-mapping: encoded output x 669 ops/sec ±1.34% (95 runs sampled) -source-map-js: encoded output x 160 ops/sec ±0.64% (83 runs sampled) -source-map-0.6.1: encoded output x 161 ops/sec ±0.47% (84 runs sampled) -source-map-0.8.0: encoded output x 190 ops/sec ±0.28% (90 runs sampled) +Generate speed: +gen-mapping: decoded output x 150,824,370 ops/sec ±0.07% (102 runs sampled) +gen-mapping: encoded output x 663 ops/sec ±0.22% (98 runs sampled) +source-map-js: encoded output x 197 ops/sec ±0.45% (84 runs sampled) +source-map-0.6.1: encoded output x 198 ops/sec ±0.33% (85 runs sampled) +source-map-0.8.0: encoded output x 197 ops/sec ±0.06% (93 runs sampled) Fastest is gen-mapping: decoded output + *** + babel.min.js.map -gen-mapping: addSegment x 51.09 ops/sec ±4.58% (56 runs sampled) -gen-mapping: addMapping x 39.38 ops/sec ±4.40% (54 runs sampled) -source-map-js: addMapping x 21.65 ops/sec ±3.34% (40 runs sampled) -source-map-0.6.1: addMapping x 21.90 ops/sec ±3.59% (41 runs sampled) -source-map-0.8.0: addMapping x 21.89 ops/sec ±3.10% (41 runs sampled) +Memory Usage: +gen-mapping: addSegment 37578063 bytes +gen-mapping: addMapping 37212897 bytes +source-map-js 47638527 bytes +source-map-0.6.1 47690503 bytes +source-map-0.8.0 47470188 bytes +Smallest memory usage is gen-mapping: addMapping + +Adding speed: +gen-mapping: addSegment x 31.05 ops/sec ±8.31% (43 runs sampled) +gen-mapping: addMapping x 29.83 ops/sec ±7.36% (51 runs sampled) +source-map-js: addMapping x 20.73 ops/sec ±6.22% (38 runs sampled) +source-map-0.6.1: addMapping x 20.03 ops/sec ±10.51% (38 runs sampled) +source-map-0.8.0: addMapping x 19.30 ops/sec ±8.27% (37 runs sampled) Fastest is gen-mapping: addSegment -gen-mapping: decoded output x 154,505,123 ops/sec ±0.45% (100 runs sampled) -gen-mapping: encoded output x 84.17 ops/sec ±5.44% (66 runs sampled) -source-map-js: encoded output x 17.57 ops/sec ±4.55% (33 runs sampled) -source-map-0.6.1: encoded output x 16.43 ops/sec ±7.03% (34 runs sampled) -source-map-0.8.0: encoded output x 16.60 ops/sec ±6.44% (32 runs sampled) +Generate speed: +gen-mapping: decoded output x 381,379,234 ops/sec ±0.29% (96 runs sampled) +gen-mapping: encoded output x 95.15 ops/sec ±2.98% (72 runs sampled) +source-map-js: encoded output x 15.20 ops/sec ±7.41% (33 runs sampled) +source-map-0.6.1: encoded output x 16.36 ops/sec ±10.46% (31 runs sampled) +source-map-0.8.0: encoded output x 16.06 ops/sec ±6.45% (31 runs sampled) Fastest is gen-mapping: decoded output + *** + preact.js.map -gen-mapping: addSegment x 11,643 ops/sec ±3.36% (91 runs sampled) -gen-mapping: addMapping x 10,921 ops/sec ±0.63% (87 runs sampled) -source-map-js: addMapping x 4,534 ops/sec ±0.25% (98 runs sampled) -source-map-0.6.1: addMapping x 4,572 ops/sec ±0.18% (99 runs sampled) -source-map-0.8.0: addMapping x 4,519 ops/sec ±0.27% (99 runs sampled) +Memory Usage: +gen-mapping: addSegment 416247 bytes +gen-mapping: addMapping 419824 bytes +source-map-js 1024619 bytes +source-map-0.6.1 1146004 bytes +source-map-0.8.0 1113250 bytes +Smallest memory usage is gen-mapping: addSegment + +Adding speed: +gen-mapping: addSegment x 13,755 ops/sec ±0.15% (98 runs sampled) +gen-mapping: addMapping x 13,013 ops/sec ±0.11% (101 runs sampled) +source-map-js: addMapping x 4,564 ops/sec ±0.21% (98 runs sampled) +source-map-0.6.1: addMapping x 4,562 ops/sec ±0.11% (99 runs sampled) +source-map-0.8.0: addMapping x 4,593 ops/sec ±0.11% (100 runs sampled) Fastest is gen-mapping: addSegment -gen-mapping: decoded output x 157,554,436 ops/sec ±0.09% (98 runs sampled) -gen-mapping: encoded output x 17,673 ops/sec ±1.11% (87 runs sampled) -source-map-js: encoded output x 5,526 ops/sec ±0.63% (93 runs sampled) -source-map-0.6.1: encoded output x 5,679 ops/sec ±0.21% (98 runs sampled) -source-map-0.8.0: encoded output x 5,911 ops/sec ±0.14% (101 runs sampled) +Generate speed: +gen-mapping: decoded output x 379,864,020 ops/sec ±0.23% (93 runs sampled) +gen-mapping: encoded output x 14,368 ops/sec ±4.07% (82 runs sampled) +source-map-js: encoded output x 5,261 ops/sec ±0.21% (99 runs sampled) +source-map-0.6.1: encoded output x 5,124 ops/sec ±0.58% (99 runs sampled) +source-map-0.8.0: encoded output x 5,434 ops/sec ±0.33% (96 runs sampled) Fastest is gen-mapping: decoded output + *** + react.js.map -gen-mapping: addSegment x 4,168 ops/sec ±1.08% (81 runs sampled) -gen-mapping: addMapping x 3,842 ops/sec ±1.27% (84 runs sampled) -source-map-js: addMapping x 1,510 ops/sec ±1.63% (95 runs sampled) -source-map-0.6.1: addMapping x 1,537 ops/sec ±0.34% (97 runs sampled) -source-map-0.8.0: addMapping x 1,546 ops/sec ±0.29% (98 runs sampled) +Memory Usage: +gen-mapping: addSegment 975096 bytes +gen-mapping: addMapping 1102981 bytes +source-map-js 2918836 bytes +source-map-0.6.1 2885435 bytes +source-map-0.8.0 2874336 bytes +Smallest memory usage is gen-mapping: addSegment + +Adding speed: +gen-mapping: addSegment x 4,772 ops/sec ±0.15% (100 runs sampled) +gen-mapping: addMapping x 4,456 ops/sec ±0.13% (97 runs sampled) +source-map-js: addMapping x 1,618 ops/sec ±0.24% (97 runs sampled) +source-map-0.6.1: addMapping x 1,622 ops/sec ±0.12% (99 runs sampled) +source-map-0.8.0: addMapping x 1,631 ops/sec ±0.12% (100 runs sampled) Fastest is gen-mapping: addSegment -gen-mapping: decoded output x 157,136,960 ops/sec ±0.13% (92 runs sampled) -gen-mapping: encoded output x 6,494 ops/sec ±0.56% (96 runs sampled) -source-map-js: encoded output x 2,206 ops/sec ±0.25% (100 runs sampled) -source-map-0.6.1: encoded output x 2,188 ops/sec ±0.51% (99 runs sampled) -source-map-0.8.0: encoded output x 2,254 ops/sec ±0.27% (100 runs sampled) +Generate speed: +gen-mapping: decoded output x 379,107,695 ops/sec ±0.07% (99 runs sampled) +gen-mapping: encoded output x 5,421 ops/sec ±1.60% (89 runs sampled) +source-map-js: encoded output x 2,113 ops/sec ±1.81% (98 runs sampled) +source-map-0.6.1: encoded output x 2,126 ops/sec ±0.10% (100 runs sampled) +source-map-0.8.0: encoded output x 2,176 ops/sec ±0.39% (98 runs sampled) Fastest is gen-mapping: decoded output ``` diff --git a/benchmark/index.mjs b/benchmark/index.mjs index f15b07d..e282253 100644 --- a/benchmark/index.mjs +++ b/benchmark/index.mjs @@ -11,9 +11,8 @@ import { addMapping, toEncodedMap, toDecodedMap, - fromMap, } from '../dist/gen-mapping.mjs'; -import { SourceMapGenerator as SourceMapGeneratorJs, SourceMapConsumer } from 'source-map-js'; +import { SourceMapGenerator as SourceMapGeneratorJs } from 'source-map-js'; import { SourceMapGenerator as SourceMapGenerator061 } from 'source-map'; import { SourceMapGenerator as SourceMapGeneratorWasm } from 'source-map-wasm'; @@ -21,11 +20,179 @@ const dir = relative(process.cwd(), dirname(fileURLToPath(import.meta.url))); console.log(`node ${process.version}\n`); +function track(label, results, cb) { + let ret; + const deltas = []; + for (let i = 0; i < 10; i++) { + ret = null; + if (global.gc) for (let i = 0; i < 3; i++) global.gc(); + const before = process.memoryUsage(); + ret = cb(); + const after = process.memoryUsage(); + deltas.push(delta(before, after)); + } + const a = avg(deltas); + console.log(`${label.padEnd(25, ' ')} ${String(a.heapUsed).padStart(10, ' ')} bytes`); + results.push({ label, delta: a.heapUsed }); + return ret; +} + +function avg(deltas) { + let rss = 0; + let heapTotal = 0; + let heapUsed = 0; + let external = 0; + let arrayBuffers = 0; + for (let i = 0; i < deltas.length; i++) { + const d = deltas[i]; + rss += d.rss / deltas.length; + heapTotal += d.heapTotal / deltas.length; + heapUsed += d.heapUsed / deltas.length; + external += d.external / deltas.length; + arrayBuffers += d.arrayBuffers / deltas.length; + } + return { + rss: Math.floor(rss), + heapTotal: Math.floor(heapTotal), + heapUsed: Math.floor(heapUsed), + external: Math.floor(external), + arrayBuffers: Math.floor(arrayBuffers), + }; +} + +function delta(before, after) { + return { + rss: after.rss - before.rss, + heapTotal: after.heapTotal - before.heapTotal, + heapUsed: after.heapUsed - before.heapUsed, + external: after.external - before.external, + arrayBuffers: after.arrayBuffers - before.arrayBuffers, + }; +} + async function bench(file) { const map = JSON.parse(readFileSync(join(dir, file))); const { sources, names } = map; const mappings = decode(map.mappings); + console.log('Memory Usage:'); + const results = []; + const genmap = track('gen-mapping: addSegment', results, () => { + const map = new GenMapping(); + for (let i = 0; i < mappings.length; i++) { + const line = mappings[i]; + for (let j = 0; j < line.length; j++) { + const seg = line[j]; + let source, sourceLine, sourceColumn, name; + const genColumn = seg[0]; + if (seg.length !== 1) { + source = sources[seg[1]]; + sourceLine = seg[2]; + sourceColumn = seg[3]; + if (seg.length === 5) name = names[seg[4]]; + } + addSegment(map, i, genColumn, source, sourceLine, sourceColumn, name); + } + } + return map; + }); + track('gen-mapping: addMapping', results, () => { + const map = new GenMapping(); + for (let i = 0; i < mappings.length; i++) { + const line = mappings[i]; + for (let j = 0; j < line.length; j++) { + const seg = line[j]; + const mapping = { + generated: { line: i + 1, column: seg[0] }, + source: undefined, + original: undefined, + name: undefined, + }; + if (seg.length !== 1) { + mapping.source = sources[seg[1]]; + mapping.original = { line: seg[2] + 1, column: seg[3] }; + if (seg.length === 5) mapping.name = names[seg[4]]; + } + addMapping(map, mapping); + } + } + return map; + }); + const smgjs = track('source-map-js', results, () => { + const map = new SourceMapGeneratorJs(); + for (let i = 0; i < mappings.length; i++) { + const line = mappings[i]; + for (let j = 0; j < line.length; j++) { + const seg = line[j]; + const mapping = { + generated: { line: i + 1, column: seg[0] }, + source: undefined, + original: undefined, + name: undefined, + }; + if (seg.length !== 1) { + mapping.source = sources[seg[1]]; + mapping.original = { line: seg[2] + 1, column: seg[3] }; + if (seg.length === 5) mapping.name = names[seg[4]]; + } + map.addMapping(mapping); + } + } + return map; + }); + const smg061 = track('source-map-0.6.1', results, () => { + const map = new SourceMapGenerator061(); + for (let i = 0; i < mappings.length; i++) { + const line = mappings[i]; + for (let j = 0; j < line.length; j++) { + const seg = line[j]; + const mapping = { + generated: { line: i + 1, column: seg[0] }, + source: undefined, + original: undefined, + name: undefined, + }; + if (seg.length !== 1) { + mapping.source = sources[seg[1]]; + mapping.original = { line: seg[2] + 1, column: seg[3] }; + if (seg.length === 5) mapping.name = names[seg[4]]; + } + map.addMapping(mapping); + } + } + return map; + }); + const smgWasm = track('source-map-0.8.0', results, () => { + const map = new SourceMapGeneratorWasm(); + for (let i = 0; i < mappings.length; i++) { + const line = mappings[i]; + for (let j = 0; j < line.length; j++) { + const seg = line[j]; + const mapping = { + generated: { line: i + 1, column: seg[0] }, + source: undefined, + original: undefined, + name: undefined, + }; + if (seg.length !== 1) { + mapping.source = sources[seg[1]]; + mapping.original = { line: seg[2] + 1, column: seg[3] }; + if (seg.length === 5) mapping.name = names[seg[4]]; + } + map.addMapping(mapping); + } + } + return map; + }); + const winner = results.reduce((min, cur) => { + if (cur.delta < min.delta) return cur; + return min; + }); + console.log(`Smallest memory usage is ${winner.label}`); + + console.log(''); + + console.log('Adding speed:'); new Benchmark.Suite() .add('gen-mapping: addSegment', () => { const map = new GenMapping(); @@ -129,7 +296,6 @@ async function bench(file) { } } }) - // add listeners .on('error', (event) => console.error(event.target.error)) .on('cycle', (event) => { @@ -142,12 +308,7 @@ async function bench(file) { console.log(''); - const consumer = new SourceMapConsumer(map); - const genmap = fromMap(map); - const smgjs = SourceMapGeneratorJs.fromSourceMap(consumer); - const smg061 = SourceMapGenerator061.fromSourceMap(consumer); - const smgWasm = SourceMapGeneratorWasm.fromSourceMap(consumer); - + console.log('Generate speed:'); new Benchmark.Suite() .add('gen-mapping: decoded output', () => { toDecodedMap(genmap); @@ -180,7 +341,7 @@ async function run(files) { for (const file of files) { if (!file.endsWith('.map')) continue; - if (!first) console.log('\n***\n'); + if (!first) console.log('\n\n***\n\n'); first = false; console.log(file); From 8c1834672b1451ac19c37b0f44cf55f1e2997d4d Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Thu, 5 May 2022 17:37:48 -0400 Subject: [PATCH 3/4] Add types field to exports --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 193e3e3..74eb079 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "typings": "dist/types/gen-mapping.d.ts", "exports": { ".": { + "types": "./dist/types/gen-mapping.d.ts", "browser": "./dist/gen-mapping.umd.js", "require": "./dist/gen-mapping.umd.js", "import": "./dist/gen-mapping.mjs" From b6aa06065065960be0465bcc6d2a586a7251c519 Mon Sep 17 00:00:00 2001 From: Justin Ridgewell Date: Thu, 5 May 2022 17:48:21 -0400 Subject: [PATCH 4/4] 0.3.1 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6579758..a716624 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@jridgewell/gen-mapping", - "version": "0.3.0", + "version": "0.3.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@jridgewell/gen-mapping", - "version": "0.3.0", + "version": "0.3.1", "license": "MIT", "dependencies": { "@jridgewell/set-array": "^1.0.0", diff --git a/package.json b/package.json index 74eb079..3b709f6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@jridgewell/gen-mapping", - "version": "0.3.0", + "version": "0.3.1", "description": "Generate source maps", "keywords": [ "source",