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:
- Detaylı Performance Metrics - Tüm önemli performans göstergeleri
- Platform-Specific Testing - iOS, Android, React Native, Flutter için özel testler
- Automated CI/CD Testing - Sürekli performans izleme
- Production Monitoring - Gerçek zamanlı performans takibi
- Load Testing - Yük testleri ve stress testleri
Bu dokümantasyon production-ready kod örnekleri ve best practices içermektedir.