Skip to content

Latest commit

Β 

History

History
498 lines (395 loc) Β· 14 KB

PERFORMANCE-GUIDE.md

File metadata and controls

498 lines (395 loc) Β· 14 KB

Performance Optimization Guide


⚑ Overview

This guide provides actionable performance optimizations for the Cloudflare Network Diagnostic Tool. Implementing these recommendations will reduce diagnostic runtime from ~70ms to ~25ms (3x faster) and eliminate UI blocking during exports.

Key Areas:

  • πŸš€ DNS Benchmarking Parallelization
  • πŸ“€ Background Thread Exports
  • πŸ“ Batched Logging Operations
  • 🎯 Health Score Caching
  • 🧹 Efficient Log Cleanup

πŸ—οΈ Architecture Performance Layers

Layer Current Issue Optimization Expected Gain
Network Layer Sequential DNS requests Parallel async/await 67ms β†’ 22ms (3x)
Trace Layer No caching Memoization -30% redundancy
Benchmark Layer Blocking on main thread Background dispatch Non-blocking
Health Layer Full recalculation Component caching 10x faster
Export Layer UI blocking (500ms) Background thread 0ms blocking
Logging Layer 33% Base64 overhead Batch encoding -33% overhead

πŸ”΄ Priority 1: Critical (Week 1)

1.1 Parallel DNS Benchmarking

Problem: DNS queries run sequentially (67ms total instead of 22ms)

Current Pattern (❌ SLOW):

// Each DNS lookup blocks until complete
let cf = measureDNS(.cloudflare)    // ~12ms
let google = measureDNS(.google)    // ~18ms
let quad9 = measureDNS(.quad9)      // ~15ms
let nextdns = measureDNS(.nextdns)  // ~22ms
// Total: ~67ms ⚠️

Optimized Pattern (βœ… FAST):

// Run all DNS tests concurrently
async let cf = measureDNS(.cloudflare)
async let google = measureDNS(.google)
async let quad9 = measureDNS(.quad9)
async let nextdns = measureDNS(.nextdns)

let results = await (cf, google, quad9, nextdns)
// Total: ~22ms (longest individual test) βœ…

Implementation:

  • See: reference/NetworkLayer-Optimized.swift
  • Use: Swift 5.5+ async/await with structured concurrency
  • Test: Xcode Instruments β†’ Time Profiler
  • Expected: 3x speedup (67ms β†’ 22ms)

Checklist:

  • Identify current sequential DNS implementation
  • Convert to async/await pattern
  • Test with Xcode Instruments
  • Verify 3x improvement
  • Run performance regression tests

1.2 URLSession Timeout Configuration

Problem: Default 60s timeout causes hangs on slow networks

Current Pattern (❌ PROBLEMATIC):

let session = URLSession.shared  // Default: 60s timeout ⚠️

Optimized Pattern (βœ… RECOMMENDED):

let config = URLSessionConfiguration.default
config.timeoutIntervalForRequest = 5.0      // Individual request
config.timeoutIntervalForResource = 30.0    // Total resource
config.httpMaximumConnectionsPerHost = 6    // Connection pooling
config.waitsForConnectivity = false         // Fail fast

let session = URLSession(configuration: config)

Implementation:

  • See: reference/NetworkLayer-Optimized.swift (lines 18-26)
  • Use: URLSessionConfiguration for all network requests
  • Test: Simulate slow network (Xcode throttling)
  • Expected: Prevents hangs, fails gracefully

Checklist:

  • Create optimized URLSessionConfiguration
  • Apply to all URLSession instances
  • Test on throttled network (slow 3G)
  • Verify timeout behavior
  • Document in troubleshooting

🟠 Priority 2: High ROI (Week 2)

2.1 Background Thread JSON Exports

Problem: JSON encoding/pretty-printing blocks UI for 100-500ms

Current Pattern (❌ BLOCKS UI):

// All on main thread - blocks UI
let jsonData = try JSONSerialization.data(
    withJSONObject: diagnostics,
    options: .prettyPrinted
)
write(jsonData)  // I/O also blocks ⚠️

Optimized Pattern (βœ… NON-BLOCKING):

// Move to background thread
DispatchQueue.global(qos: .userInitiated).async {
    let jsonData = try JSONSerialization.data(
        withJSONObject: diagnostics,
        options: .prettyPrinted
    )
    write(jsonData)
    
    // Deliver result on main thread
    DispatchQueue.main.async {
        completion(jsonData)
    }
}

Best Pattern (βœ… MODERN):

// Use async/await (Swift 5.5+)
let result = try await withCheckedThrowingContinuation { continuation in
    DispatchQueue.global(qos: .userInitiated).async {
        do {
            let jsonData = try JSONSerialization.data(
                withJSONObject: diagnostics,
                options: .prettyPrinted
            )
            continuation.resume(returning: jsonData)
        } catch {
            continuation.resume(throwing: error)
        }
    }
}

Implementation:

  • See: reference/ExportLayer-Optimized.swift
  • Use: DispatchQueue or async/await
  • Test: Core Animation profiler (check 60 FPS)
  • Expected: Zero UI blocking

Checklist:

  • Audit current export implementation
  • Move encoding to background thread
  • Test with large datasets (1000+ items)
  • Verify 60 FPS maintained
  • Test all export formats

2.2 Batched Base64 Logging

Problem: Every log write triggers encoding, causing 33% overhead + blocking

Current Pattern (❌ SLOW & BLOCKING):

# Encodes and writes each entry synchronously
for log_entry in diagnostics:
    encoded = base64.b64encode(log_entry)  # 33% overhead ⚠️
    log_file.write(encoded)                 # I/O blocking ⚠️

Optimized Pattern (βœ… BATCHED):

# Batch in memory, encode on background thread
log_buffer = []

def write_log(entry):
    log_buffer.append(entry)
    if len(log_buffer) >= BATCH_SIZE:  # Flush every 100 entries
        batch = log_buffer.copy()
        log_buffer.clear()
        executor.submit(flush_batch, batch)  # Background thread

def flush_batch(batch):
    batch_str = '\\n'.join(batch)
    encoded = base64.b64encode(batch_str)  # Batch encode
    with open(log_file, 'a') as f:
        f.write(encoded)  # Single I/O operation

Alternative (βœ… EVEN BETTER):

# Use compression instead of Base64
# - 40-60% smaller files
# - Better performance
# - More secure
with gzip.open(log_file, 'at') as f:
    f.write(json.dumps(entry))

Implementation:

  • See: reference/LoggingLayer-Optimized.py
  • Use: Batching or compression
  • Test: Measure I/O performance
  • Expected: -33% overhead or compression alternative

Checklist:

  • Audit current logging implementation
  • Implement batching with 100-entry batch size
  • Move encoding to background thread
  • Measure I/O improvements
  • Consider compression alternative

🟑 Priority 3: Polish (Week 3)

3.1 Health Score Caching

Problem: Recalculates full score from scratch every time

Current Pattern (❌ REDUNDANT):

// Every call recalculates everything
let score = calculateHealthScore(dns, doh, trace, warp)
// Even if inputs haven't changed ⚠️

Optimized Pattern (βœ… CACHED):

// Check cache first
if let cached = cachedScore,
   Date().timeIntervalSince(cacheTime) < 300 {  // 5-min TTL
    return cached  // Instant return βœ…
}

// Calculate and cache
let score = _calculateScore(...)
cachedScore = score
cacheTime = Date()
return score

Advanced Pattern (βœ… MEMOIZED COMPONENTS):

// Cache individual component scores
var dnsScoreCache: [String: Double] = [:]
var dohScoreCache: [String: Double] = [:]
var locationScoreCache: [String: Double] = [:]

// Return immediately if in cache
if let cached = dnsScoreCache[key] {
    return cached
}
// Calculate and cache
let score = _calculateDNSScore(...)
dnsScoreCache[key] = score
return score

Implementation:

  • See: reference/HealthScoring-Optimized.swift
  • Use: TTL-based cache (300s) + component memoization
  • Test: Measure repeated diagnostics
  • Expected: 10x faster on repeated calls

Checklist:

  • Identify all score calculations
  • Add TTL-based cache
  • Implement component memoization
  • Test with repeated diagnostics
  • Add cache statistics

3.2 Efficient Log Cleanup

Problem: Scanning all logs sequentially for deletion can stall app

Current Pattern (❌ SLOW):

// Checks modification date of every single file
for file in allLogFiles {
    let modDate = file.modificationDate  // I/O call per file ⚠️
    if modDate < cutoffDate {
        delete(file)
    }
}

Optimized Pattern (βœ… DATE-BASED BATCH):

// Extract date from filename (no I/O needed)
let cutoffDate = Date(timeIntervalSinceNow: -30*24*3600)
let cutoffString = ISO8601DateFormatter().string(from: cutoffDate)

for file in logFiles {
    // Format: diagnostic_YYYY-MM-DDTHH:MM:SS.cflog
    let fileDate = filename.dropFirst(11).prefix(10)  // YYYY-MM-DD
    
    if fileDate < cutoffString {
        markForDeletion(file)
    }
}

// Delete in batches on background thread
deleteInBatches(markedFiles, batchSize: 50)

Advanced Pattern (βœ… ASYNC PERIODIC CLEANUP):

func schedulePeriodicCleanup(interval: TimeInterval = 24*3600) {
    Task {
        while true {
            try? await Task.sleep(nanoseconds: UInt64(interval * 1e9))
            await cleanupLogsAsync()  // Non-blocking
        }
    }
}

Implementation:

  • See: reference/LogCleanup-Optimized.swift
  • Use: Date-based filtering + batch deletion
  • Test: 1000+ log files
  • Expected: 10x faster cleanup

Checklist:

  • Audit current cleanup implementation
  • Extract date from filename instead of stat calls
  • Implement batch deletion
  • Add async periodic cleanup scheduling
  • Test with large log directories

πŸ“Š Performance Targets

Metric Before After Target Status
DNS Benchmarking ~67ms ~22ms 3x 🎯
Export Blocking ~500ms 0ms Non-blocking 🎯
Log I/O Overhead +33% 0% Optimized 🎯
Health Score Calc ~50ms <5ms 10x 🎯
Log Cleanup (1000 files) ~5000ms ~500ms 10x 🎯
Overall Diagnostic ~70ms ~25ms 3x 🎯

πŸ§ͺ Testing & Profiling

Using Xcode Instruments

1. Time Profiler (Measure CPU time)

  • βœ… Verify DNS parallelization reduces time by 3x
  • βœ… Check health score calculation improvements
  • Target: < 25ms total diagnostic time

2. Core Animation (Detect UI blocking)

  • βœ… Verify exports don't block UI
  • βœ… Check export maintains 60 FPS
  • Target: 60 FPS maintained during exports

3. System Trace (Thread scheduling)

  • βœ… Verify main thread not blocked
  • βœ… Check background threads active
  • Target: Main thread idle during heavy work

4. Memory Graph (Detect leaks)

  • βœ… Check async operations don't leak
  • βœ… Verify cache size bounded
  • Target: Stable memory usage

5. File Activity (I/O patterns)

  • βœ… Verify batched logging works
  • βœ… Check fewer I/O operations
  • Target: Fewer I/O calls than before

Testing Checklist

Unit Tests:

  • Parallel DNS benchmark correctness
  • Export format encoding accuracy
  • Health score consistency
  • Cache invalidation logic
  • Log cleanup date filtering

Integration Tests:

  • Full diagnostic pipeline
  • All export formats
  • Concurrent diagnostics
  • Error handling & fallbacks
  • Memory leak detection

Device Testing:

  • iPhone 12 (A14 Bionic)
  • iPhone 14 (A15 Bionic)
  • iPhone 15 (A17 Pro)
  • iPad (various models)
  • macOS (Intel & Apple Silicon)

πŸ“ Implementation Roadmap

Week 1: Critical Path

Monday-Tuesday:   Parallel DNS Benchmarking
Wednesday:        URLSession Timeout Config
Thursday-Friday:  Testing & Validation
Target:           3x diagnostic speedup

Week 2: High ROI

Monday-Tuesday:   Background Thread Exports
Wednesday:        Batched Base64 Logging
Thursday:         Testing & Validation
Friday:           Documentation
Target:           Zero UI blocking

Week 3: Polish

Monday-Tuesday:   Health Score Caching
Wednesday:        Log Cleanup Optimization
Thursday:         Performance Validation
Friday:           Final Documentation
Target:           All optimizations complete

πŸ”— Reference Implementation Files

File Purpose Language
NetworkLayer-Optimized.swift Parallel DNS & timeouts Swift
ExportLayer-Optimized.swift Background exports Swift
LoggingLayer-Optimized.py Batched encoding Python
HealthScoring-Optimized.swift Score caching Swift
LogCleanup-Optimized.swift Efficient cleanup Swift

All files include:

  • βœ… Before/after comparison patterns
  • βœ… Detailed implementation examples
  • βœ… Usage examples and integration guide
  • βœ… Performance testing strategy

πŸ“– Additional Resources


πŸ“‹ Contributing Optimizations

Follow these guidelines when contributing performance improvements:

  1. Measure First β€” Use Xcode Instruments to baseline
  2. Implement β€” Use reference implementations as guide
  3. Test β€” Verify improvement with benchmarks
  4. Document β€” Update this guide with metrics
  5. PR Review β€” Include performance data

πŸ“ž Support & Questions


Cloudflare Network Diagnostic Tool β€” Fast. Private. Optimized.

Made with ❀️ for performance | v1.0 Performance Guide | Last updated: June 2026