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

@xctrace-analyzer/core

v0.1.3

Published

Core analysis library for Xcode Instruments traces

Downloads

482

Readme

@xctrace-analyzer/core

Core analysis library for Xcode Instruments performance traces

A TypeScript library for parsing and analyzing Xcode Instruments .trace files, identifying Time Profiler bottlenecks, main-thread hangs, app-attributed user-code frames, and additional Memory, Network, Energy, Allocations, and Leaks findings.

Features

  • 📊 Parse Time Profiler traces from xctrace XML output
  • 🧭 Parse Memory, Network, Energy, Allocations, and Leaks tables when exportable
  • 🔍 Identify slow functions and performance bottlenecks
  • 🧊 Surface main-thread hang events without treating clean CPU thresholds as a global all-clear
  • 🎯 Attribute Time Profiler samples to Top User-Code Frames
  • 📈 Compare traces to detect performance regressions
  • 💡 Generate actionable optimization recommendations
  • 🎯 Pattern-based suggestion engine (image caching, async operations, etc.)
  • 🧾 Support status and export diagnostics for honest reporting

What The Core Package Does

The core package is the reusable analysis layer behind the MCP server. It does not speak MCP directly. It provides:

  • xctrace process utilities for recording, exporting TOCs, exporting XPath tables, and exporting HAR data
  • Capability detection and symbolication utilities for local xctrace
  • TraceParser for normalizing Xcode .trace XML/HAR data into typed TypeScript structures
  • PerformanceAnalyzer for Time Profiler statistics, bottlenecks, main-thread hang callouts, user-code frame attribution, and summaries
  • RecommendationEngine for CPU, memory, network, allocation, leak, and energy recommendations
  • ComparativeAnalyzer for Time Profiler baseline/current regression checks

Installation

npm install @xctrace-analyzer/core

For source development, run pnpm install --frozen-lockfile and pnpm build from the monorepo root.

Quick Start

import { analyzeTraceFile, compareTraceFiles } from '@xctrace-analyzer/core';

// Analyze a single trace
const analysis = await analyzeTraceFile('/path/to/app.trace', {
  slowThreshold: 100, // ms
  topN: 10,
  timeRangeMs: { startMs: 2000, endMs: 7000 },
  userBinaryHints: ['MyApp'],
});

console.log(analysis.summary);
console.log('Bottlenecks:', analysis.bottlenecks);
console.log('User-code frames:', analysis.userFrameProfiles);
console.log('Recommendations:', analysis.recommendations);

// Compare two traces
const comparison = await compareTraceFiles(
  '/path/to/baseline.trace',
  '/path/to/current.trace',
  undefined, // analysis options
  { regressionThreshold: 10 } // comparison options
);

console.log(comparison.summary);
console.log('Regressions:', comparison.regressions);
console.log('Improvements:', comparison.improvements);

API Reference

High-Level Functions

analyzeTraceFile(tracePath, options?)

Parse and analyze a trace file in one call.

Returns: Promise<Analysis>

Options:

interface AnalysisOptions {
  slowThreshold?: number;      // ms threshold for slow functions (default: 100)
  topN?: number;                // show top N functions (default: 10)
  includeRecommendations?: boolean; // generate recommendations (default: true)
  minCallCount?: number;        // minimum calls to consider (default: 1)
  timeRangeMs?: { startMs: number; endMs: number }; // trace-relative window
  userBinaryHints?: string[];    // app/module names for user-code attribution
}

compareTraceFiles(baselinePath, currentPath, analysisOptions?, comparisonOptions?)

Compare two trace files for regressions and improvements.

Returns: Promise<Comparison>

Comparison Options:

interface ComparisonOptions {
  failOnRegression?: boolean;       // reserved for MCP/CLI automation (default: false)
  regressionThreshold?: number;     // % increase to flag (default: 10)
  minDuration?: number;             // only compare functions > N ms (default: 10)
}

Core Classes

TraceParser

Parses xctrace XML output into structured data.

import { TraceParser } from '@xctrace-analyzer/core';

const parser = new TraceParser();
const parsed = await parser.parseTrace('/path/to/app.trace');

PerformanceAnalyzer

Analyzes parsed traces for bottlenecks.

import { PerformanceAnalyzer } from '@xctrace-analyzer/core';

const analyzer = new PerformanceAnalyzer();
const analysis = analyzer.analyze(parsedTrace, {
  slowThreshold: 100,
  topN: 10,
});

ComparativeAnalyzer

Compares two analyses to detect regressions.

import { ComparativeAnalyzer } from '@xctrace-analyzer/core';

const comparator = new ComparativeAnalyzer();
const comparison = comparator.compare(baselineAnalysis, currentAnalysis, {
  regressionThreshold: 10,
});

RecommendationEngine

Generates optimization recommendations.

import { RecommendationEngine } from '@xctrace-analyzer/core';

const engine = new RecommendationEngine();
const recommendations = engine.generateRecommendations(analysis);

Utilities

xctrace-runner

Utility functions for calling xctrace commands.

import {
  isXCTraceAvailable,
  getXCTraceVersion,
  exportTOC,
  exportTable,
  exportHAR,
  listTemplates,
  listDevices,
  getXCTraceCapabilities,
  recordTrace,
  symbolicateTrace,
} from '@xctrace-analyzer/core';

// Check availability
const available = await isXCTraceAvailable();

// List templates
const templates = await listTemplates();

// Export time profile data
const xml = await exportTable('/path/to/trace.trace', 'time-profile');

// Export network HAR data when available
const har = await exportHAR('/path/to/network.trace');

// Inspect local xctrace capabilities
const capabilities = await getXCTraceCapabilities();

// Record a running app with the Leaks template
await recordTrace({
  template: 'Leaks',
  processName: 'MyApp',
  duration: 60,
  outputPath: '/path/to/MyApp-leaks.trace',
});

// Symbolicate to a separate output trace before analysis
await symbolicateTrace({
  inputPath: '/path/to/app.trace',
  outputPath: '/path/to/app-symbolicated.trace',
  dsymPath: '/path/to/App.dSYM',
});

// Record one combined profiling trace
await recordTrace({
  template: 'Time Profiler',
  instruments: ['Leaks', 'Allocations', 'HTTP Traffic'],
  processName: 'MyApp',
  duration: 60,
  outputPath: '/path/to/MyApp-full.trace',
});

recordTrace intentionally uses execFile argument arrays rather than shell command strings. This keeps paths and process names safe even when they contain spaces.

Data Types

Analysis

Complete analysis result for a trace.

interface Analysis {
  metadata: TraceMetadata;
  stats: PerformanceStats;
  bottlenecks: Bottleneck[];
  recommendations: Recommendation[];
  topFunctions: FunctionProfile[];
  userFrameProfiles?: UserFrameProfile[];
  instrumentAnalyses: InstrumentAnalysis[];
  hangs?: HangsData;
  supportStatus?: AnalysisSupportStatus[];
  exportAttempts?: ExportAttempt[];
  summary: string;
}

UserFrameProfile

App-attributed Time Profiler frame. The analyzer walks each sample backtrace from leaf to root and aggregates the deepest frame whose module matches TOC-derived user process names or userBinaryHints.

interface UserFrameProfile {
  name: string;
  module?: string;
  selfTime: number;
  sampleCount: number;
  percentage: number;
}

InstrumentAnalysis

Normalized analysis for non-Time-Profiler instruments.

interface InstrumentAnalysis {
  kind: 'time-profile' | 'memory' | 'network' | 'energy' | 'allocations' | 'leaks';
  title: string;
  summary: string;
  metrics: InstrumentMetric[];
  findings: InstrumentFinding[];
  sourceSchemas: string[];
}

Comparison

Result of comparing two traces.

interface Comparison {
  baseline: Analysis;
  current: Analysis;
  delta: PerformanceDelta;
  regressions: Regression[];
  improvements: Improvement[];
  hasRegression: boolean;
  hasCriticalRegression: boolean;
  summary: string;
}

Bottleneck

A performance bottleneck identified in the trace.

interface Bottleneck {
  function: string;
  module?: string;
  impact: 'critical' | 'high' | 'medium' | 'low';
  duration: number;          // milliseconds
  percentage: number;        // % of total time
  suggestion: string;
  callCount?: number;
}

Recommendation

An actionable optimization recommendation.

interface Recommendation {
  type: 'optimization' | 'architecture' | 'caching' | 'async' | 'memory' | 'algorithm';
  priority: 'high' | 'medium' | 'low';
  title: string;
  description: string;
  affectedFunctions: string[];
  potentialImprovement: string;
  codeExample?: string;      // Swift code example
}

Examples

Basic Analysis

import { analyzeTraceFile } from '@xctrace-analyzer/core';

async function analyzeApp() {
  const analysis = await analyzeTraceFile('./app.trace', {
    slowThreshold: 100,
    topN: 5,
  });

  console.log(`\n📊 Analysis Summary:`);
  console.log(analysis.summary);

  console.log(`\n🐌 Slow Functions:`);
  for (const bottleneck of analysis.bottlenecks.slice(0, 3)) {
    console.log(`- ${bottleneck.function}: ${bottleneck.duration.toFixed(0)}ms`);
    console.log(`  💡 ${bottleneck.suggestion}`);
  }

  console.log(`\n💡 Top Recommendations:`);
  for (const rec of analysis.recommendations.slice(0, 3)) {
    console.log(`\n${rec.title} (${rec.priority} priority)`);
    console.log(rec.description);
    console.log(`Potential improvement: ${rec.potentialImprovement}`);
  }
}

analyzeApp().catch(console.error);

Regression Detection

import { compareTraceFiles } from '@xctrace-analyzer/core';

async function checkRegression() {
  try {
    const comparison = await compareTraceFiles(
      './baseline.trace',
      './current.trace',
      undefined,
      {
        regressionThreshold: 15, // fail if >15% slower
      }
    );

    console.log(comparison.summary);

    if (comparison.regressions.length > 0) {
      console.log('\n⚠️ Regressions found:');
      for (const reg of comparison.regressions) {
        console.log(
          `- ${reg.function}: ` +
          `${reg.baselineTime.toFixed(0)}ms → ${reg.currentTime.toFixed(0)}ms ` +
          `(+${reg.percentageIncrease.toFixed(0)}%)`
        );
      }
      process.exit(1); // Fail CI
    }

    console.log('\n✅ No significant regressions');
  } catch (error) {
    console.error('Regression detected!', error);
    process.exit(1);
  }
}

checkRegression();

Custom Analysis Pipeline

import {
  TraceParser,
  PerformanceAnalyzer,
  RecommendationEngine,
} from '@xctrace-analyzer/core';

async function customAnalysis() {
  // Step 1: Parse
  const parser = new TraceParser();
  const trace = await parser.parseTrace('./app.trace');

  console.log(`Parsed ${trace.metadata.fileName}`);
  console.log(`Duration: ${trace.metadata.duration}ms`);

  // Step 2: Analyze
  const analyzer = new PerformanceAnalyzer();
  const analysis = analyzer.analyze(trace, {
    slowThreshold: 50, // Lower threshold
    topN: 20,          // More functions
  });

  // Step 3: Generate recommendations
  const engine = new RecommendationEngine();
  analysis.recommendations = engine.generateRecommendations(analysis);

  // Step 4: Custom reporting
  const criticalBottlenecks = analysis.bottlenecks.filter(
    b => b.impact === 'critical'
  );

  if (criticalBottlenecks.length > 0) {
    console.error('🔴 Critical performance issues found!');
    for (const b of criticalBottlenecks) {
      console.error(`- ${b.function}: ${b.duration}ms`);
    }
  }

  return analysis;
}

customAnalysis();

Requirements

  • macOS with Xcode Command Line Tools installed
  • Node.js 18+
  • xctrace command-line tool (included with Xcode)
  • Time Profiler, Memory, Network, Energy, Allocations, or Leaks .trace files. Availability depends on which tables xcrun xctrace export --toc exposes for the trace.

Error Handling

The library provides specific error types:

import {
  TraceParserError,
  XCTraceError,
  AnalysisError,
} from '@xctrace-analyzer/core';

try {
  const analysis = await analyzeTraceFile('./nonexistent.trace');
} catch (error) {
  if (error instanceof TraceParserError) {
    console.error('Failed to parse trace:', error.message);
  } else if (error instanceof XCTraceError) {
    console.error('xctrace command failed:', error.message);
    console.error('Exit code:', error.exitCode);
  } else if (error instanceof AnalysisError) {
    console.error('Analysis failed:', error.message);
  }
}

Production Notes

  • This package analyzes data that xcrun xctrace export exposes through TOC, XPath, and HAR exports.
  • It reports data that is not present in the trace or not exportable explicitly instead of assuming Instruments.app GUI parity.
  • Large-trace streaming and broader template coverage are tracked as production hardening work, not current guarantees.

License

MIT

Contributing

See the main repository README for contribution guidelines.