diff --git a/application.tsx b/application.tsx index 7abdc4b..71b2378 100644 --- a/application.tsx +++ b/application.tsx @@ -16,7 +16,7 @@ import {SortMethod, SortField, SortDirection} from './profile-table-view' import {triangle} from './utils' import {Color} from './color' import {RowAtlas} from './row-atlas' -import {importAsmJsSymbolMap} from './asm-js' +import {importEmscriptenSymbolMap} from './emscripten' import {SandwichView} from './sandwich-view' import {saveToFile} from './file-format' @@ -384,9 +384,9 @@ export class Application extends ReloadableComponent<{}, ApplicationState> { // a symbol map. If that's the case, we want to parse it, and apply the symbol // mapping to the already loaded profile. This can be use to take an opaque // profile and make it readable. - const map = importAsmJsSymbolMap(reader.result) + const map = importEmscriptenSymbolMap(reader.result) if (map) { - console.log('Importing as asm.js symbol map') + console.log('Importing as emscripten symbol map') let profile = this.state.profile profile.remapNames(name => map.get(name) || name) return profile diff --git a/asm-js.ts b/asm-js.ts deleted file mode 100644 index 33e517f..0000000 --- a/asm-js.ts +++ /dev/null @@ -1,26 +0,0 @@ -type AsmJsSymbolMap = Map - -// This imports symbol maps generated by emscripten using the "--emit-symbol-map" flag. -// It allows you to visualize a profile captured in a release build as long as you also -// have the associated symbol map. To do this, first drop the profile into speedscope -// and then drop the symbol map. After the second drop, the symbols will be remapped to -// their original names. -export function importAsmJsSymbolMap(contents: string): AsmJsSymbolMap | null { - const lines = contents.split('\n') - if (!lines.length) return null - - // Remove a trailing blank line if there is one - if (lines[lines.length - 1] === '') lines.pop() - if (!lines.length) return null - - const map: AsmJsSymbolMap = new Map() - const regex = /^([\$\w]+):([\$\w]+)$/ - - for (const line of lines) { - const match = regex.exec(line) - if (!match) return null - map.set(match[1], match[2]) - } - - return map -} diff --git a/asm-js.test.ts b/emscripten.test.ts similarity index 57% rename from asm-js.test.ts rename to emscripten.test.ts index c963788..f16d06b 100644 --- a/asm-js.test.ts +++ b/emscripten.test.ts @@ -1,9 +1,9 @@ -import {importAsmJsSymbolMap} from './asm-js' +import {importEmscriptenSymbolMap} from './emscripten' -test('importAsmJSSymbolMap', () => { +test('importEmscriptenSymbolMap', () => { // Valid symbol map expect( - importAsmJsSymbolMap( + importEmscriptenSymbolMap( [ /* prettier: ignore */ 'a:A', @@ -15,7 +15,7 @@ test('importAsmJSSymbolMap', () => { // Valid symbol map with trailing newline expect( - importAsmJsSymbolMap( + importEmscriptenSymbolMap( [ /* prettier: ignore */ 'a:A', @@ -27,14 +27,27 @@ test('importAsmJSSymbolMap', () => { ).toEqual(new Map([['a', 'A'], ['b', 'B'], ['c', 'C']])) // Valid symbol map with non-alpha characters - - expect(importAsmJsSymbolMap('u6:__ZN8tinyxml210XMLCommentD0Ev\n')).toEqual( + expect(importEmscriptenSymbolMap('u6:__ZN8tinyxml210XMLCommentD0Ev\n')).toEqual( new Map([['u6', '__ZN8tinyxml210XMLCommentD0Ev']]), ) + // WebAssembly symbol map + expect( + importEmscriptenSymbolMap( + [ + /* prettier: ignore */ + '0:A', + '1:B', + '2:C', + ].join('\n'), + ), + ).toEqual( + new Map([['wasm-function[0]', 'A'], ['wasm-function[1]', 'B'], ['wasm-function[2]', 'C']]), + ) + // Invalid symbol map expect( - importAsmJsSymbolMap( + importEmscriptenSymbolMap( [ /* prettier: ignore */ 'a:A', @@ -47,7 +60,7 @@ test('importAsmJSSymbolMap', () => { // Collapsed stack format should not be imported as an asm.js symbol map expect( - importAsmJsSymbolMap( + importEmscriptenSymbolMap( [ /* prettier: ignore */ 'a;b 1', @@ -58,6 +71,6 @@ test('importAsmJSSymbolMap', () => { ).toEqual(null) // Unrelated files - expect(importAsmJsSymbolMap('')).toEqual(null) - expect(importAsmJsSymbolMap('\n')).toEqual(null) + expect(importEmscriptenSymbolMap('')).toEqual(null) + expect(importEmscriptenSymbolMap('\n')).toEqual(null) }) diff --git a/emscripten.ts b/emscripten.ts new file mode 100644 index 0000000..d0ac9a2 --- /dev/null +++ b/emscripten.ts @@ -0,0 +1,39 @@ +type EmscriptenSymbolMap = Map + +// This imports symbol maps generated by emscripten using the "--emit-symbol-map" flag. +// It allows you to visualize a profile captured in a release build as long as you also +// have the associated symbol map. To do this, first drop the profile into speedscope +// and then drop the symbol map. After the second drop, the symbols will be remapped to +// their original names. +export function importEmscriptenSymbolMap(contents: string): EmscriptenSymbolMap | null { + const lines = contents.split('\n') + if (!lines.length) return null + + // Remove a trailing blank line if there is one + if (lines[lines.length - 1] === '') lines.pop() + if (!lines.length) return null + + const map: EmscriptenSymbolMap = new Map() + const intRegex = /^(\d+):([\$\w]+)$/ + const idRegex = /^([\$\w]+):([\$\w]+)$/ + + for (const line of lines) { + // Match lines like "103:__ZN8tinyxml210XMLCommentD0Ev" + const intMatch = intRegex.exec(line) + if (intMatch) { + map.set(`wasm-function[${intMatch[1]}]`, intMatch[2]) + continue + } + + // Match lines like "u6:__ZN8tinyxml210XMLCommentD0Ev" + const idMatch = idRegex.exec(line) + if (idMatch) { + map.set(idMatch[1], idMatch[2]) + continue + } + + return null + } + + return map +}