Compare commits

..
2 Commits
Author SHA1 Message Date
Jamie Wong d7969ac2b8 0.3.0 2018-07-18 08:54:53 -07:00
Evan Wallace 1b36a2e3f4 add support for "wasm-function" symbol maps (#93)
This is an improvement to #76, which added support for asm.js symbol maps. This PR expands this to also work for emscripten's WebAssembly symbol maps too. This currently only works in Firefox. Chrome would need to fix https://crbug.com/863205 for this to be useful in Chrome.
2018-07-18 08:47:58 -07:00
7 changed files with 72 additions and 41 deletions
+5
View File
@@ -0,0 +1,5 @@
## [0.3.0] - 2018-07-18
### Added
* Support for remapping profiles using a wasm symbol file [#93]
+3 -3
View File
@@ -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
-26
View File
@@ -1,26 +0,0 @@
type AsmJsSymbolMap = Map<string, string>
// 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
}
+23 -10
View File
@@ -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)
})
+39
View File
@@ -0,0 +1,39 @@
type EmscriptenSymbolMap = Map<string, string>
// 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
}
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "speedscope",
"version": "0.2.0",
"version": "0.3.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "speedscope",
"version": "0.2.0",
"version": "0.3.0",
"description": "",
"main": "index.js",
"bin": {