refactor: unify device analysis and performance testing logic for improved module consistency
This commit is contained in:
@@ -8,6 +8,12 @@ import 'performance_test.dart'; // Make sure this path is correct
|
||||
class DeviceAnalyzer {
|
||||
final DeviceInfoPlugin _deviceInfo = DeviceInfoPlugin();
|
||||
|
||||
// نتيجة الفحص لا تتغير عمليا خلال جلسة واحدة، فنخزنها مؤقتا
|
||||
// كي لا تُعاد الاختبارات الثقيلة (كتابة تخزين + حساب مكثف) كل مرة تُفتح الصفحة.
|
||||
static List<Map<String, dynamic>>? _cachedResult;
|
||||
static DateTime? _cachedAt;
|
||||
static const Duration _cacheTtl = Duration(minutes: 30);
|
||||
|
||||
/// Reads the total RAM from the system's meminfo file.
|
||||
/// Returns the value in Megabytes (MB).
|
||||
Future<double> _readTotalRamMB() async {
|
||||
@@ -53,9 +59,12 @@ class DeviceAnalyzer {
|
||||
}
|
||||
|
||||
/// The main analysis function that runs all checks.
|
||||
Future<Map<String, dynamic>> analyzeDevice() async {
|
||||
List<Map<String, dynamic>> details = [];
|
||||
|
||||
///
|
||||
/// البنود من 1 إلى 7 تقيس قدرة الجهاز الثابتة (لا تتغير خلال الجلسة) وتُخزَّن
|
||||
/// مؤقتا لتفادي إعادة تشغيل الاختبارات الثقيلة (كتابة تخزين + حساب مكثف) في كل
|
||||
/// مرة تُفتح فيها الصفحة. أما بند ضغط الذاكرة الحالي (#8) فيُقاس دائما بشكل فوري
|
||||
/// لأنه رقم متغير باستمرار ولا يصح تجميده مع بقية النتيجة.
|
||||
Future<Map<String, dynamic>> analyzeDevice({bool forceRefresh = false}) async {
|
||||
if (!Platform.isAndroid) {
|
||||
return {
|
||||
'score': 0,
|
||||
@@ -70,6 +79,50 @@ class DeviceAnalyzer {
|
||||
};
|
||||
}
|
||||
|
||||
List<Map<String, dynamic>> staticDetails;
|
||||
if (!forceRefresh &&
|
||||
_cachedResult != null &&
|
||||
_cachedAt != null &&
|
||||
DateTime.now().difference(_cachedAt!) < _cacheTtl) {
|
||||
staticDetails = _cachedResult!;
|
||||
} else {
|
||||
staticDetails = await _computeStaticDetails();
|
||||
_cachedResult = staticDetails;
|
||||
_cachedAt = DateTime.now();
|
||||
}
|
||||
|
||||
// 8. Memory Pressure (Max: 15 points) — يُقاس دائما بشكل فوري، لا يُخزَّن مؤقتا.
|
||||
final usedPercent = await _readUsedRamPercent();
|
||||
int memScore;
|
||||
if (usedPercent <= 60) {
|
||||
memScore = 15;
|
||||
} else if (usedPercent <= 80) {
|
||||
memScore = 10;
|
||||
} else if (usedPercent <= 90) {
|
||||
memScore = 5;
|
||||
} else {
|
||||
memScore = 0;
|
||||
}
|
||||
final memDetail = {
|
||||
'label': 'استخدام الرام الحالي (${usedPercent.toStringAsFixed(0)}%)',
|
||||
'status': memScore >= 10,
|
||||
'achieved_score': memScore,
|
||||
'max_score': 15,
|
||||
};
|
||||
|
||||
final details = [...staticDetails, memDetail];
|
||||
final totalScore = details.fold<int>(
|
||||
0, (sum, item) => sum + (item['achieved_score'] as int));
|
||||
|
||||
return {
|
||||
'score': totalScore.clamp(0, 100),
|
||||
'details': details,
|
||||
};
|
||||
}
|
||||
|
||||
Future<List<Map<String, dynamic>>> _computeStaticDetails() async {
|
||||
List<Map<String, dynamic>> details = [];
|
||||
|
||||
final info = await _deviceInfo.androidInfo;
|
||||
final data = info.data;
|
||||
final features = List<String>.from(data['systemFeatures'] ?? []);
|
||||
@@ -174,32 +227,6 @@ class DeviceAnalyzer {
|
||||
'max_score': 20,
|
||||
});
|
||||
|
||||
// 8. Memory Pressure (Max: 15 points)
|
||||
final usedPercent = await _readUsedRamPercent();
|
||||
int memScore;
|
||||
if (usedPercent <= 60) {
|
||||
memScore = 15;
|
||||
} else if (usedPercent <= 80) {
|
||||
memScore = 10;
|
||||
} else if (usedPercent <= 90) {
|
||||
memScore = 5;
|
||||
} else {
|
||||
memScore = 0;
|
||||
}
|
||||
details.add({
|
||||
'label': 'استخدام الرام الحالي (${usedPercent.toStringAsFixed(0)}%)',
|
||||
'status': memScore >= 10,
|
||||
'achieved_score': memScore,
|
||||
'max_score': 15,
|
||||
});
|
||||
|
||||
// Calculate the final total score by summing up the achieved scores.
|
||||
final totalScore = details.fold<int>(
|
||||
0, (sum, item) => sum + (item['achieved_score'] as int));
|
||||
|
||||
return {
|
||||
'score': totalScore.clamp(0, 100),
|
||||
'details': details,
|
||||
};
|
||||
return details;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,40 +1,59 @@
|
||||
import 'dart:io';
|
||||
import 'dart:isolate';
|
||||
|
||||
class PerformanceTester {
|
||||
/// ✅ فحص سرعة الكتابة إلى التخزين (Storage Write Speed) بوحدة MB/s
|
||||
static Future<double> testStorageWriteSpeed() async {
|
||||
try {
|
||||
final tempDir = Directory.systemTemp;
|
||||
final testFile = File('${tempDir.path}/speed_test.txt');
|
||||
final data = List<int>.filled(1024 * 1024 * 5, 0); // 5MB
|
||||
/// يكرر القياس عدة مرات ويأخذ المتوسط الوسيط لتقليل تأثير الحمل العرضي على الجهاز.
|
||||
static Future<double> testStorageWriteSpeed({int samples = 3}) async {
|
||||
final List<double> speeds = [];
|
||||
for (int i = 0; i < samples; i++) {
|
||||
try {
|
||||
final tempDir = Directory.systemTemp;
|
||||
final testFile = File('${tempDir.path}/speed_test_$i.txt');
|
||||
final data = List<int>.filled(1024 * 1024 * 5, 0); // 5MB
|
||||
|
||||
final stopwatch = Stopwatch()..start();
|
||||
await testFile.writeAsBytes(data, flush: true);
|
||||
stopwatch.stop();
|
||||
final stopwatch = Stopwatch()..start();
|
||||
await testFile.writeAsBytes(data, flush: true);
|
||||
stopwatch.stop();
|
||||
|
||||
await testFile.delete();
|
||||
await testFile.delete();
|
||||
|
||||
double seconds = stopwatch.elapsedMilliseconds / 1000;
|
||||
if (seconds == 0) seconds = 0.001;
|
||||
double seconds = stopwatch.elapsedMilliseconds / 1000;
|
||||
if (seconds == 0) seconds = 0.001;
|
||||
|
||||
final speed = 5 / seconds;
|
||||
return double.parse(speed.toStringAsFixed(2));
|
||||
} catch (e) {
|
||||
print("❌ Storage write error: $e");
|
||||
return 0.0;
|
||||
speeds.add(5 / seconds);
|
||||
} catch (e) {
|
||||
print("❌ Storage write error: $e");
|
||||
}
|
||||
}
|
||||
if (speeds.isEmpty) return 0.0;
|
||||
speeds.sort();
|
||||
final median = speeds[speeds.length ~/ 2];
|
||||
return double.parse(median.toStringAsFixed(2));
|
||||
}
|
||||
|
||||
/// عملية حسابية مكثفة تُنفَّذ داخل isolate منفصل حتى لا تجمّد واجهة المستخدم.
|
||||
static double _cpuBurn(int iterations) {
|
||||
double x = 0;
|
||||
for (int i = 0; i < iterations; i++) {
|
||||
x += i * 0.000001;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
/// ✅ فحص سرعة المعالج (CPU Compute Speed) بوحدة الثواني
|
||||
static Future<double> testCPUSpeed() async {
|
||||
/// يعمل في isolate منفصل (لا يجمّد الواجهة) ويكرر القياس ويأخذ الوسيط.
|
||||
static Future<double> testCPUSpeed({int samples = 3}) async {
|
||||
try {
|
||||
final stopwatch = Stopwatch()..start();
|
||||
double x = 0;
|
||||
for (int i = 0; i < 100000000; i++) {
|
||||
x += i * 0.000001;
|
||||
final List<double> times = [];
|
||||
for (int i = 0; i < samples; i++) {
|
||||
final stopwatch = Stopwatch()..start();
|
||||
await Isolate.run(() => _cpuBurn(100000000));
|
||||
stopwatch.stop();
|
||||
times.add(stopwatch.elapsedMilliseconds / 1000.0);
|
||||
}
|
||||
stopwatch.stop();
|
||||
return stopwatch.elapsedMilliseconds / 1000.0;
|
||||
times.sort();
|
||||
return times[times.length ~/ 2];
|
||||
} catch (e) {
|
||||
print("❌ CPU compute error: $e");
|
||||
return 999.0;
|
||||
|
||||
Reference in New Issue
Block a user