Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14,404 changes: 3,788 additions & 10,616 deletions package-lock.json

Large diffs are not rendered by default.

11 changes: 9 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,12 @@
"acorn": "7.2.0",
"aphrodite": "2.1.0",
"esbuild": "0.27.0",
"esbuild-jest": "0.5.0",
"eslint": "8.0.0",
"eslint-plugin-prettier": "5.1.2",
"eslint-plugin-react-hooks": "4.6.0",
"jest": "24.3.0",
"jfrview": "0.2.0",
"jsverify": "0.8.3",
"jszip": "3.1.5",
"pako": "1.0.6",
Expand All @@ -53,17 +55,22 @@
"ts-jest": "24.3.0",
"tsx": "4.19.2",
"typescript": "5.3.3",
"typescript-json-schema": "0.42.0",
"typescript-json-schema": "0.67.0",
"uglify-es": "3.2.2",
"uint8array-json-parser": "0.0.2"
},
"jest": {
"transform": {
"^.+\\.tsx?$": "ts-jest"
"^.+\\.tsx?$": "ts-jest",
"^.+\\.js$": "esbuild-jest"
},
"transformIgnorePatterns": [],
"setupFilesAfterEnv": [
"./src/jest-setup.js"
],
"moduleNameMapper": {
"\\jfrview_bg.wasm$": "<rootDir>/src/import/java-flight-record.mock.ts"
},
"testRegex": "\\.test\\.tsx?$",
"collectCoverageFrom": [
"**/*.{ts,tsx}",
Expand Down
Binary file added sample/profiles/java-flight-recorder/heavy.jfr
Binary file not shown.
1 change: 1 addition & 0 deletions scripts/esbuild-shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export const buildOptions: esbuild.BuildOptions = {
'.woff2': 'file',
'.png': 'file',
'.ico': 'file',
'.wasm': 'file',
},
}

Expand Down
8 changes: 8 additions & 0 deletions src/global.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
declare global {
// Mock modern Typescript constructs used in JfrView until we update our Typescript
interface SymbolConstructor {
readonly dispose: symbol
}
}

export {}
1,167 changes: 1,167 additions & 0 deletions src/import/__snapshots__/java-flight-recorder.test.ts.snap

Large diffs are not rendered by default.

9 changes: 9 additions & 0 deletions src/import/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {isTraceEventFormatted, importTraceEvents} from './trace-event'
import {importFromCallgrind} from './callgrind'
import {importFromPapyrus} from './papyrus'
import {importFromPMCStatCallGraph} from './pmcstat-callgraph'
import {importFromJfr, isJfrRecording} from './java-flight-recorder'

export async function importProfileGroupFromText(
fileName: string,
Expand Down Expand Up @@ -127,6 +128,9 @@ async function _importProfileGroup(dataSource: ProfileDataSource): Promise<Profi
} else if (fileName.endsWith('.pmcstat.graph')) {
console.log('Importing as pmcstat callgraph format')
return toGroup(importFromPMCStatCallGraph(contents))
} else if (fileName.endsWith('.jfr')) {
console.log('Importing as Java Flight Recorder profile')
return await importFromJfr(fileName, buffer)
}

// Second pass: Try to guess what file format it is based on structure
Expand Down Expand Up @@ -197,6 +201,11 @@ async function _importProfileGroup(dataSource: ProfileDataSource): Promise<Profi
return toGroup(importFromPapyrus(contents))
}

if (isJfrRecording(buffer)) {
console.log('Importing as Java Flight Recorder profile')
return importFromJfr(fileName, buffer)
}

const fromLinuxPerf = importFromLinuxPerf(contents)
if (fromLinuxPerf) {
console.log('Importing from linux perf script output')
Expand Down
6 changes: 6 additions & 0 deletions src/import/java-flight-record.mock.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import fs from 'fs'

// We need to load the wasm binary as file
// This is different from the production case where we load the binary via `fetch`
const wasm_module = fs.readFileSync('node_modules/jfrview/jfrview_bg.wasm')
module.exports = wasm_module
5 changes: 5 additions & 0 deletions src/import/java-flight-recorder.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import {checkProfileSnapshot} from '../lib/test-utils'

test('importFromJfr', async () => {
await checkProfileSnapshot('./sample/profiles/java-flight-recorder/heavy.jfr')
})
46 changes: 46 additions & 0 deletions src/import/java-flight-recorder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import {FrameInfo, Profile, ProfileGroup, StackListProfileBuilder} from '../lib/profile'
import init, {Frame, interpret_jfr} from 'jfrview'
// @ts-ignore
import wasm_data from 'jfrview/jfrview_bg.wasm'

export async function importFromJfr(fileName: string, data: ArrayBuffer): Promise<ProfileGroup> {
await init({module_or_path: wasm_data})
const withoutNative = create_profile(data, false)
const withNative = create_profile(data, true)

return {
indexToView: 0,
name: fileName,
profiles: [withoutNative, withNative],
}
}

export function isJfrRecording(buffer: ArrayBuffer) {
const b = buffer.slice(0, 3)
const bytes = new Uint8Array(b)
return bytes[0] === 0x46 && bytes[1] === 0x4c && bytes[2] === 0x52
}

function create_profile(data: ArrayBuffer, includeNative: boolean): Profile {
const result = interpret_jfr(new Uint8Array(data), includeNative)

const builder = new StackListProfileBuilder(result.length)
if (includeNative) {
builder.setName('With native calls')
} else {
builder.setName('Without native calls')
}

function to_fi(input: Frame): FrameInfo {
return {
name: input.name,
key: input.name,
}
}

for (const sample of result) {
builder.appendSampleWithWeight(sample.frames.map(to_fi), 1)
}

return builder.build()
}
1 change: 1 addition & 0 deletions src/jest-setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,5 @@
//
// Let's emulate it being a global API during tests.
global.TextDecoder = require('util').TextDecoder
global.TextEncoder = require('util').TextEncoder
})()