npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@flamedeck/import

v0.1.0

Published

Speedscope import utilities for parsing various performance profile formats

Readme

@flamedeck/import

Import any support profile into the standard speedscope format.

Installation

npm install @flamedeck/import

Usage

import { importProfile } from '@flamedeck/import';
import { readFileSync } from 'fs';

// Import from a file (automatically detects format)
const profileData = readFileSync('profile.cpuprofile', 'utf8');
const result = await importProfile(profileData, 'profile.cpuprofile');

// Or import from binary data
const binaryData = readFileSync('profile.pprof'); 
const result = await importProfile(binaryData, 'profile.pprof');

// Access the parsed profile
if (result.profileGroup) {
  console.log('Profile type:', result.profileType);
  console.log('Number of profiles:', result.profileGroup.profiles.length);
  
  const profile = result.profileGroup.profiles[0];
  console.log('Profile name:', profile.name);
  console.log('Duration:', profile.duration, 'ms');
  console.log('Frames:', profile.frames.length);
  console.log('Samples:', profile.samples.length);
}

Supported Formats

This package supports all the same formats as Speedscope:

  • Chrome DevTools CPU Profiles (.cpuprofile)
  • Firefox Profiler format
  • Node.js profiles
  • pprof format (Go, C++, etc.)
  • Stackprof (Ruby)
  • Instruments (macOS)
  • Perf (Linux)
  • And many more...

API

importProfile(input: string | ArrayBuffer | Buffer, fileName: string): Promise<ImportResult>

Imports a performance profile from various input types, automatically detecting the format and setting up Node.js dependencies.

  • input: Profile data as string (for JSON formats), ArrayBuffer, or Node.js Buffer
  • fileName: The original filename (used for format detection)
  • Returns: A Promise that resolves to an ImportResult object

ImportResult

interface ImportResult {
  profileGroup: ProfileGroup | null;
  profileType: ProfileType;
}
ProfileGroup

When parsing succeeds, profileGroup contains:

interface ProfileGroup {
  name: string;           // Name of the profile group
  indexToView: number;    // Index of the profile to view by default (usually 0)
  profiles: Profile[];    // Array of parsed profiles
}
Profile

Each profile in the group provides comprehensive performance data:

class Profile {
  // Basic information
  getName(): string;                    // Profile name
  getTotalWeight(): number;             // Total execution time/samples
  getTotalNonIdleWeight(): number;      // Total time excluding idle
  getWeightUnit(): ValueUnit;           // Units ('nanoseconds', 'milliseconds', etc.)
  formatValue(value: number): string;   // Format a value with units
  
  // Call tree analysis
  getAppendOrderCalltreeRoot(): CallTreeNode;   // Raw call order tree
  getGroupedCalltreeRoot(): CallTreeNode;       // Grouped/sorted call tree
  
  // Frame and sample data
  forEachFrame(fn: (frame: Frame) => void): void;     // Iterate over all frames
  forEachCall(openFrame, closeFrame): void;           // Walk call timeline
  forEachCallGrouped(openFrame, closeFrame): void;    // Walk grouped calls
  
  // Analysis methods
  getProfileWithRecursionFlattened(): Profile;                    // Remove recursion
  getInvertedProfileForCallersOf(frame: FrameInfo): Profile;     // Caller analysis
  getProfileForCalleesOf(frame: FrameInfo): Profile;             // Callee analysis
}
Frame

Individual stack frames contain:

interface FrameInfo {
  key: string | number;    // Unique identifier
  name: string;            // Function/method name
  file?: string;           // Source file path
  line?: number;           // Line number (1-based)
  col?: number;            // Column number (1-based)
}

class Frame extends FrameInfo {
  getSelfWeight(): number;     // Time spent in this frame only
  getTotalWeight(): number;    // Time spent in frame + children
}
ProfileType

The detected profile format, one of:

  • 'speedscope' - Native Speedscope format
  • 'chrome-cpuprofile' - Chrome DevTools CPU Profile
  • 'chrome-timeline' - Chrome Timeline/Tracing format
  • 'chrome-heap-profile' - Chrome Heap Profile
  • 'pprof' - Protocol buffer format (Go, C++, etc.)
  • 'firefox' - Firefox Profiler format
  • 'safari' - Safari profiler format
  • 'stackprof' - Ruby Stackprof format
  • 'instruments-deepcopy' - macOS Instruments text export
  • 'instruments-trace' - macOS Instruments trace directory
  • 'linux-perf' - Linux perf script output
  • 'collapsed-stack' - Collapsed stack format
  • 'v8-prof-log' - V8 profiler log format
  • 'haskell' - Haskell GHC profiler format
  • 'trace-event' - Generic trace event format
  • 'callgrind' - Valgrind Callgrind format
  • 'papyrus' - Papyrus profiler format
  • 'unknown' - Could not detect format

Advanced Usage

Analyzing Call Performance

import { importProfile } from '@flamedeck/import';
import { readFileSync } from 'fs';

const profileData = readFileSync('profile.cpuprofile', 'utf8');
const result = await importProfile(profileData, 'profile.cpuprofile');

if (result.profileGroup) {
  const profile = result.profileGroup.profiles[0];
  
  // Get basic metrics
  console.log('Total execution time:', profile.formatValue(profile.getTotalWeight()));
  console.log('Time units:', profile.getWeightUnit());
  
  // Analyze individual frames
  const hotFrames = [];
  profile.forEachFrame(frame => {
    if (frame.getSelfWeight() > 1000) { // Frames with >1000 units of self time
      hotFrames.push({
        name: frame.name,
        selfTime: frame.getSelfWeight(),
        totalTime: frame.getTotalWeight(),
        file: frame.file,
        line: frame.line
      });
    }
  });
  
  // Sort by self time (hottest first)
  hotFrames.sort((a, b) => b.selfTime - a.selfTime);
  console.log('Hottest functions:', hotFrames.slice(0, 10));
}

Walking the Call Tree

const profile = result.profileGroup.profiles[0];

// Walk the timeline in execution order
profile.forEachCall(
  (node, startTime) => {
    console.log(`${startTime}ms: Entering ${node.frame.name}`);
  },
  (node, endTime) => {
    console.log(`${endTime}ms: Exiting ${node.frame.name}`);
  }
);

// Walk the grouped/sorted call tree (for flamegraph-like analysis)
profile.forEachCallGrouped(
  (node, startTime) => {
    const selfTime = node.getSelfWeight();
    const totalTime = node.getTotalWeight();
    console.log(`${node.frame.name}: ${selfTime}ms self, ${totalTime}ms total`);
  },
  (node, endTime) => {
    // Frame completed
  }
);

Caller/Callee Analysis

// Find who calls a specific function
const targetFrame = { key: 'myFunction', name: 'myFunction' };
const callerProfile = profile.getInvertedProfileForCallersOf(targetFrame);
console.log('Functions that call myFunction:');
callerProfile.forEachFrame(frame => {
  console.log(`${frame.name}: ${frame.getTotalWeight()}ms`);
});

// Find what a function calls
const calleeProfile = profile.getProfileForCalleesOf(targetFrame);
console.log('Functions called by myFunction:');
calleeProfile.forEachFrame(frame => {
  console.log(`${frame.name}: ${frame.getTotalWeight()}ms`);
});

Flattening Recursion

// Remove recursive calls for cleaner analysis
const flatProfile = profile.getProfileWithRecursionFlattened();
console.log('Profile with recursion flattened:');
console.log('Total time:', flatProfile.formatValue(flatProfile.getTotalWeight()));

Related Packages

License

ISC

Development

Generating Protobuf Code

This package includes importers for pprof (protobuf) formatted profiles. The TypeScript code for handling these protobuf definitions is generated from a .proto schema file.

If you modify packages/speedscope-import/src/speedscope-import/profile.proto, you will need to regenerate the corresponding TypeScript file (profile.proto.ts) using the following command from the workspace root:

npx pbjs --ts packages/speedscope-import/src/speedscope-import/profile.proto.ts packages/speedscope-import/src/speedscope-import/profile.proto

This command uses pbjs (from protobufjs-cli) to convert the .proto file directly into a TypeScript module that includes both the runtime logic and type definitions for the protobuf messages.

Prerequisites:

  • Ensure protobufjs-cli is available. You can install it globally (npm install -g protobufjs-cli) or add it as a dev dependency to the workspace root and run via npx pbjs ....