bsprof-cli
v1.0.0
Published
CLI tool for parsing and analyzing BrightScript Profiler (.bsprof) files
Maintainers
Readme
bsprof-cli
CLI tool for parsing and analyzing BrightScript Profiler (.bsprof) files from Roku devices.
Supports memory leak detection, CPU hot-path analysis, profile comparison, and multiple export formats including Chrome DevTools traces.
Getting a .bsprof File
To generate a profiling file from your Roku device:
- Enable the profiler in your app's
manifestfile:bs_prof_enabled=true - Sideload and run your app on the Roku device.
- Download the profile via the developer console at
http://<roku-ip>:8080under the Profiler section, or retrieve it programmatically from the device's profiling endpoint.
The resulting .bsprof file contains binary-encoded CPU and memory profiling data that this tool decodes and analyzes.
For full details on the file format, see the Roku BrightScript Profiler specification.
Installation
npm install -g bsprof-cli
# or run directly
npx bsprof-cli analyze memory ./profile.bsprofCommands
bsprof analyze <mode> <file>
Analyze a .bsprof file. Modes:
| Mode | Description |
|------|-------------|
| memory | Memory allocation analysis -- retained bytes, leak detection |
| cpu | CPU time analysis -- self time, wall time, hot functions |
| full | Combined memory + CPU report |
| summary | One-page overview with key metrics |
# Memory analysis with top 20 leaks
bsprof analyze memory profile.bsprof --top 20
# CPU analysis sorted by wall time, JSON output
bsprof analyze cpu profile.bsprof --sort wallSelf --format json
# Full report filtered to a specific module
bsprof analyze full profile.bsprof --filter-module "My App"
# Summary written to a file
bsprof analyze summary profile.bsprof --output report.txtOptions
| Flag | Default | Description |
|------|---------|-------------|
| --format <fmt> | text | Output format: text, json, markdown |
| --top <n> | 30 | Number of entries in ranked lists |
| --sort <field> | varies | Sort field: retained, allocated, allocCount, cpuSelf, wallSelf, callCount |
| --filter-module <name> | -- | Filter results to a specific module/thread |
| --filter-file <glob> | -- | Filter results to files matching glob |
| --exclude-module <name> | -- | Exclude a module (e.g. roku_ads_lib) |
| --threshold <bytes> | 0 | Only show entries exceeding threshold |
| --output <path> | stdout | Write output to file |
bsprof compare <file1> <file2>
Diff two profiles to detect regressions or verify fixes.
bsprof compare before.bsprof after.bsprof
bsprof compare before.bsprof after.bsprof --format json --output diff.jsonOutput includes:
- Delta in retained bytes per function (positive = regression, negative = improvement)
- New leak sources (functions that appear only in the "after" profile)
- Resolved leaks (functions in "before" but not "after")
- CPU time deltas
bsprof info <file>
Print header metadata without full parsing.
bsprof info profile.bsprofTarget: My App v2.0.1
Device: Roku Ultra (14.0.0)
Format: v3.0.0
Size: 42.3 MB
Features: line-specific-data, memory-operationsbsprof export <file>
Export parsed data for external tools.
# Chrome DevTools trace (open in chrome://tracing or Perfetto)
bsprof export profile.bsprof --format chrome-trace --output trace.json
# CSV for spreadsheets
bsprof export profile.bsprof --format csv --output data.csv
# Full JSON
bsprof export profile.bsprof --format json --output full.json| Format | Description |
|--------|-------------|
| chrome-trace | Chrome DevTools trace (viewable in chrome://tracing or Perfetto) |
| csv | Flat CSV for spreadsheet analysis |
| json | Structured JSON with full analysis data |
Programmatic API
The package also exports a library for use in other tools (e.g. MCP servers):
import { readFileSync } from 'fs';
import { parseBsprof, analyzeMemory, analyzeCpu, compareBsprof } from 'bsprof-cli';
// Parse raw binary
const profile = parseBsprof(readFileSync('profile.bsprof'));
// Memory analysis
const memoryReport = analyzeMemory(profile, { top: 20, sortBy: 'retained' });
// CPU analysis
const cpuReport = analyzeCpu(profile, { top: 20, sortBy: 'cpuSelf' });
// Compare two profiles
const before = parseBsprof(readFileSync('before.bsprof'));
const after = parseBsprof(readFileSync('after.bsprof'));
const diff = compareBsprof(before, after, 'before.bsprof', 'after.bsprof');Example Output
Memory analysis (bsprof analyze memory profile.bsprof --top 5)
=== My Roku App v2.0.1 ===
Device: Roku Ultra (14.0.0) | Format: v3.0.0 | Size: 42.3 MB
=== MEMORY SUMMARY ===
Total Allocated: 93.7 MB
Total Freed: 86.9 MB
Total Retained: 6.8 MB
Alloc Count: 1,240,000
Free Count: 1,180,000
=== MEMORY BY MODULE/THREAD ===
Module Alloc Free Retained Allocs# Frees#
------------------------------------------------------------------------------------------------------------------------
My Roku App 50.0 MB 43.7 MB 6.3 MB 800,000 750,000
roku_ads_lib 43.7 MB 43.2 MB 524.3 KB 440,000 430,000
=== TOP 5 MEMORY BY FUNCTION (retained bytes) ===
# Retained Alloc Free Ops Calls CPU Self Wall Self Function / File
-------------------------------------------------------------------------------------------
1 6.6 MB 6.9 MB 307.2 KB 14,000 14,000 0us 0us analytics_track (pkg:/source/analytics.brs)
2 204.8 KB 819.2 KB 614.4 KB 2,000 2,000 0us 0us ui_render_list (pkg:/source/ui/list.brs)
3 102.4 KB 512.0 KB 409.6 KB 1,500 1,500 0us 0us network_fetch (pkg:/source/net/http.brs)
4 51.2 KB 256.0 KB 204.8 KB 800 800 0us 0us parse_response (pkg:/source/net/parser.brs)
5 25.6 KB 128.0 KB 102.4 KB 400 400 0us 0us cache_store (pkg:/source/cache.brs)CPU analysis (bsprof analyze cpu profile.bsprof --top 3)
=== TOP 3 CPU BY FUNCTION ===
# CPU Self Wall Self Calls Function / File
----------------------------------------------------------------
1 1.2s 3.4s 14,000 analytics_track (pkg:/source/analytics.brs)
← init_analytics (pkg:/source/main.brs:42)
← main (pkg:/source/main.brs:10)
2 800.0ms 2.1s 2,000 ui_render_list (pkg:/source/ui/list.brs)
← on_focus (pkg:/source/ui/screen.brs:88)
3 450.0ms 1.8s 1,500 network_fetch (pkg:/source/net/http.brs)CPU output includes reconstructed call stacks showing the caller chain for each hot function.
Architecture
src/
├── parser/
│ ├── types.ts # Shared interfaces (ParsedProfile, reports, etc.)
│ ├── varint.ts # LEB128 varint decoder / buffer reader
│ └── BsprofParser.ts # Core binary parser for the .bsprof format
├── analyzer/
│ ├── common.ts # Header info / parse stats builders
│ ├── Aggregator.ts # Group-by module/file/function with filtering
│ ├── MemoryAnalyzer.ts # Retained bytes, leak detection
│ ├── CpuAnalyzer.ts # Self-time ranking, call-path reconstruction
│ └── DiffAnalyzer.ts # Two-profile comparison (regressions/improvements)
├── formatter/
│ ├── helpers.ts # Formatting utils (bytes, time, numbers)
│ ├── TextFormatter.ts # Colored terminal tables
│ ├── JsonFormatter.ts # Structured JSON output
│ ├── MarkdownFormatter.ts # Markdown tables
│ ├── ChromeTraceExporter.ts # Chrome DevTools trace format
│ └── CsvExporter.ts # Flat CSV export
├── index.ts # CLI entry point (commander)
└── lib.ts # Programmatic API for library consumersData flows through three layers:
- Parser -- reads the binary
.bsproffile and produces aParsedProfilewith raw maps of strings, modules, path elements, memory records, and CPU records. - Analyzers -- aggregate the raw data by module/file/function, apply filters, compute retained bytes, detect leaks, rank hot paths, and diff two profiles.
- Formatters -- render analysis results as terminal text (with colors), JSON, Markdown, Chrome traces, or CSV.
.bsprof Format
This tool parses the BrightScript Profiler binary format (v3.0.0) as specified in the Roku developer documentation.
Supported entry types:
- String table entries
- Executable module entries
- Path elements (root and chained)
- Memory operations (alloc, free, free_realloc) with address tracking
- CPU measurements (cpu cycles, wall clock time)
- Path call count entries
License
MIT
