A fast, interactive web-based viewer for performance profiles with AI-powered analysis. Supports import from a variety of profiles in a variety of languages (JS, Ruby, Python, Go & more).
git clone https://github.com/whbernard/speedscope.git
cd speedscope
npm install
npm run electron:devgit clone https://github.com/whbernard/speedscope.git
cd speedscope
npm install
npm run dev
# Open http://localhost:8000- Node.js LTS (18+) - Download here
- Git - Download here
Note: The web version works on all platforms. Desktop app requires additional setup for Windows/Linux.
# Development
npm run electron:dev # Desktop app
npm run dev # Web version
npm run build # Build for production
# Testing & Quality
npm test # Run all tests (typecheck, lint, coverage)
npm run typecheck # TypeScript type checking
npm run lint # ESLint code linting
npm run coverage # Jest test coverage
# Distribution
npm run electron:build # Create installers- VS Code with recommended extensions:
- TypeScript and JavaScript Language Features
- ESLint
- Prettier
- Jest Runner
- Thunder Client (for API testing)
-
Clone and install dependencies:
git clone https://github.com/whbernard/speedscope.git cd speedscope npm install -
Open in VS Code:
code .
# Start development server
npm run electron:dev- Main Process: Runs in Node.js context (main.js)
- Renderer Process: Runs in Chromium context (React app)
- DevTools: Automatically opens in development mode
# Start web development server
npm run dev
# Open http://localhost:8000Create a .vscode/launch.json file with the following configuration:
{
"version": "0.2.0",
"configurations": [
{
"name": "Debug Electron (Main + Renderer)",
"type": "node",
"request": "launch",
"cwd": "${workspaceFolder}",
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron",
"windows": {
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron.cmd"
},
"args": [".", "--inspect=5858", "--remote-debugging-port=9222"],
"outputCapture": "std",
"console": "integratedTerminal",
"env": {
"NODE_ENV": "development"
},
"skipFiles": ["<node_internals>/**"],
"sourceMaps": true,
"resolveSourceMapLocations": [
"${workspaceFolder}/**",
"!**/node_modules/**"
],
"outFiles": ["${workspaceFolder}/build/**/*.js"],
"preLaunchTask": "npm: build"
},
{
"name": "Debug Electron Main",
"type": "node",
"request": "launch",
"cwd": "${workspaceFolder}",
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron",
"windows": {
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron.cmd"
},
"args": [".", "--inspect=5858"],
"outputCapture": "std",
"console": "integratedTerminal",
"env": {
"NODE_ENV": "development"
}
},
{
"name": "Debug Electron Renderer",
"type": "node",
"request": "launch",
"cwd": "${workspaceFolder}",
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron",
"windows": {
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron.cmd"
},
"args": [".", "--remote-debugging-port=9222"],
"outputCapture": "std",
"console": "integratedTerminal",
"env": {
"NODE_ENV": "development"
},
"skipFiles": ["<node_internals>/**"]
},
{
"name": "Debug Tests",
"type": "node",
"request": "launch",
"program": "${workspaceFolder}/node_modules/.bin/jest",
"args": ["--runInBand", "--no-cache"],
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen",
"env": {
"NODE_ENV": "test"
}
}
]
}-
Debug Electron (Main + Renderer) - Recommended
- Best for: Full app debugging with both main and renderer processes
- Usage: Press
F5or select from Run & Debug panel - Features:
- Main process debugging on port 5858
- Renderer process debugging on port 9222
- Full breakpoint support in both contexts
-
Debug Electron Main - Main Process Only
- Best for: Debugging IPC handlers, OAuth/LLM requests, file operations
- Usage: Set breakpoints in
main.jsand related files - Features: Node.js debugging with full access to main process
-
Debug Electron Renderer - Renderer Process Only
- Best for: Debugging React components, frontend logic
- Usage: Set breakpoints in
src/files - Features: Chromium DevTools integration
-
Debug Tests - Jest Testing
- Best for: Debugging individual test cases
- Usage: Set breakpoints in test files, run specific tests
- Features: Full Jest debugging with breakpoints
Recommended Extensions (.vscode/extensions.json):
{
"recommendations": [
"ms-vscode.vscode-typescript-next",
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"firsttris.vscode-jest-runner",
"ms-vscode.vscode-json",
"bradlc.vscode-tailwindcss",
"rangav.vscode-thunder-client"
]
}Editor Settings (.vscode/settings.json):
{
"typescript.preferences.importModuleSpecifier": "relative",
"typescript.suggest.autoImports": true,
"typescript.updateImportsOnFileMove.enabled": "always",
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
},
"eslint.validate": [
"javascript",
"javascriptreact",
"typescript",
"typescriptreact"
],
"jest.jestCommandLine": "npm test --",
"jest.autoRun": "off",
"files.exclude": {
"**/node_modules": true,
"**/build": true,
"**/dist": true,
"**/coverage": true
},
"search.exclude": {
"**/node_modules": true,
"**/build": true,
"**/dist": true,
"**/coverage": true
},
"emmet.includeLanguages": {
"typescript": "html",
"typescriptreact": "html"
}
}Development Tasks (.vscode/tasks.json):
{
"version": "2.0.0",
"tasks": [
{
"label": "npm: build",
"type": "shell",
"command": "npm",
"args": ["run", "build"],
"group": "build",
"presentation": {
"echo": true,
"reveal": "always",
"focus": false,
"panel": "new"
},
"problemMatcher": []
},
{
"label": "npm: electron:dev",
"type": "shell",
"command": "npm",
"args": ["run", "electron:dev"],
"group": "build",
"presentation": {
"echo": true,
"reveal": "always",
"focus": false,
"panel": "new"
},
"problemMatcher": []
},
{
"label": "npm: test",
"type": "shell",
"command": "npm",
"args": ["test"],
"group": "test",
"presentation": {
"echo": true,
"reveal": "always",
"focus": false,
"panel": "new"
},
"problemMatcher": []
},
{
"label": "npm: typecheck",
"type": "shell",
"command": "npm",
"args": ["run", "typecheck"],
"group": "build",
"presentation": {
"echo": true,
"reveal": "always",
"focus": false,
"panel": "new"
},
"problemMatcher": ["$tsc"]
}
]
}- React DevTools: Install browser extension
- Redux DevTools: Available in development mode
- Console Logging: Use
console.log()in renderer process - Network Tab: Monitor API calls to OAuth/LLM endpoints
- Main Process Logs: Check VS Code terminal output
- IPC Communication: Logs in main.js show IPC calls
- API Requests: Axios requests logged with full payloads
- Error Handling: Full request payloads shown in error modal
# Run all tests
npm test
# Individual test commands
npm run typecheck # TypeScript compilation
npm run lint # Code style checking
npm run coverage # Test coverage report- Install Jest Runner extension
- Run individual tests: Click "Run" button above test functions
- Debug tests: Set breakpoints and use "Debug" button
- Coverage: View coverage in VS Code or open
coverage/lcov-report/index.html
- Check error modal: Shows full request payload
- Verify credentials: Client ID/secret in adapter configuration
- TLS issues: Check CA certificate path or disable validation
- Network: Verify endpoint URL and firewall settings
- Request payload: Full JSON shown in error modal
- Template variables: Check
{{profile_data}}and{{prompt}}replacement - Headers: Verify custom headers and authentication
- Rate limiting: Check API quotas and rate limits
- File format: Check supported formats in
src/import/ - File size: Large files may timeout (10MB limit)
- Parsing errors: Check console for detailed error messages
- Memory usage: Monitor in DevTools Performance tab
- Large profiles: Consider using interval selection for analysis
- WebGL: Check browser compatibility and GPU drivers
# Start development server
npm run electron:dev
# In another terminal, run tests
npm test
# Check for type errors
npm run typecheck- ESLint: Fixes auto-applied on save (if configured)
- Prettier: Code formatting on save
- TypeScript: Real-time type checking in VS Code
# Build for production
npm run build
# Create desktop installers
npm run electron:build- "Electron API not available": Ensure running in Electron context
- "Config file not found": Normal warning, using defaults
- TypeScript errors: Run
npm run typecheckfor details - White screen when debugging: See debugging troubleshooting below
- Build failures: Check Node.js version (18+ required)
- Console logs: Check both main and renderer process logs
- Error modals: Full request context provided
- DevTools: Network, Console, and Performance tabs
- GitHub Issues: Report bugs with full error details
To verify VS Code debugging is working:
-
Open VS Code in the project directory:
code . -
Set a breakpoint in
main.js(e.g., line 210 in the OAuth handler) -
Start debugging:
- Press
F5or go to Run & Debug panel - Select "Debug Electron (Main + Renderer)"
- The app should start and hit your breakpoint
- Press
-
Test breakpoints:
- Set breakpoints in
src/views/application.tsxfor frontend debugging - Set breakpoints in
main.jsfor backend debugging - Use the debug console to inspect variables
- Set breakpoints in
-
Verify features:
- β Main process debugging (Node.js context)
- β Renderer process debugging (React context)
- β Breakpoint support in both processes
- β Variable inspection and watch expressions
- β Call stack navigation
- β Error modal with full request payloads
Expected output when debugging starts:
Debugger listening on ws://127.0.0.1:5858/...
DevTools listening on ws://127.0.0.1:9222/...
App name set to: Speedscope with LLM
Window ready to show
If your breakpoints are "unbinding" (turning gray) after debug starts:
# Check if source maps exist
ls -la build/*.map
# Rebuild with source maps
npm run buildAdd these properties to your launch.json:
{
"sourceMaps": true,
"resolveSourceMapLocations": [
"${workspaceFolder}/**",
"!**/node_modules/**"
],
"outFiles": ["${workspaceFolder}/build/**/*.js"]
}- Don't set breakpoints before starting debug
- Start the debugger first
- Then set breakpoints in the running code
- Wait for "Debugger attached" message
- Open Chrome DevTools:
http://localhost:9222 - Set breakpoints directly in Chrome DevTools
- More reliable for frontend debugging
- Ensure breakpoints are in files that are actually bundled
- Check that the file path matches exactly (case-sensitive)
- Avoid breakpoints in files that aren't imported
- Stop the debugger completely
- Clear VS Code's debug cache:
Ctrl+Shift+Pβ "Debug: Clear Breakpoints" - Restart the debug session
- Set breakpoints again
If breakpoints still don't work:
// Add temporary logging
console.log('Debug point reached:', variableName);
debugger; // Force breakpointIf you see a white screen when launching "Debug Electron (Main + Renderer)":
# Clean and rebuild
rm -rf build/
npm run buildEnsure your .vscode/launch.json includes:
{
"name": "Debug Electron (Main + Renderer)",
"preLaunchTask": "npm: build",
"outFiles": ["${workspaceFolder}/build/**/*.js"],
"sourceMaps": true
}The app loads build/index.html via file protocol. Check:
build/index.htmlexists and has contentbuild/speedscope-*.jsfiles exist- No CORS errors in DevTools console
If still having issues, temporarily modify main.js:
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
preload: path.join(__dirname, 'preload.js'),
webSecurity: false, // Already set for development
allowRunningInsecureContent: true // Already set for development
}- Use "Debug Electron Main" instead of the combined option
- Run
npm run electron:devin terminal, then attach debugger - Use Chrome DevTools at
http://localhost:9222for renderer debugging
- Install Xcode Command Line Tools:
xcode-select --install - Install Node.js LTS (18+) and npm
- Run the app in dev:
npm run electron:dev - Build a signed/notarized app (optional): set mac signing env or edit
electron-builderconfig, thennpm run electron:build
- Install Node.js LTS (18+) and npm
- Install Visual Studio Build Tools (Desktop development with C++) from Microsoft (required by some native deps)
- Run the app in dev (PowerShell or CMD):
npm run electron:dev - Build an installer:
npm run electron:build
- Install system deps:
sudo apt update && sudo apt install -y libgtk-3-0 libnss3 libxss1 libasound2 libxtst6 libx11-xcb1 gconf-service libgbm1
- Install Node.js LTS (18+) and npm
- Run the app in dev:
npm run electron:dev - Build packages:
npm run electron:build(produces.AppImage/.debdepending on config)
| Feature | Web Version | Desktop App |
|---|---|---|
| Setup | β‘ Instant | π Fast |
| LLM Features | β Full | |
| Experience | Browser | Native |
- AI Analysis: Analyze profiling data with AI models
- Custom Prompts: Ask specific questions about your performance data
- Secure Authentication: OAuth integration with LLM providers
- Real-time Insights: Get instant analysis from your profiling data
Speedscope allows you to interactively explore profiling data to understand performance bottlenecks. The LLM integration provides AI-powered analysis and recommendations.
# Or manually
git clone https://github.com/whbernard/speedscope.git
cd speedscope
npm install
npm run electron:devnpm install -g speedscope
speedscope /path/to/profile.json"Command not found: npm"
- Install Node.js from nodejs.org
"Missing script: electron:dev"
cd speedscope
npm installDesktop app won't start
npm run dev # Use web version insteadPermission denied on Linux
sudo apt update && sudo apt install libwebkit2gtk-4.0-dev build-essentialConfigure OAuth/LLM entirely in code via the adapter methods shown below. You control the OAuth endpoint, fields (client_id_field, client_secret_field, grant_type, scope), and TLS (custom CA or disabled verification). For LLM, provide the endpoint, headers, and request_schema with {{profile_data}} and {{prompt}} placeholders.
This app configures OAuth/LLM entirely in code. Adjust these files to change behavior:
-
src/services/adapters.tsOAuthAdapter.requestToken(clientId, clientSecret, customConfig?)- Set/override:
endpoint,grant_type,scope,client_id_field,client_secret_field - TLS options (enable/disable CA verification):
tls.ca_pem(string PEM), ortls.ca_path(path to PEM)tls.disableCertValidation: boolean
- Set/override:
LLMAdapter.sendPrompt(prompt, profileData, accessToken?, customConfig?)- Provide:
endpoint,custom_headers, andrequest_schema request_schema.system[].textandmessages[].content[].textsupport{{profile_data}}and{{prompt}}
- Provide:
-
main.js(Electron backend)- OAuth IPC handler: search for
ipcMain.handle('oauth-request'to see required request fields and TLS handling - LLM IPC handler:
ipcMain.handle('llm-request'for how the payload is built and how{{profile_data}}is injected
- OAuth IPC handler: search for
Example: pass TLS and fields via adapters
// OAuth
await OAuthAdapter.requestToken(clientId, clientSecret, {
endpoint: 'https://oauth.example.com/token',
grant_type: 'client_credentials',
scope: 'api',
client_id_field: 'client_id',
client_secret_field: 'client_secret',
tls: {
// choose one of these:
// ca_pem: myCaPemString,
// ca_path: '/path/to/ca.pem',
// or disable verification for testing only
// disableCertValidation: true
}
})
// LLM
await LLMAdapter.sendPrompt(prompt, profileData, accessToken, {
endpoint: 'https://api.anthropic.com/v1/messages',
custom_headers: { Authorization: 'Bearer {{ACCESS_TOKEN}}' },
request_schema: {
messages: [{ role: 'user', content: [{ text: '{{prompt}}' }] }],
system: [{ text: 'You are a performance analysis expert.\n\nProfile data:\n{{profile_data}}' }],
inferenceConfig: { maxTokens: 2000, temperature: 0.7, topP: 0.9, stopSequences: [] }
}
})For detailed configuration and advanced usage, see the project documentation.