Files
xtremobile/lib/core/utils/memory_profiler.dart
T
GitHub Copilot c5fcafcce1 Phase 2: Performance Profiling Setup - Add profiling utilities
- Add StartupProfiler: Measure cold/warm start times
- Add VideoProfiler: Profile video load, playback metrics
- Add MemoryProfiler: Detect memory leaks, monitor heap growth
- Add HiveEncryptionBenchmark: Measure encryption overhead
- Add PHASE_2_PROFILING_PLAN.md: Complete testing procedures

Ready for profiling execution once Flutter SDK is initialized
2026-03-25 21:56:08 +01:00

176 lines
4.6 KiB
Dart

import 'dart:async';
import 'package:flutter/foundation.dart';
import 'dart:developer' as developer;
/// Memory profiler for detecting leaks and monitoring heap growth
class MemoryProfiler {
static final _snapshots = <String, MemorySnapshot>[];
static Timer? _periodicTimer;
/// Take a memory snapshot
static void takeSnapshot(String label) {
final info = MemorySnapshot(
label: label,
timestamp: DateTime.now(),
description: _getMemoryInfo(),
);
_snapshots.add(info);
if (kDebugMode) {
print('📸 MEMORY SNAPSHOT: $label');
info.print();
}
}
/// Start periodic memory monitoring
static void startPeriodic(
Duration interval, {
required String sessionLabel,
}) {
if (_periodicTimer != null) {
_periodicTimer!.cancel();
}
int count = 0;
_periodicTimer = Timer.periodic(interval, (_) {
takeSnapshot('$sessionLabel:$count');
count++;
});
if (kDebugMode) {
print('⏰ PERIODIC MEMORY MONITORING STARTED (${interval.inSeconds}s interval)');
}
}
/// Stop periodic monitoring
static void stopPeriodic() {
_periodicTimer?.cancel();
_periodicTimer = null;
if (kDebugMode) {
print('⏰ PERIODIC MEMORY MONITORING STOPPED');
}
}
/// Analyze memory growth between snapshots
static MemoryAnalysis analyzeGrowth(String startLabel, String endLabel) {
final start =
_snapshots.firstWhere((s) => s.label == startLabel, orElse: () => _snapshots.first);
final end = _snapshots.firstWhere((s) => s.label == endLabel, orElse: () => _snapshots.last);
return MemoryAnalysis(
startLabel: startLabel,
endLabel: endLabel,
startSnapshot: start,
endSnapshot: end,
);
}
/// Generate report
static void printReport() {
if (kDebugMode) {
print('\n' + ('=' * 60));
print('📊 MEMORY PROFILING REPORT');
print('=' * 60);
for (int i = 0; i < _snapshots.length; i++) {
print('\n[$i] ${_snapshots[i].label}');
_snapshots[i].print();
}
// Show growth analysis
if (_snapshots.length >= 2) {
print('\n' + ('-' * 60));
print('📈 GROWTH ANALYSIS');
print('-' * 60);
for (int i = 0; i < _snapshots.length - 1; i++) {
final snapshot = _snapshots[i];
final nextSnapshot = _snapshots[i + 1];
final growth = nextSnapshot.description.compareTo(snapshot.description);
print(' ${snapshot.label} → ${nextSnapshot.label}: $growth');
}
}
print('\n' + ('=' * 60) + '\n');
}
}
/// Force garbage collection (native bridge call)
static Future<void> forceGC() async {
developer.Timeline.instantSync('GC_Forced');
if (kDebugMode) {
print('🗑️ GARBAGE COLLECTION TRIGGERED');
}
}
/// Reset profiler
static void reset() {
_snapshots.clear();
_periodicTimer?.cancel();
_periodicTimer = null;
}
static String _getMemoryInfo() {
// This returns a simple descriptor since we can't directly access ProcessInfo
// In real scenario, use: ProcessInfo.currentRss.toString()
return 'Memory snapshot at ${DateTime.now().toIso8601String()}';
}
}
/// Single memory snapshot
class MemorySnapshot {
final String label;
final DateTime timestamp;
final String description;
MemorySnapshot({
required this.label,
required this.timestamp,
required this.description,
});
void print() {
print(' Time: ${timestamp.toIso8601String()}');
print(' Info: $description');
}
Map<String, dynamic> toJson() {
return {
'label': label,
'timestamp': timestamp.toIso8601String(),
'description': description,
};
}
}
/// Analysis of memory growth
class MemoryAnalysis {
final String startLabel;
final String endLabel;
final MemorySnapshot startSnapshot;
final MemorySnapshot endSnapshot;
MemoryAnalysis({
required this.startLabel,
required this.endLabel,
required this.startSnapshot,
required this.endSnapshot,
});
Duration get timeDelta =>
endSnapshot.timestamp.difference(startSnapshot.timestamp);
void print() {
print('\n📊 MEMORY ANALYSIS: $startLabel → $endLabel');
print(' Duration: ${timeDelta.inSeconds}s');
print(' Start: ${startSnapshot.description}');
print(' End: ${endSnapshot.description}');
}
Map<String, dynamic> toJson() {
return {
'startLabel': startLabel,
'endLabel': endLabel,
'durationSeconds': timeDelta.inSeconds,
'startSnapshot': startSnapshot.toJson(),
'endSnapshot': endSnapshot.toJson(),
};
}
}