Files
Kordant/iOS/docs/PERFORMANCE.md
Michael Freno e33ddf3002 feat: complete Tasks 21-28 — backend integration, security hardening, UI tests & CI
- Add Apple Sign-In backend (JWKS verification, account linking, session management)
- Implement push notification deep linking with NotificationDeepLinkRouter
- Add jailbreak detection, runtime integrity monitoring, secure enclave service
- Implement OAuth social login, token refresh, and secure logout flows
- Add image caching (memory/disk), optimizer, upload queue, async semaphore
- Implement notification analytics, type preferences, and category setup
- Expand UI test suite with UITestBase, accessibility, auth flow, performance tests
- Add CI pipeline for iOS UI tests (3 device sizes) and performance benchmarks
- Restructure Xcode project to manual groups with KordantWidgets target
- Add SwiftLint, Swift Collections/Algorithms/GoogleSignIn dependencies
- Update project.yml for XcodeGen with new targets and configurations
2026-06-02 15:01:38 -04:00

10 KiB

Kordant Performance Baseline

Last Updated: 2026-06-02 Owner: iOS Team Target Devices: iPhone SE (2nd gen), iPhone 12, iPhone 15 Pro


1. Overview

This document defines performance budgets, baselines, and measurement methodology for the Kordant iOS app. Performance tests are implemented using XCTMetric (XCTClockMetric, XCTCPUMetric, XCTMemoryMetric, XCTApplicationLaunchMetric) in both unit and UI test targets.

1.1 Performance Goals

Metric Target Device Priority
Cold Launch Time < 2.0s iPhone 12 P0
Warm Launch Time < 1.0s iPhone 12 P0
Scroll FPS 60fps All lists P0
ViewModel Data Load < 100ms iPhone 12 P1
API Deserialization < 50ms (1000 items) iPhone 12 P1
Memory Usage (navigation) < 150MB iPhone 12 P1
Image Cache Key Generation < 1ms All devices P2
Security Checks < 10ms All devices P2

2. Test Categories

2.1 Launch Performance (KordantUITests)

Test Metric Baseline Regression Threshold
testColdLaunchPerformance XCTApplicationLaunchMetric < 2.0s 10% (> 2.2s fails)
testWarmLaunchPerformance XCTApplicationLaunchMetric < 1.0s 10% (> 1.1s fails)

Measurement: Uses XCTApplicationLaunchMetric with waitUntilResponsive: true, waiting for the Dashboard navigation bar to appear. Tests run in UI testing mode with mocked data (populatedDashboard scenario).

2.2 Scroll Performance (KordantUITests)

Test Metric Baseline Regression Threshold
testDashboardScrollPerformance Clock, CPU, Memory Smooth (no dropped frames) 10%
testAlertListScrollPerformance Clock, CPU, Memory Smooth (no dropped frames) 10%
testServiceListScrollPerformance Clock, CPU, Memory Smooth (no dropped frames) 10%

Measurement: Uses XCTClockMetric, XCTCPUMetric, XCTMemoryMetric in measure(metrics:) blocks. The test scrolls through lists programmatically and measures rendering performance. Must run on physical devices — simulators do not reflect real-world scroll performance.

2.3 Navigation Performance (KordantUITests)

Test Metric Baseline Regression Threshold
testTabNavigationPerformance Clock, CPU < 500ms per transition 10%
testServiceDetailNavigationPerformance Clock, Memory < 500ms per transition 10%

2.4 Data Loading Performance (KordantUITests)

Test Metric Baseline Regression Threshold
testDashboardDataLoadPerformance Clock, CPU, Memory < 2s (includes network) 10%
testDarkWatchDataLoadPerformance Clock, Memory < 2s (includes network) 10%

2.5 Memory Performance (KordantUITests)

Test Metric Baseline Regression Threshold
testMemoryUsageAcrossNavigationFlow XCTMemoryMetric < 150MB peak 10%
testMemoryReturnsAfterNavigation XCTMemoryMetric Stable (no leaks) 10% increase

2.6 Unit Performance (KordantTests)

Test Metric Baseline Regression Threshold
DeserializationPerformanceTests.decodeAlerts Manual timing < 50ms (1000 items) 10%
DeserializationPerformanceTests.decodeExposures Manual timing < 50ms (1000 items) 10%
ViewModelPerformanceTests.dashboardViewModelLoadTime Manual timing < 100ms (50 items) 10%
ViewModelPerformanceTests.darkWatchViewModelLoadTime Manual timing < 100ms (30 items) 10%
KeychainPerformanceTests.keychainStoreRetrievePerformance Manual timing < 0.1ms per op 10%
SecurityPerformanceTests.jailbreakDetectionPerformance Manual timing < 10ms 10%
SecurityPerformanceTests.runtimeIntegrityPerformance Manual timing < 10ms 10%

2.7 XCTMetric Unit Performance (KordantTests)

Test Metric Baseline Regression Threshold
testJSONEncodingPerformance Clock, CPU, Memory Established by 10 runs 10%
testJSONDecodingPerformance Clock, CPU, Memory Established by 10 runs 10%
testThreatScoreCalculationPerformance Clock, CPU, Memory Established by 10 runs 10%
testImageCacheMetadataPersistencePerformance Clock Established by 10 runs 10%
testAlertSortingPerformance Clock Established by 10 runs 10%

3. Baseline Establishment Process

  1. Initial Baseline: Run each performance test 10 times on a reference device (iPhone 12).
  2. Record Results: Xcode automatically records the baseline average.
  3. Document: Record the baseline values in the "Baselines" column above.
  4. Accept: Xcode compares future runs against the stored baseline.
  5. Review: Baselines should be re-established after major OS updates or architecture changes.

3.1 Device-Specific Baselines

Device Cold Launch Scroll FPS Memory Peak
iPhone SE (2nd gen) < 3.0s 60fps (slower scroll) < 120MB
iPhone 12 < 2.0s 60fps < 150MB
iPhone 15 Pro < 1.2s 60fps < 200MB

4. Regression Detection

4.1 Threshold Configuration

Xcode's measure(metrics:) API automatically compares test results against stored baselines. A 10% regression threshold is configured for all tests.

// Example: Xcode flags this test if time exceeds baseline by > 10%
measure(metrics: [XCTClockMetric(), XCTCPUMetric(), XCTMemoryMetric()]) {
    // code under test
}

4.2 CI Pipeline Integration

Performance tests run as part of the CI pipeline on every PR and release build:

  1. Unit performance tests: Run on every PR (fast, no device needed)
  2. UI performance tests: Run on device farm (iPhone SE, 12, 15 Pro) nightly
  3. Failure action: PR cannot merge if any performance test regresses by > 10%
  4. Alert: Performance degradation alerts sent to #ios-eng Slack channel

4.3 Manual Verification

In Xcode:

  1. Open the test report (⌘9 → Tests tab)
  2. Select a performance test
  3. View the "Metrics" tab to see baseline vs. current results
  4. Check "Performance Graph" for trend analysis across test runs

5. Optimization Techniques

5.1 Launch Time

Technique Location Impact
Lazy service initialization KordantApp.swift ~500ms saved
Deferred setup after first frame ContentView.swift → task ~300ms saved
Minimal didFinishLaunchingWithOptions AppDelegate.swift ~200ms saved
Mock data in testing mode TestingMode.swift N/A (testing only)

5.2 Scroll Performance

Technique Location Impact
LazyVStack for lists All list views 60fps maintained
Image prefetching PaginatedListView.swift No loading jank
ShieldSkeleton placeholders All loading states Perceived performance
CachedAsyncImage with downsampling CachedAsyncImage.swift Memory efficient loading

5.3 Memory

Technique Location Impact
50MB URLCache memory limit ImageCacheService.swift Prevents OOM
LRU disk cache eviction ImageCacheService.swift Disk quota enforced
Memory warning handling ImageCacheService.swift Clears cache on pressure
@StateObject lifecycle management All ViewModels No leaked view models

5.4 Data Processing

Technique Location Impact
Concurrent async data loading DashboardViewModel.swift 3x faster dashboard
JSON with iso8601 date strategy APIClient.swift Fast date parsing
Codable conformance All models Zero boilerplate parsing
Lazy metadata loading ImageCacheService.swift No disk I/O at launch

6. Running Performance Tests

6.1 Local (Xcode)

# Run all performance tests
xcodebuild test \
  -project Kordant.xcodeproj \
  -scheme Kordant \
  -testPlan KordantUITests \
  -destination 'platform=iOS,name=iPhone 12' \
  -only-testing:KordantUITests/LaunchPerformanceTests \
  -only-testing:KordantUITests/ScrollPerformanceTests \
  -only-testing:KordantUITests/NavigationPerformanceTests

# Run unit performance tests
xcodebuild test \
  -project Kordant.xcodeproj \
  -scheme Kordant \
  -destination 'platform=iOS Simulator,name=iPhone 15 Pro' \
  -only-testing:KordantTests/XCTMetricPerformanceTests

6.2 CI (Device Farm)

# Run on all target devices
xcodebuild test \
  -project Kordant.xcodeproj \
  -scheme Kordant \
  -testPlan KordantUITests \
  -destination 'platform=iOS,name=iPhone SE (2nd generation)' \
  -destination 'platform=iOS,name=iPhone 12' \
  -destination 'platform=iOS,name=iPhone 15 Pro' \
  -resultBundlePath ./PerformanceResults.xcresult

6.3 Important Notes

  • Always run performance tests on physical devices. Simulators do not reflect real-world CPU, GPU, or memory performance.
  • Tests should be run with the device in Airplane Mode (for local stability tests) or with real network conditions (for data loading tests).
  • Device brightness should be set to ~50% for consistency.
  • Close all other apps before running performance tests.
  • Tests should be run with a Release build configuration for accurate timing.

7. Troubleshooting

Issue Likely Cause Resolution
Scroll test fails on device Background processes Restart device, close apps
Launch time > 2s New dependency added in init Move to deferred setup
Memory > 150MB Image cache leak Check URLCache eviction
JSON decode > 50ms Large nested payload Optimize API response shape
Baseline drift iOS version change Re-baseline after OS update

8. Review Cadence

  • Weekly: Review performance test results in CI dashboard
  • Monthly: Full performance audit on reference device
  • Per Release: Re-establish baselines before release branch cut
  • Per OS Update: Re-run all tests after iOS beta/stable update