Skip to content

Mobile Performance Benchmarking & Testing Guide

Overview

This comprehensive guide covers performance benchmarking, testing strategies, and monitoring techniques for mobile applications. It includes platform-specific tools, automated testing frameworks, and production monitoring solutions.

Performance Metrics & Benchmarks

Core Performance Indicators

typescript
interface PerformanceMetrics {
  // App Lifecycle
  coldStartTime: number;      // Target: < 2s
  warmStartTime: number;      // Target: < 1s
  hotStartTime: number;       // Target: < 0.5s
  
  // Runtime Performance
  frameRate: number;          // Target: 60 FPS
  frameDrops: number;         // Target: < 5%
  memoryUsage: number;        // Target: < 100MB
  cpuUsage: number;          // Target: < 20%
  
  // Network Performance
  apiResponseTime: number;    // Target: < 500ms
  networkErrors: number;      // Target: < 1%
  dataUsage: number;         // Minimize
  
  // User Experience
  screenTransitionTime: number; // Target: < 300ms
  scrollPerformance: number;    // Target: 60 FPS
  inputLatency: number;         // Target: < 100ms
  batteryDrain: number;         // Minimize
}

class PerformanceBenchmark {
  private metrics: PerformanceMetrics[] = [];
  private thresholds = {
    coldStart: 2000,
    frameRate: 55,
    memoryUsage: 100 * 1024 * 1024, // 100MB
    apiResponse: 500,
  };
  
  async measurePerformance(): Promise<PerformanceReport> {
    const metrics = await this.collectMetrics();
    const analysis = this.analyzeMetrics(metrics);
    
    return {
      metrics,
      analysis,
      recommendations: this.generateRecommendations(analysis),
      grade: this.calculateGrade(analysis),
    };
  }
  
  private async collectMetrics(): Promise<PerformanceMetrics> {
    return {
      coldStartTime: await this.measureColdStart(),
      warmStartTime: await this.measureWarmStart(),
      hotStartTime: await this.measureHotStart(),
      frameRate: await this.measureFrameRate(),
      frameDrops: await this.measureFrameDrops(),
      memoryUsage: await this.measureMemoryUsage(),
      cpuUsage: await this.measureCPUUsage(),
      apiResponseTime: await this.measureAPIResponse(),
      networkErrors: await this.measureNetworkErrors(),
      dataUsage: await this.measureDataUsage(),
      screenTransitionTime: await this.measureScreenTransitions(),
      scrollPerformance: await this.measureScrollPerformance(),
      inputLatency: await this.measureInputLatency(),
      batteryDrain: await this.measureBatteryDrain(),
    };
  }
}

Platform-Specific Testing Tools

iOS Performance Testing

swift
// iOS Performance Testing Framework
import XCTest
import MetricKit

class iOSPerformanceTests: XCTestCase {
    private let performanceMonitor = PerformanceMonitor()
    
    func testColdStartPerformance() {
        measure(metrics: [XCTApplicationLaunchMetric()]) {
            XCUIApplication().launch()
        }
    }
    
    func testScrollPerformance() {
        let app = XCUIApplication()
        app.launch()
        
        let scrollView = app.scrollViews.firstMatch
        
        measure(metrics: [XCTOSSignpostMetric.scrollingAndDecelerationMetric]) {
            scrollView.swipeUp(velocity: .fast)
        }
    }
    
    func testMemoryPerformance() {
        measure(metrics: [XCTMemoryMetric()]) {
            // Perform memory-intensive operations
            performMemoryIntensiveTask()
        }
    }
    
    func testCPUPerformance() {
        measure(metrics: [XCTCPUMetric()]) {
            // Perform CPU-intensive operations
            performCPUIntensiveTask()
        }
    }
}

// MetricKit Integration for Production Monitoring
class MetricKitManager: NSObject, MXMetricManagerSubscriber {
    override init() {
        super.init()
        MXMetricManager.shared.add(self)
    }
    
    func didReceive(_ payloads: [MXMetricPayload]) {
        for payload in payloads {
            processMetricPayload(payload)
        }
    }
    
    private func processMetricPayload(_ payload: MXMetricPayload) {
        // Process CPU metrics
        if let cpuMetrics = payload.cpuMetrics {
            logCPUMetrics(cpuMetrics)
        }
        
        // Process memory metrics
        if let memoryMetrics = payload.memoryMetrics {
            logMemoryMetrics(memoryMetrics)
        }
        
        // Process display metrics
        if let displayMetrics = payload.displayMetrics {
            logDisplayMetrics(displayMetrics)
        }
        
        // Process application launch metrics
        if let launchMetrics = payload.applicationLaunchMetrics {
            logLaunchMetrics(launchMetrics)
        }
    }
    
    private func logCPUMetrics(_ metrics: MXCPUMetrics) {
        let cpuUsage = metrics.cumulativeCPUTime.converted(to: .seconds).value
        Analytics.log("cpu_usage", value: cpuUsage)
    }
    
    private func logMemoryMetrics(_ metrics: MXMemoryMetrics) {
        let peakMemory = metrics.peakMemoryUsage.converted(to: .megabytes).value
        Analytics.log("peak_memory", value: peakMemory)
    }
}

Android Performance Testing

kotlin
// Android Performance Testing Framework
@RunWith(AndroidJUnit4::class)
@LargeTest
class AndroidPerformanceTests {
    
    @get:Rule
    val activityRule = ActivityTestRule(MainActivity::class.java)
    
    @Test
    fun testColdStartPerformance() {
        val scenario = ActivityScenario.launch(MainActivity::class.java)
        
        // Measure cold start time
        val startTime = System.nanoTime()
        scenario.onActivity { activity ->
            val endTime = System.nanoTime()
            val launchTime = (endTime - startTime) / 1_000_000 // Convert to ms
            
            Assert.assertTrue("Cold start too slow: ${launchTime}ms", launchTime < 2000)
        }
    }
    
    @Test
    fun testScrollPerformance() {
        // Use JankStats to measure scroll performance
        val jankStats = JankStats.createAndTrack(activityRule.activity.window) { frameData ->
            frameData.states.forEach { state ->
                when (state) {
                    is JankStats.JankStatsApi.JankState.Jank -> {
                        Log.w("Performance", "Jank detected: ${state.reason}")
                    }
                }
            }
        }
        
        // Perform scroll test
        onView(withId(R.id.recycler_view))
            .perform(RecyclerViewActions.scroll(10))
    }
    
    @Test
    fun testMemoryUsage() {
        val runtime = Runtime.getRuntime()
        val initialMemory = runtime.totalMemory() - runtime.freeMemory()
        
        // Perform memory-intensive operations
        performMemoryIntensiveTask()
        
        val finalMemory = runtime.totalMemory() - runtime.freeMemory()
        val memoryIncrease = finalMemory - initialMemory
        
        Assert.assertTrue(
            "Memory usage too high: ${memoryIncrease / 1024 / 1024}MB",
            memoryIncrease < 50 * 1024 * 1024 // 50MB limit
        )
    }
}

// Continuous Performance Monitoring
class AndroidPerformanceMonitor {
    private val frameMetricsListener = FrameMetricsListener()
    
    fun startMonitoring(activity: Activity) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            activity.window.addOnFrameMetricsAvailableListener(
                frameMetricsListener,
                Handler(Looper.getMainLooper())
            )
        }
        
        startMemoryMonitoring()
        startCPUMonitoring()
    }
    
    private inner class FrameMetricsListener : Window.OnFrameMetricsAvailableListener {
        override fun onFrameMetricsAvailable(
            window: Window,
            frameMetrics: FrameMetrics,
            dropCountSinceLastInvocation: Int
        ) {
            val totalDuration = frameMetrics.getMetric(FrameMetrics.TOTAL_DURATION)
            val layoutDuration = frameMetrics.getMetric(FrameMetrics.LAYOUT_MEASURE_DURATION)
            val drawDuration = frameMetrics.getMetric(FrameMetrics.DRAW_DURATION)
            
            // Log performance metrics
            Analytics.log("frame_metrics", mapOf(
                "total_duration" to totalDuration,
                "layout_duration" to layoutDuration,
                "draw_duration" to drawDuration,
                "dropped_frames" to dropCountSinceLastInvocation
            ))
            
            // Alert if frame is too slow
            if (totalDuration > 16_000_000) { // 16ms threshold
                Log.w("Performance", "Slow frame detected: ${totalDuration / 1_000_000}ms")
            }
        }
    }
}

React Native Performance Testing

typescript
// React Native Performance Testing
import { render, waitFor } from '@testing-library/react-native';
import { performance } from 'perf_hooks';

class ReactNativePerformanceTests {
  async testComponentRenderPerformance<T>(
    Component: React.ComponentType<T>,
    props: T
  ): Promise<PerformanceResult> {
    const startTime = performance.now();
    
    const { rerender } = render(<Component {...props} />);
    
    const initialRenderTime = performance.now() - startTime;
    
    // Test re-render performance
    const rerenderStartTime = performance.now();
    rerender(<Component {...props} />);
    const rerenderTime = performance.now() - rerenderStartTime;
    
    return {
      initialRenderTime,
      rerenderTime,
      passed: initialRenderTime < 100 && rerenderTime < 50,
    };
  }
  
  async testListScrollPerformance(): Promise<PerformanceResult> {
    const frameDrops: number[] = [];
    
    // Monitor frame drops during scroll
    const frameRateMonitor = setInterval(() => {
      const fps = this.getCurrentFPS();
      if (fps < 55) {
        frameDrops.push(fps);
      }
    }, 100);
    
    // Simulate scroll
    await this.simulateScroll();
    
    clearInterval(frameRateMonitor);
    
    return {
      frameDrops: frameDrops.length,
      averageFPS: this.calculateAverageFPS(),
      passed: frameDrops.length < 5,
    };
  }
  
  private getCurrentFPS(): number {
    // Implementation depends on platform
    return 60; // Placeholder
  }
}

// Flipper Integration for Development
class FlipperPerformancePlugin {
  private connection: any;
  
  constructor() {
    this.setupFlipperConnection();
  }
  
  private setupFlipperConnection() {
    if (__DEV__) {
      const flipper = require('react-native-flipper');
      this.connection = flipper.addPlugin({
        getId() { return 'PerformanceMonitor'; },
        onConnect(connection: any) {
          this.connection = connection;
        },
        runInBackground() {
          return false;
        },
      });
    }
  }
  
  reportPerformanceMetrics(metrics: PerformanceMetrics) {
    if (this.connection) {
      this.connection.send('performanceMetrics', metrics);
    }
  }
}

Flutter Performance Testing

dart
// Flutter Performance Testing
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';

class FlutterPerformanceTests {
  
  void testScrollPerformance() {
    testWidgets('Scroll performance test', (WidgetTester tester) async {
      // Track timeline during test
      await tester.binding.traceAction(() async {
        await tester.pumpWidget(MyApp());
        
        // Find scrollable widget
        final listFinder = find.byType(ListView);
        
        // Perform scroll operation
        await tester.drag(listFinder, const Offset(0, -500));
        await tester.pumpAndSettle();
        
        // Scroll back
        await tester.drag(listFinder, const Offset(0, 500));
        await tester.pumpAndSettle();
      },
      reportKey: 'scroll_performance_timeline',
      stream: Timeline.timeSync);
    });
  }
  
  void testWidgetBuildPerformance() {
    testWidgets('Widget build performance', (WidgetTester tester) async {
      final stopwatch = Stopwatch()..start();
      
      await tester.pumpWidget(ComplexWidget());
      
      stopwatch.stop();
      
      expect(stopwatch.elapsedMilliseconds, lessThan(100),
          reason: 'Widget build took too long: ${stopwatch.elapsedMilliseconds}ms');
    });
  }
  
  void testAnimationPerformance() {
    testWidgets('Animation performance test', (WidgetTester tester) async {
      await tester.binding.traceAction(() async {
        await tester.pumpWidget(AnimatedWidget());
        
        // Start animation
        await tester.tap(find.byType(FloatingActionButton));
        
        // Let animation complete
        await tester.pumpAndSettle(const Duration(seconds: 2));
      },
      reportKey: 'animation_performance_timeline');
    });
  }
}

// Production Performance Monitoring
class FlutterPerformanceMonitor {
  static final FlutterPerformanceMonitor _instance = 
      FlutterPerformanceMonitor._internal();
  factory FlutterPerformanceMonitor() => _instance;
  FlutterPerformanceMonitor._internal();
  
  void startMonitoring() {
    // Monitor frame rendering
    SchedulerBinding.instance.addPostFrameCallback((_) {
      _recordFrameTime();
    });
    
    // Monitor widget builds
    WidgetsBinding.instance.addObserver(_PerformanceObserver());
  }
  
  void _recordFrameTime() {
    final currentTime = DateTime.now().millisecondsSinceEpoch;
    // Record frame timing
    AnalyticsService.recordFrameTime(currentTime);
  }
}

class _PerformanceObserver extends WidgetsBindingObserver {
  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    AnalyticsService.recordAppLifecycleChange(state.toString());
  }
}

Automated Performance Testing Pipeline

CI/CD Performance Tests

yaml
# GitHub Actions Performance Testing
name: Mobile Performance Tests

on:
  pull_request:
    branches: [main]
  push:
    branches: [main]

jobs:
  ios-performance:
    runs-on: macos-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: Setup iOS
        uses: actions/setup-node@v3
        with:
          node-version: '18'
      
      - name: Install dependencies
        run: |
          cd ios
          pod install
      
      - name: Run iOS Performance Tests
        run: |
          xcodebuild test \
            -workspace ios/App.xcworkspace \
            -scheme App \
            -destination 'platform=iOS Simulator,name=iPhone 14' \
            -testPlan PerformanceTests \
            -resultBundlePath TestResults.xcresult
      
      - name: Analyze Performance
        run: |
          xcrun xcresulttool get --format json \
            --path TestResults.xcresult > performance-results.json
      
      - name: Upload Results
        uses: actions/upload-artifact@v3
        with:
          name: ios-performance-results
          path: performance-results.json

  android-performance:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: Setup Android
        uses: android-actions/setup-android@v2
      
      - name: Run Android Performance Tests
        run: |
          ./gradlew :app:connectedAndroidTest \
            -Pandroid.testInstrumentationRunnerArguments.class=com.app.PerformanceTestSuite
      
      - name: Generate Performance Report
        run: |
          ./gradlew :app:generatePerformanceReport
      
      - name: Upload Results
        uses: actions/upload-artifact@v3
        with:
          name: android-performance-results
          path: app/build/reports/performance/

  performance-analysis:
    needs: [ios-performance, android-performance]
    runs-on: ubuntu-latest
    steps:
      - name: Download Results
        uses: actions/download-artifact@v3
      
      - name: Analyze Performance Trends
        run: |
          node scripts/analyze-performance.js
      
      - name: Comment PR with Results
        uses: actions/github-script@v6
        with:
          script: |
            const fs = require('fs');
            const results = JSON.parse(fs.readFileSync('performance-summary.json'));
            
            github.rest.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: `## Performance Test Results\n\n${results.summary}`
            });

Production Performance Monitoring

Real-time Performance Dashboard

typescript
// Performance Monitoring Service
class PerformanceMonitoringService {
  private analytics: AnalyticsService;
  private alerting: AlertingService;
  
  constructor() {
    this.analytics = new AnalyticsService();
    this.alerting = new AlertingService();
  }
  
  async setupRealTimeMonitoring(): Promise<void> {
    // Setup performance tracking
    this.setupFrameRateMonitoring();
    this.setupMemoryMonitoring();
    this.setupNetworkMonitoring();
    this.setupCrashReporting();
    
    // Setup alerting thresholds
    this.setupPerformanceAlerts();
  }
  
  private setupFrameRateMonitoring(): void {
    const frameRateMonitor = new FrameRateMonitor();
    
    frameRateMonitor.onFrameRate((fps: number) => {
      this.analytics.track('frame_rate', { fps });
      
      if (fps < 50) {
        this.alerting.sendAlert({
          type: 'performance',
          severity: 'warning',
          message: `Low frame rate detected: ${fps} FPS`,
          metadata: { fps, timestamp: Date.now() }
        });
      }
    });
  }
  
  private setupMemoryMonitoring(): void {
    const memoryMonitor = new MemoryMonitor();
    
    memoryMonitor.onMemoryUsage((usage: MemoryUsage) => {
      this.analytics.track('memory_usage', usage);
      
      if (usage.used > usage.total * 0.8) {
        this.alerting.sendAlert({
          type: 'memory',
          severity: 'critical',
          message: 'High memory usage detected',
          metadata: usage
        });
      }
    });
  }
  
  generatePerformanceReport(): PerformanceReport {
    return {
      summary: this.analytics.getSummary(),
      trends: this.analytics.getTrends(),
      alerts: this.alerting.getActiveAlerts(),
      recommendations: this.generateRecommendations(),
    };
  }
}

// Performance Dashboard Component
interface PerformanceDashboardProps {
  timeRange: TimeRange;
  platforms: Platform[];
}

const PerformanceDashboard: React.FC<PerformanceDashboardProps> = ({
  timeRange,
  platforms
}) => {
  const [metrics, setMetrics] = useState<PerformanceMetrics[]>([]);
  const [alerts, setAlerts] = useState<Alert[]>([]);
  
  useEffect(() => {
    const fetchData = async () => {
      const data = await PerformanceAPI.getMetrics(timeRange, platforms);
      setMetrics(data.metrics);
      setAlerts(data.alerts);
    };
    
    fetchData();
    
    // Setup real-time updates
    const interval = setInterval(fetchData, 30000); // 30 seconds
    return () => clearInterval(interval);
  }, [timeRange, platforms]);
  
  return (
    <div className="performance-dashboard">
      <MetricsOverview metrics={metrics} />
      <FrameRateChart data={metrics} />
      <MemoryUsageChart data={metrics} />
      <NetworkPerformanceChart data={metrics} />
      <AlertsPanel alerts={alerts} />
      <RecommendationsPanel metrics={metrics} />
    </div>
  );
};

Performance Testing Strategies

Load Testing for Mobile Apps

typescript
// Mobile Load Testing Framework
class MobileLoadTester {
  private testConfig: LoadTestConfig;
  
  constructor(config: LoadTestConfig) {
    this.testConfig = config;
  }
  
  async runLoadTest(): Promise<LoadTestResults> {
    const results: LoadTestResults = {
      totalRequests: 0,
      successfulRequests: 0,
      failedRequests: 0,
      averageResponseTime: 0,
      throughput: 0,
      errors: [],
    };
    
    // Simulate concurrent users
    const userSimulations = Array.from(
      { length: this.testConfig.concurrentUsers },
      (_, index) => this.simulateUser(index)
    );
    
    const allResults = await Promise.allSettled(userSimulations);
    
    // Aggregate results
    return this.aggregateResults(allResults);
  }
  
  private async simulateUser(userId: number): Promise<UserTestResult> {
    const userActions = [
      'login',
      'browse',
      'search',
      'viewDetails',
      'addToCart',
      'checkout',
    ];
    
    const results: ActionResult[] = [];
    
    for (const action of userActions) {
      const startTime = Date.now();
      
      try {
        await this.performAction(action);
        const endTime = Date.now();
        
        results.push({
          action,
          success: true,
          responseTime: endTime - startTime,
          userId,
        });
      } catch (error) {
        results.push({
          action,
          success: false,
          error: error.message,
          userId,
        });
      }
    }
    
    return { userId, results };
  }
}

interface LoadTestConfig {
  concurrentUsers: number;
  duration: number;
  rampUpTime: number;
  baseURL: string;
  scenarios: TestScenario[];
}

interface TestScenario {
  name: string;
  weight: number;
  actions: Action[];
}

Bu kapsamlı performance benchmarking ve testing guide'ı, mobil uygulamalar için:

  1. Detaylı Performance Metrics - Tüm önemli performans göstergeleri
  2. Platform-Specific Testing - iOS, Android, React Native, Flutter için özel testler
  3. Automated CI/CD Testing - Sürekli performans izleme
  4. Production Monitoring - Gerçek zamanlı performans takibi
  5. Load Testing - Yük testleri ve stress testleri

Bu dokümantasyon production-ready kod örnekleri ve best practices içermektedir.

Created by Eren Demir.