CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-fluidframework--common-utils

Collection of utility functions for Fluid Framework including async operations, data structures, performance monitoring, and cross-platform compatibility.

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

performance-monitoring.mddocs/

Performance & Monitoring

Performance measurement and tracing utilities for monitoring application performance with cross-platform support and detailed timing information.

Capabilities

Isomorphic Performance

Cross-platform performance measurement with unified API across Node.js and Browser environments.

/**
 * Isomorphic performance interface with optional browser Performance properties
 * Provides core timing methods that work consistently across environments
 */
interface IsomorphicPerformance {
  /** Returns high-resolution timestamp in milliseconds */
  now(): number;
  
  /** Creates a named performance mark at the current time */
  mark(name: string): void;
  
  /** 
   * Creates a performance measure between two marks or from a mark to now
   * @param name - Name for the measure
   * @param startMark - Optional start mark name (uses navigation start if omitted)
   * @param endMark - Optional end mark name (uses current time if omitted)
   */
  measure(name: string, startMark?: string, endMark?: string): void;
  
  /** 
   * Clears performance marks
   * @param name - Optional mark name (clears all marks if omitted)
   */
  clearMarks(name?: string): void;
  
  /** Additional browser-specific properties (when available) */
  clearMeasures?(name?: string): void;
  getEntries?(): PerformanceEntryList;
  getEntriesByName?(name: string, type?: string): PerformanceEntryList;
  getEntriesByType?(type: string): PerformanceEntryList;
}

/**
 * Reference to globalThis.performance with isomorphic typing
 * Works in both Node.js (with perf_hooks) and Browser environments
 */
declare const performance: IsomorphicPerformance;

Usage Examples:

import { performance } from "@fluidframework/common-utils";

// Basic timing
const start = performance.now();
await someAsyncOperation();
const end = performance.now();
console.log(`Operation took ${end - start} milliseconds`);

// Performance marks and measures
performance.mark("operation-start");
await performHeavyComputation();
performance.mark("operation-end");

// Create measure between marks
performance.measure("heavy-computation", "operation-start", "operation-end");

// Clear marks when done
performance.clearMarks();

// Benchmarking utility
class Benchmark {
  private marks = new Map<string, number>();
  
  start(name: string): void {
    this.marks.set(name, performance.now());
    performance.mark(`${name}-start`);
  }
  
  end(name: string): number {
    const startTime = this.marks.get(name);
    if (!startTime) {
      throw new Error(`No start mark found for: ${name}`);
    }
    
    const endTime = performance.now();
    const duration = endTime - startTime;
    
    performance.mark(`${name}-end`);
    performance.measure(name, `${name}-start`, `${name}-end`);
    
    this.marks.delete(name);
    return duration;
  }
  
  time<T>(name: string, fn: () => T): T;
  time<T>(name: string, fn: () => Promise<T>): Promise<T>;
  time<T>(name: string, fn: () => T | Promise<T>): T | Promise<T> {
    this.start(name);
    
    try {
      const result = fn();
      
      if (result instanceof Promise) {
        return result.finally(() => {
          const duration = this.end(name);
          console.log(`${name}: ${duration.toFixed(2)}ms`);
        });
      } else {
        const duration = this.end(name);
        console.log(`${name}: ${duration.toFixed(2)}ms`);
        return result;
      }
    } catch (error) {
      this.end(name); // Ensure cleanup
      throw error;
    }
  }
}

// Usage
const benchmark = new Benchmark();

const result = await benchmark.time("database-query", async () => {
  return await fetchDataFromDatabase();
});

const computed = benchmark.time("computation", () => {
  return heavyMathOperation();
});

Trace Class

Performance tracing helper with detailed timing information and tick counting.

/**
 * Trace event containing detailed timing information
 */
interface ITraceEvent {
  /** Total time elapsed since trace creation in milliseconds */
  totalTimeElapsed: number;
  
  /** Duration since last trace() call in milliseconds */
  duration: number;
  
  /** Number of times trace() has been called */
  tick: number;
}

/**
 * Performance tracing helper for detailed operation monitoring
 * Tracks cumulative time and provides incremental timing information
 */
class Trace {
  /**
   * Creates and starts a new trace
   * @returns New Trace instance ready for timing
   */
  static start(): Trace;
  
  /**
   * Records a trace event and returns timing information
   * @returns Trace event with current timing data
   */
  trace(): ITraceEvent;
}

Usage Examples:

import { Trace } from "@fluidframework/common-utils";

// Basic tracing
const trace = Trace.start();

// Perform operations and trace progress
await step1();
const event1 = trace.trace();
console.log(`Step 1: ${event1.duration}ms (total: ${event1.totalTimeElapsed}ms, tick: ${event1.tick})`);

await step2();
const event2 = trace.trace();
console.log(`Step 2: ${event2.duration}ms (total: ${event2.totalTimeElapsed}ms, tick: ${event2.tick})`);

await step3();
const event3 = trace.trace();
console.log(`Step 3: ${event3.duration}ms (total: ${event3.totalTimeElapsed}ms, tick: ${event3.tick})`);

// Pipeline performance monitoring
class PipelineTracer {
  private trace: Trace;
  private stepName: string = "";
  
  start(name: string): this {
    this.trace = Trace.start();
    this.stepName = name;
    console.log(`Starting pipeline: ${name}`);
    return this;
  }
  
  step(stepName: string): this {
    if (!this.trace) {
      throw new Error("Trace not started");
    }
    
    const event = this.trace.trace();
    console.log(`${this.stepName} - ${stepName}: ${event.duration.toFixed(2)}ms (cumulative: ${event.totalTimeElapsed.toFixed(2)}ms)`);
    return this;
  }
  
  finish(): ITraceEvent {
    if (!this.trace) {
      throw new Error("Trace not started");
    }
    
    const finalEvent = this.trace.trace();
    console.log(`${this.stepName} completed: ${finalEvent.totalTimeElapsed.toFixed(2)}ms total, ${finalEvent.tick} steps`);
    return finalEvent;
  }
}

// Usage
const tracer = new PipelineTracer();

await tracer
  .start("Data Processing Pipeline")
  .step("Load data");

await processData();
tracer.step("Process data");

await validateResults();
tracer.step("Validate results");

await saveResults();
const finalEvent = tracer.finish();

// Trace with conditional logging
class ConditionalTracer {
  private trace: Trace | null = null;
  private enabled: boolean;
  
  constructor(enabled: boolean = false) {
    this.enabled = enabled;
  }
  
  start(): void {
    if (this.enabled) {
      this.trace = Trace.start();
    }
  }
  
  checkpoint(name: string): ITraceEvent | null {
    if (!this.enabled || !this.trace) {
      return null;
    }
    
    const event = this.trace.trace();
    console.log(`Checkpoint ${name}: ${event.duration.toFixed(2)}ms`);
    return event;
  }
  
  enable(): void {
    this.enabled = true;
  }
  
  disable(): void {
    this.enabled = false;
    this.trace = null;
  }
}

// Debug mode tracing
const DEBUG = process.env.NODE_ENV === "development";
const debugTracer = new ConditionalTracer(DEBUG);

debugTracer.start();
await operation1();
debugTracer.checkpoint("Operation 1");

await operation2();
debugTracer.checkpoint("Operation 2");

Advanced Monitoring Patterns

Performance Profiler

import { Trace, performance } from "@fluidframework/common-utils";

class PerformanceProfiler {
  private profiles = new Map<string, {
    count: number;
    totalTime: number;
    minTime: number;
    maxTime: number;
    avgTime: number;
  }>();
  
  profile<T>(name: string, fn: () => T): T;
  profile<T>(name: string, fn: () => Promise<T>): Promise<T>;
  profile<T>(name: string, fn: () => T | Promise<T>): T | Promise<T> {
    const start = performance.now();
    
    const updateStats = (duration: number) => {
      const existing = this.profiles.get(name) || {
        count: 0,
        totalTime: 0,
        minTime: Infinity,
        maxTime: 0,
        avgTime: 0
      };
      
      existing.count++;
      existing.totalTime += duration;
      existing.minTime = Math.min(existing.minTime, duration);
      existing.maxTime = Math.max(existing.maxTime, duration);
      existing.avgTime = existing.totalTime / existing.count;
      
      this.profiles.set(name, existing);
    };
    
    try {
      const result = fn();
      
      if (result instanceof Promise) {
        return result.finally(() => {
          const duration = performance.now() - start;
          updateStats(duration);
        });
      } else {
        const duration = performance.now() - start;
        updateStats(duration);
        return result;
      }
    } catch (error) {
      const duration = performance.now() - start;
      updateStats(duration);
      throw error;
    }
  }
  
  getStats(name?: string) {
    if (name) {
      return this.profiles.get(name);
    }
    return Object.fromEntries(this.profiles);
  }
  
  reset(name?: string): void {
    if (name) {
      this.profiles.delete(name);
    } else {
      this.profiles.clear();
    }
  }
  
  report(): void {
    console.log("\n=== Performance Report ===");
    for (const [name, stats] of this.profiles) {
      console.log(`${name}:`);
      console.log(`  Calls: ${stats.count}`);
      console.log(`  Total: ${stats.totalTime.toFixed(2)}ms`);
      console.log(`  Avg: ${stats.avgTime.toFixed(2)}ms`);
      console.log(`  Min: ${stats.minTime.toFixed(2)}ms`);
      console.log(`  Max: ${stats.maxTime.toFixed(2)}ms`);
      console.log();
    }
  }
}

// Usage
const profiler = new PerformanceProfiler();

// Profile individual operations
for (let i = 0; i < 100; i++) {
  await profiler.profile("database-read", () => readFromDatabase());
  await profiler.profile("cache-write", () => writeToCache());
}

// Get performance statistics
profiler.report();

Real-time Performance Monitor

import { Trace, performance } from "@fluidframework/common-utils";

class RealTimeMonitor {
  private activeTraces = new Map<string, Trace>();
  private thresholds = new Map<string, number>();
  private onSlowOperation?: (name: string, duration: number) => void;
  
  setThreshold(operation: string, thresholdMs: number): void {
    this.thresholds.set(operation, thresholdMs);
  }
  
  onSlow(callback: (name: string, duration: number) => void): void {
    this.onSlowOperation = callback;
  }
  
  startMonitoring(name: string): void {
    this.activeTraces.set(name, Trace.start());
  }
  
  stopMonitoring(name: string): number | null {
    const trace = this.activeTraces.get(name);
    if (!trace) return null;
    
    const event = trace.trace();
    this.activeTraces.delete(name);
    
    const threshold = this.thresholds.get(name);
    if (threshold && event.totalTimeElapsed > threshold) {
      this.onSlowOperation?.(name, event.totalTimeElapsed);
    }
    
    return event.totalTimeElapsed;
  }
  
  monitor<T>(name: string, fn: () => T): T;
  monitor<T>(name: string, fn: () => Promise<T>): Promise<T>;
  monitor<T>(name: string, fn: () => T | Promise<T>): T | Promise<T> {
    this.startMonitoring(name);
    
    try {
      const result = fn();
      
      if (result instanceof Promise) {
        return result.finally(() => {
          this.stopMonitoring(name);
        });
      } else {
        this.stopMonitoring(name);
        return result;
      }
    } catch (error) {
      this.stopMonitoring(name);
      throw error;
    }
  }
}

// Usage
const monitor = new RealTimeMonitor();

// Set performance thresholds
monitor.setThreshold("api-call", 1000); // 1 second
monitor.setThreshold("db-query", 500);  // 500ms

// Handle slow operations
monitor.onSlow((name, duration) => {
  console.warn(`Slow operation detected: ${name} took ${duration.toFixed(2)}ms`);
});

// Monitor operations
await monitor.monitor("api-call", () => fetchFromAPI());
await monitor.monitor("db-query", () => queryDatabase());

These performance monitoring utilities provide comprehensive tools for measuring, tracking, and optimizing application performance in Fluid Framework applications.

docs

assertions.md

async-operations.md

buffer-operations.md

data-structures.md

encoding-hashing.md

event-handling.md

index.md

performance-monitoring.md

utility-functions.md

tile.json