ObsiViewer/docs/PERFORMENCE/phase4/PHASE4_CONFIGURATION.md

11 KiB

Phase 4 - Configuration & Tuning Guide

Overview

Phase 4 provides multiple configuration options to optimize for different use cases and environments.

Service Configurations

1. ClientCacheService

Memory Cache

Default: 50 items, 30-minute TTL

// In client-cache.service.ts
private readonly maxMemoryItems = 50;

// Usage
cache.setMemory(key, value, 30 * 60 * 1000); // 30 minutes

Tuning:

// For low-memory devices
private readonly maxMemoryItems = 25;

// For high-memory devices
private readonly maxMemoryItems = 100;

// For high-traffic scenarios
private readonly maxMemoryItems = 150;

Persistent Cache

Default: 200 items, LRU eviction

// In client-cache.service.ts
private readonly maxPersistentItems = 200;

Tuning:

// For mobile
private readonly maxPersistentItems = 50;

// For desktop
private readonly maxPersistentItems = 500;

// For high-traffic
private readonly maxPersistentItems = 1000;

TTL Configuration

Choose appropriate TTLs based on update frequency:

// Frequently updated content (5 minutes)
cache.setMemory(`note_${id}`, content, 5 * 60 * 1000);

// Standard content (30 minutes)
cache.setMemory(`note_${id}`, content, 30 * 60 * 1000);

// Rarely updated content (1 hour)
cache.setMemory(`note_${id}`, content, 60 * 60 * 1000);

// Very stable content (2 hours)
cache.setMemory(`note_${id}`, content, 2 * 60 * 60 * 1000);

2. NotePreloaderService

Preload Distance

How many notes to preload on each side of current note:

// In note-preloader.service.ts
private preloadConfig = {
  preloadDistance: 2,  // Default: 2 notes each side
};

// Runtime configuration
preloader.setConfig({ preloadDistance: 1 }); // Conservative
preloader.setConfig({ preloadDistance: 2 }); // Balanced
preloader.setConfig({ preloadDistance: 3 }); // Aggressive
preloader.setConfig({ preloadDistance: 5 }); // Very aggressive

Recommendations:

Scenario Distance Rationale
Mobile / Low bandwidth 1 Minimize network usage
Standard desktop 2 Good balance
High-speed network 3-4 Maximize prefetch
Very fast network 5+ Aggressive prefetch

Concurrent Loads

Max simultaneous preload operations:

private preloadConfig = {
  maxConcurrentLoads: 3,  // Default
};

// Runtime configuration
preloader.setConfig({ maxConcurrentLoads: 1 }); // Sequential
preloader.setConfig({ maxConcurrentLoads: 2 }); // Conservative
preloader.setConfig({ maxConcurrentLoads: 3 }); // Balanced
preloader.setConfig({ maxConcurrentLoads: 5 }); // Aggressive

Recommendations:

Scenario Concurrent Rationale
Mobile / Limited bandwidth 1-2 Prevent congestion
Standard connection 3 Good parallelism
Fast connection 4-5 Maximum parallelism
Server-side limited 2-3 Respect server

Enable/Disable

// Disable preloading if needed
preloader.setConfig({ enabled: false });

// Re-enable
preloader.setConfig({ enabled: true });

3. PerformanceProfilerService

Sample Size

Max samples per operation (default: 100):

// In performance-profiler.service.ts
private readonly maxSamples = 100;

Tuning:

// For quick feedback (less memory)
private readonly maxSamples = 50;

// Standard (balanced)
private readonly maxSamples = 100;

// For detailed analysis
private readonly maxSamples = 200;

Environment-Specific Configuration

Development Environment

// Enable all features for debugging
preloader.setConfig({
  enabled: true,
  maxConcurrentLoads: 3,
  preloadDistance: 2
});

// Keep detailed metrics
profiler.maxSamples = 100;

// Show performance panel
// (automatically enabled on localhost)

Production Environment

// Conservative settings for stability
preloader.setConfig({
  enabled: true,
  maxConcurrentLoads: 2,
  preloadDistance: 1
});

// Reduce memory usage
cache.maxMemoryItems = 30;
cache.maxPersistentItems = 100;

// Reduce metrics overhead
profiler.maxSamples = 50;

// Hide performance panel
// (automatically hidden in production)

Mobile Environment

// Minimal preloading for bandwidth
preloader.setConfig({
  enabled: true,
  maxConcurrentLoads: 1,
  preloadDistance: 1
});

// Reduce memory footprint
cache.maxMemoryItems = 20;
cache.maxPersistentItems = 50;

// Shorter TTL for mobile
cache.setMemory(key, value, 5 * 60 * 1000); // 5 minutes

High-Traffic Environment

// Aggressive preloading
preloader.setConfig({
  enabled: true,
  maxConcurrentLoads: 5,
  preloadDistance: 3
});

// Large caches
cache.maxMemoryItems = 100;
cache.maxPersistentItems = 500;

// Longer TTL
cache.setMemory(key, value, 60 * 60 * 1000); // 1 hour

Dynamic Configuration

Network-Aware Configuration

// Detect network speed and adjust
if (navigator.connection?.effectiveType === '4g') {
  preloader.setConfig({ preloadDistance: 3, maxConcurrentLoads: 5 });
} else if (navigator.connection?.effectiveType === '3g') {
  preloader.setConfig({ preloadDistance: 2, maxConcurrentLoads: 3 });
} else {
  preloader.setConfig({ preloadDistance: 1, maxConcurrentLoads: 1 });
}

Device-Aware Configuration

// Detect device type
const isLowEndDevice = navigator.deviceMemory < 4;
const isHighEndDevice = navigator.deviceMemory >= 8;

if (isLowEndDevice) {
  cache.maxMemoryItems = 20;
  preloader.setConfig({ preloadDistance: 1 });
} else if (isHighEndDevice) {
  cache.maxMemoryItems = 100;
  preloader.setConfig({ preloadDistance: 3 });
}

Battery-Aware Configuration

// Reduce activity on low battery
if (navigator.getBattery) {
  navigator.getBattery().then(battery => {
    if (battery.level < 0.2) {
      preloader.setConfig({ enabled: false });
    }
  });
}

Performance Tuning

Identifying Bottlenecks

// Get bottleneck analysis
const bottlenecks = profiler.analyzeBottlenecks();

console.log('Slow operations:', bottlenecks.slowOperations);
console.log('Frequent operations:', bottlenecks.frequentOperations);

// Adjust configuration based on findings
if (bottlenecks.slowOperations.length > 0) {
  // Reduce concurrent loads
  preloader.setConfig({ maxConcurrentLoads: 2 });
}

Optimizing Cache Hit Rate

// Monitor cache statistics
const stats = cache.getStats();
const hitRate = stats.memory.size / stats.memory.maxSize;

if (hitRate < 0.5) {
  // Increase cache size
  cache.maxMemoryItems = 100;
} else if (hitRate > 0.9) {
  // Cache is efficient, can reduce size
  cache.maxMemoryItems = 50;
}

Reducing Memory Usage

// Monitor memory
const metrics = profiler.exportMetrics();
const memoryUsage = metrics.memory?.used;

if (memoryUsage > 100 * 1024 * 1024) {
  // Reduce cache sizes
  cache.maxMemoryItems = 30;
  cache.maxPersistentItems = 100;
  
  // Reduce preload distance
  preloader.setConfig({ preloadDistance: 1 });
}

Configuration Profiles

Profile: Conservative (Mobile/Low-End)

// Minimal resource usage
const conservativeProfile = {
  cache: {
    maxMemoryItems: 20,
    maxPersistentItems: 50,
    ttl: 5 * 60 * 1000 // 5 minutes
  },
  preloader: {
    enabled: true,
    maxConcurrentLoads: 1,
    preloadDistance: 1
  },
  profiler: {
    maxSamples: 50
  }
};

Profile: Balanced (Standard Desktop)

// Good balance of performance and resources
const balancedProfile = {
  cache: {
    maxMemoryItems: 50,
    maxPersistentItems: 200,
    ttl: 30 * 60 * 1000 // 30 minutes
  },
  preloader: {
    enabled: true,
    maxConcurrentLoads: 3,
    preloadDistance: 2
  },
  profiler: {
    maxSamples: 100
  }
};

Profile: Aggressive (High-End/Fast Network)

// Maximum performance
const aggressiveProfile = {
  cache: {
    maxMemoryItems: 100,
    maxPersistentItems: 500,
    ttl: 60 * 60 * 1000 // 1 hour
  },
  preloader: {
    enabled: true,
    maxConcurrentLoads: 5,
    preloadDistance: 3
  },
  profiler: {
    maxSamples: 200
  }
};

Applying Profiles

// Apply profile at startup
function applyProfile(profile: any) {
  cache.maxMemoryItems = profile.cache.maxMemoryItems;
  cache.maxPersistentItems = profile.cache.maxPersistentItems;
  
  preloader.setConfig({
    maxConcurrentLoads: profile.preloader.maxConcurrentLoads,
    preloadDistance: profile.preloader.preloadDistance,
    enabled: profile.preloader.enabled
  });
  
  profiler.maxSamples = profile.profiler.maxSamples;
}

// Detect environment and apply
if (isProduction()) {
  applyProfile(conservativeProfile);
} else if (isHighEndDevice()) {
  applyProfile(aggressiveProfile);
} else {
  applyProfile(balancedProfile);
}

Monitoring Configuration Impact

Before and After Metrics

// Capture baseline
const baselineMetrics = profiler.exportMetrics();

// Apply new configuration
preloader.setConfig({ preloadDistance: 3 });

// Wait for warm-up period
setTimeout(() => {
  // Capture new metrics
  const newMetrics = profiler.exportMetrics();
  
  // Compare
  console.log('Baseline:', baselineMetrics);
  console.log('After change:', newMetrics);
}, 5 * 60 * 1000); // 5 minutes

Configuration Best Practices

  1. Start Conservative: Begin with minimal settings, increase gradually
  2. Monitor Impact: Always measure before and after changes
  3. Test on Real Devices: Configuration should match target devices
  4. Document Changes: Keep track of why configurations were changed
  5. Periodic Review: Re-evaluate configuration as usage patterns change
  6. A/B Testing: Test different configurations with user segments

Troubleshooting Configuration

High Memory Usage

// Reduce cache sizes
cache.maxMemoryItems = 30;
cache.maxPersistentItems = 100;

// Reduce preload distance
preloader.setConfig({ preloadDistance: 1 });

// Increase cleanup frequency
setInterval(() => cache.cleanup(), 2 * 60 * 1000); // Every 2 minutes

Low Cache Hit Rate

// Increase cache sizes
cache.maxMemoryItems = 100;
cache.maxPersistentItems = 500;

// Increase TTL
cache.setMemory(key, value, 60 * 60 * 1000); // 1 hour

// Increase preload distance
preloader.setConfig({ preloadDistance: 3 });

Slow Navigation

// Increase preload distance
preloader.setConfig({ preloadDistance: 3 });

// Increase concurrent loads
preloader.setConfig({ maxConcurrentLoads: 5 });

// Increase cache sizes
cache.maxMemoryItems = 100;

Configuration Guide: Complete Profiles: 3 (Conservative, Balanced, Aggressive) Dynamic Configuration: Network, Device, Battery aware