From 426b0f6c3c6970076c784caeec850cc3d14ec059 Mon Sep 17 00:00:00 2001 From: Anh Date: Tue, 5 Nov 2024 10:50:30 +0700 Subject: [PATCH 01/16] Clean up pubspec.yaml --- flutter/pubspec.lock | 16 ---------------- flutter/pubspec.yaml | 2 -- 2 files changed, 18 deletions(-) diff --git a/flutter/pubspec.lock b/flutter/pubspec.lock index b0890b821..649ac5669 100644 --- a/flutter/pubspec.lock +++ b/flutter/pubspec.lock @@ -836,22 +836,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.11.1" - permission_handler_platform_interface: - dependency: transitive - description: - name: permission_handler_platform_interface - sha256: "6760eb5ef34589224771010805bea6054ad28453906936f843a8cc4d3a55c4a4" - url: "https://pub.dev" - source: hosted - version: "3.12.0" - permission_handler_windows: - dependency: "direct overridden" - description: - name: permission_handler_windows - sha256: cc074aace208760f1eee6aa4fae766b45d947df85bc831cde77009cdb4720098 - url: "https://pub.dev" - source: hosted - version: "0.1.3" petitparser: dependency: transitive description: diff --git a/flutter/pubspec.yaml b/flutter/pubspec.yaml index 36bb66f07..00fa93f69 100644 --- a/flutter/pubspec.yaml +++ b/flutter/pubspec.yaml @@ -68,8 +68,6 @@ dev_dependencies: dependency_overrides: win32: 5.5.0 - # Fix Nuget.exe not found error by using an older version of permission_handler_windows - permission_handler_windows: 0.1.3 flutter_launcher_icons: image_path: "assets/ic_launcher_ios.png" From 001b1cf8f96fd4a4f3dffef7d2e55bdc33916d66 Mon Sep 17 00:00:00 2001 From: Anh Date: Wed, 6 Nov 2024 12:19:24 +0700 Subject: [PATCH 02/16] Add ResourcesScreen --- flutter/lib/l10n/app_en.arb | 1 + flutter/lib/ui/home/app_drawer.dart | 14 +++++ flutter/lib/ui/settings/resources_screen.dart | 53 +++++++++++++++++++ 3 files changed, 68 insertions(+) create mode 100644 flutter/lib/ui/settings/resources_screen.dart diff --git a/flutter/lib/l10n/app_en.arb b/flutter/lib/l10n/app_en.arb index 8eb04d97c..c9524b088 100644 --- a/flutter/lib/l10n/app_en.arb +++ b/flutter/lib/l10n/app_en.arb @@ -7,6 +7,7 @@ "menuHome": "MLPerf Mobile", "menuHistory": "History", "menuSettings": "Settings", + "menuResources": "Resources", "menuAbout": "About", "menuProfile": "Profile", "menuSignIn": "Sign In", diff --git a/flutter/lib/ui/home/app_drawer.dart b/flutter/lib/ui/home/app_drawer.dart index 48497e31a..1b92305b5 100644 --- a/flutter/lib/ui/home/app_drawer.dart +++ b/flutter/lib/ui/home/app_drawer.dart @@ -10,6 +10,7 @@ import 'package:mlperfbench/ui/history/history_list_screen.dart'; import 'package:mlperfbench/ui/home/user_profile.dart'; import 'package:mlperfbench/ui/settings/about_screen.dart'; import 'package:mlperfbench/ui/settings/settings_screen.dart'; +import 'package:mlperfbench/ui/settings/resources_screen.dart'; class AppDrawer extends StatelessWidget { const AppDrawer({super.key}); @@ -104,6 +105,19 @@ class AppDrawer extends StatelessWidget { ); }, ), + ListTile( + leading: const Icon(Icons.file_present), + title: Text(l10n.menuResources), + onTap: () { + Navigator.pop(context); + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const ResourcesScreen(), + ), + ); + }, + ), ListTile( leading: const Icon(Icons.info), title: Text(l10n.menuAbout), diff --git a/flutter/lib/ui/settings/resources_screen.dart b/flutter/lib/ui/settings/resources_screen.dart new file mode 100644 index 000000000..a2973e24f --- /dev/null +++ b/flutter/lib/ui/settings/resources_screen.dart @@ -0,0 +1,53 @@ +import 'dart:io'; + +import 'package:flutter/material.dart'; + +import 'package:provider/provider.dart'; + +import 'package:mlperfbench/app_constants.dart'; +import 'package:mlperfbench/benchmark/run_mode.dart'; +import 'package:mlperfbench/benchmark/state.dart'; +import 'package:mlperfbench/build_info.dart'; +import 'package:mlperfbench/firebase/firebase_manager.dart'; +import 'package:mlperfbench/localizations/app_localizations.dart'; +import 'package:mlperfbench/resources/config_manager.dart'; +import 'package:mlperfbench/store.dart'; +import 'package:mlperfbench/ui/app_styles.dart'; +import 'package:mlperfbench/ui/confirm_dialog.dart'; +import 'package:mlperfbench/ui/settings/task_config_section.dart'; + +class ResourcesScreen extends StatefulWidget { + const ResourcesScreen({super.key}); + + @override + State createState() => _ResourcesScreen(); +} + +class _ResourcesScreen extends State { + late AppLocalizations l10n; + late BenchmarkState state; + late Store store; + + @override + Widget build(BuildContext context) { + store = context.watch(); + state = context.watch(); + l10n = AppLocalizations.of(context)!; + + return Scaffold( + appBar: AppBar(title: Text(l10n.menuResources)), + body: SafeArea( + child: ListView( + padding: const EdgeInsets.only(top: 20), + children: [ + _mainSection(), + const Divider(), + const SizedBox(height: 20) + ], + ))); + } + + Widget _mainSection() { + return const Text('data'); + } +} From a03fb570590e9311c9941e09479e69ac48454208 Mon Sep 17 00:00:00 2001 From: Anh Date: Thu, 7 Nov 2024 09:12:56 +0700 Subject: [PATCH 03/16] Refactor BenchmarkStore.listResources() --- flutter/lib/benchmark/benchmark.dart | 4 +-- flutter/lib/benchmark/state.dart | 10 +++---- flutter/lib/resources/validation_helper.dart | 11 ++++++-- .../benchmark/benchmark_store_test.dart | 28 ++++++++++++++++--- 4 files changed, 38 insertions(+), 15 deletions(-) diff --git a/flutter/lib/benchmark/benchmark.dart b/flutter/lib/benchmark/benchmark.dart index 511f45788..3eb6c1816 100644 --- a/flutter/lib/benchmark/benchmark.dart +++ b/flutter/lib/benchmark/benchmark.dart @@ -154,13 +154,11 @@ class BenchmarkStore { List listResources({ required List modes, - bool skipInactive = false, + required List benchmarks, }) { final result = []; for (final b in benchmarks) { - if (skipInactive && !b.isActive) continue; - for (var mode in modes) { final dataset = mode.chooseDataset(b.taskConfig); final data = Resource( diff --git a/flutter/lib/benchmark/state.dart b/flutter/lib/benchmark/state.dart index d77a348e0..0b72ca8ea 100644 --- a/flutter/lib/benchmark/state.dart +++ b/flutter/lib/benchmark/state.dart @@ -140,13 +140,11 @@ class BenchmarkState extends ChangeNotifier { await Wakelock.enable(); print('start loading resources'); - await resourceManager.handleResources( - _benchmarkStore.listResources( - modes: [taskRunner.perfMode, taskRunner.accuracyMode], - skipInactive: false, - ), - needToPurgeCache, + final resources = _benchmarkStore.listResources( + modes: [taskRunner.perfMode, taskRunner.accuracyMode], + benchmarks: benchmarks, ); + await resourceManager.handleResources(resources, needToPurgeCache); print('finished loading resources'); error = null; stackTrace = null; diff --git a/flutter/lib/resources/validation_helper.dart b/flutter/lib/resources/validation_helper.dart index 50aeebbd4..6cd4e0140 100644 --- a/flutter/lib/resources/validation_helper.dart +++ b/flutter/lib/resources/validation_helper.dart @@ -18,6 +18,9 @@ class ValidationHelper { required this.selectedRunModes, }); + List get activeBenchmarks => + benchmarkStore.benchmarks.where((e) => e.isActive).toList(); + Future validateExternalResourcesDirectory( String errorDescription) async { final dataFolderPath = resourceManager.getDataFolder(); @@ -28,7 +31,9 @@ class ValidationHelper { return 'Data folder does not exist'; } final resources = benchmarkStore.listResources( - modes: selectedRunModes, skipInactive: true); + modes: selectedRunModes, + benchmarks: activeBenchmarks, + ); final missing = await resourceManager.validateResourcesExist(resources); if (missing.isEmpty) return ''; @@ -38,7 +43,9 @@ class ValidationHelper { Future validateOfflineMode(String errorDescription) async { final resources = benchmarkStore.listResources( - modes: selectedRunModes, skipInactive: true); + modes: selectedRunModes, + benchmarks: activeBenchmarks, + ); final internetResources = filterInternetResources(resources); if (internetResources.isEmpty) return ''; diff --git a/flutter/unit_test/benchmark/benchmark_store_test.dart b/flutter/unit_test/benchmark/benchmark_store_test.dart index bd52e6d6f..e4a613220 100644 --- a/flutter/unit_test/benchmark/benchmark_store_test.dart +++ b/flutter/unit_test/benchmark/benchmark_store_test.dart @@ -88,7 +88,12 @@ void main() { ); final modes = [BenchmarkRunMode.accuracy]; - final resources = store.listResources(modes: modes, skipInactive: true); + final activeBenchmarks = + store.benchmarks.where((e) => e.isActive).toList(); + final resources = store.listResources( + modes: modes, + benchmarks: activeBenchmarks, + ); expect(resources.length, 0); }); @@ -100,7 +105,12 @@ void main() { ); final modes = [BenchmarkRunMode.accuracy]; - final resources = store.listResources(modes: modes, skipInactive: true); + final activeBenchmarks = + store.benchmarks.where((e) => e.isActive).toList(); + final resources = store.listResources( + modes: modes, + benchmarks: activeBenchmarks, + ); expect(resources.length, 3); expect( @@ -132,7 +142,12 @@ void main() { ); final modes = [BenchmarkRunMode.performance]; - final resources = store.listResources(modes: modes); + final activeBenchmarks = + store.benchmarks.where((e) => e.isActive).toList(); + final resources = store.listResources( + modes: modes, + benchmarks: activeBenchmarks, + ); expect(resources.length, 2); expect( @@ -161,7 +176,12 @@ void main() { BenchmarkRunMode.accuracyTest, BenchmarkRunMode.performanceTest, ]; - final resources = store.listResources(modes: modes); + final activeBenchmarks = + store.benchmarks.where((e) => e.isActive).toList(); + final resources = store.listResources( + modes: modes, + benchmarks: activeBenchmarks, + ); expect(resources.length, 2); expect( From 45e013ea164261f5f65e072b1b6eeb8b5d85055a Mon Sep 17 00:00:00 2001 From: Anh Date: Thu, 7 Nov 2024 09:42:13 +0700 Subject: [PATCH 04/16] Move clearCacheButton from settings_screen to resources_screen --- flutter/lib/l10n/app_en.arb | 3 +- flutter/lib/ui/settings/resources_screen.dart | 99 ++++++++++++++++--- flutter/lib/ui/settings/settings_screen.dart | 26 ----- 3 files changed, 89 insertions(+), 39 deletions(-) diff --git a/flutter/lib/l10n/app_en.arb b/flutter/lib/l10n/app_en.arb index c9524b088..cd122b258 100644 --- a/flutter/lib/l10n/app_en.arb +++ b/flutter/lib/l10n/app_en.arb @@ -79,7 +79,8 @@ "settingsTaskConfigError": "Path to config is invalid:", "settingsTaskDataFolderTitle": "Data folder", "settingsClearCache": "Clear cache", - "settingsClearCacheConfirm": "All loaded resources will be deleted and downloaded again. Continue?", + "settingsClearCacheConfirm": "All downloaded resources will be deleted. Continue?", + "settingsClearCacheFinished": "Cache cleared.", "settingsUnableSpecifyConfiguration": "Could not specify until benchmarks is running or content is loading", "dialogTitleWarning": "Warning", diff --git a/flutter/lib/ui/settings/resources_screen.dart b/flutter/lib/ui/settings/resources_screen.dart index a2973e24f..cde86b000 100644 --- a/flutter/lib/ui/settings/resources_screen.dart +++ b/flutter/lib/ui/settings/resources_screen.dart @@ -1,6 +1,7 @@ import 'dart:io'; import 'package:flutter/material.dart'; +import 'package:mlperfbench/benchmark/benchmark.dart'; import 'package:provider/provider.dart'; @@ -34,20 +35,94 @@ class _ResourcesScreen extends State { state = context.watch(); l10n = AppLocalizations.of(context)!; + final loadingProgressText = + 'Loading progress: ${(state.loadingProgress * 100).round()}%'; + + final children = []; + + for (var benchmark in state.benchmarks) { + children.add(_listTile(benchmark)); + children.add(const Divider(height: 20)); + } + children.add(Text(loadingProgressText)); + children.add(const Divider(height: 20)); + children.add(_clearCacheButton()); + return Scaffold( - appBar: AppBar(title: Text(l10n.menuResources)), - body: SafeArea( - child: ListView( - padding: const EdgeInsets.only(top: 20), - children: [ - _mainSection(), - const Divider(), - const SizedBox(height: 20) - ], - ))); + appBar: AppBar(title: Text(l10n.menuResources)), + body: SafeArea( + child: Container( + color: Colors.white, + child: ListView( + padding: const EdgeInsets.fromLTRB(0, 20, 0, 20), + children: children, + ), + ), + ), + ); + } + + Widget _listTile(Benchmark benchmark) { + final leadingWidth = 0.10 * MediaQuery.of(context).size.width; + final subtitleWidth = 0.70 * MediaQuery.of(context).size.width; + final trailingWidth = 0.20 * MediaQuery.of(context).size.width; + return ListTile( + leading: SizedBox( + width: leadingWidth, + height: leadingWidth, + child: Padding( + padding: const EdgeInsets.all(4), + child: benchmark.info.icon, + )), + title: Text(benchmark.info.taskName), + subtitle: SizedBox( + width: subtitleWidth, + child: const Text('Download progress...'), + ), + trailing: SizedBox( + width: trailingWidth, + child: _downloadButton(benchmark), + ), + ); + } + + Widget _downloadButton(Benchmark benchmark) { + return ElevatedButton( + onPressed: () { + print('download files for ${benchmark.info.taskName}'); + print(benchmark.taskConfig.datasets.lite.inputPath); + print(benchmark.taskConfig.datasets.lite.groundtruthPath); + }, + child: FittedBox( + fit: BoxFit.scaleDown, + child: const Text('Download'), + ), + ); } - Widget _mainSection() { - return const Text('data'); + Widget _clearCacheButton() { + return TextButton( + style: TextButton.styleFrom( + textStyle: const TextStyle(fontSize: 20), + ), + onPressed: () async { + final dialogAction = + await showConfirmDialog(context, l10n.settingsClearCacheConfirm); + switch (dialogAction) { + case ConfirmDialogAction.ok: + await state.clearCache(); + BotToast.showSimpleNotification( + title: l10n.settingsClearCacheFinished, + hideCloseButton: true, + ); + break; + case ConfirmDialogAction.cancel: + break; + default: + break; + } + }, + child: Text(l10n.settingsClearCache), + ); } } diff --git a/flutter/lib/ui/settings/settings_screen.dart b/flutter/lib/ui/settings/settings_screen.dart index db46c12db..b834d48b8 100644 --- a/flutter/lib/ui/settings/settings_screen.dart +++ b/flutter/lib/ui/settings/settings_screen.dart @@ -41,7 +41,6 @@ class _SettingsScreen extends State { Widget keepLogSwitch = _keepLogSwitch(); Widget cooldownSwitch = _cooldownSwitch(); Widget cooldownSlider = _cooldownSlider(); - Widget clearCacheButton = _clearCacheButton(context); Widget versionText = _versionText(); Widget taskConfig = _taskConfig(context); @@ -61,7 +60,6 @@ class _SettingsScreen extends State { crashlyticsSwitch, taskConfig, const Divider(), - clearCacheButton, const Divider(), versionText, const SizedBox(height: 20) @@ -92,30 +90,6 @@ class _SettingsScreen extends State { ); } - Widget _clearCacheButton(BuildContext context) { - return TextButton( - style: TextButton.styleFrom( - textStyle: const TextStyle(fontSize: 20), - ), - onPressed: () async { - final dialogAction = - await showConfirmDialog(context, l10n.settingsClearCacheConfirm); - switch (dialogAction) { - case ConfirmDialogAction.ok: - await state.clearCache(); - if (!context.mounted) return; - Navigator.pop(context); - break; - case ConfirmDialogAction.cancel: - break; - default: - break; - } - }, - child: Text(l10n.settingsClearCache), - ); - } - Widget _cooldownSlider() { return Slider( value: store.cooldownDuration.toDouble(), From e32f0d102f5c2a19d5b52a2b9fb91bd8b9765ed1 Mon Sep 17 00:00:00 2001 From: Anh Date: Thu, 7 Nov 2024 20:34:34 +0700 Subject: [PATCH 05/16] Show resource download status --- flutter/lib/resources/validation_helper.dart | 9 ++++++++ flutter/lib/ui/settings/resources_screen.dart | 23 ++++++++++++++++--- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/flutter/lib/resources/validation_helper.dart b/flutter/lib/resources/validation_helper.dart index 6cd4e0140..00fecfe23 100644 --- a/flutter/lib/resources/validation_helper.dart +++ b/flutter/lib/resources/validation_helper.dart @@ -54,4 +54,13 @@ class ValidationHelper { .mapIndexed((i, element) => '\n${i + 1}) $element') .join(); } + + Future validateResourcesExist(Benchmark benchmark) async { + final resources = benchmarkStore.listResources( + modes: [BenchmarkRunMode.performance, BenchmarkRunMode.accuracy], + benchmarks: [benchmark], + ); + final missing = await resourceManager.validateResourcesExist(resources); + return missing.isEmpty; + } } diff --git a/flutter/lib/ui/settings/resources_screen.dart b/flutter/lib/ui/settings/resources_screen.dart index cde86b000..142000853 100644 --- a/flutter/lib/ui/settings/resources_screen.dart +++ b/flutter/lib/ui/settings/resources_screen.dart @@ -1,5 +1,7 @@ import 'dart:io'; +import 'package:bot_toast/bot_toast.dart'; +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:mlperfbench/benchmark/benchmark.dart'; @@ -41,7 +43,7 @@ class _ResourcesScreen extends State { final children = []; for (var benchmark in state.benchmarks) { - children.add(_listTile(benchmark)); + children.add(_listTileBuilder(benchmark)); children.add(const Divider(height: 20)); } children.add(Text(loadingProgressText)); @@ -62,10 +64,11 @@ class _ResourcesScreen extends State { ); } - Widget _listTile(Benchmark benchmark) { + Widget _listTile(Benchmark benchmark, bool downloaded) { final leadingWidth = 0.10 * MediaQuery.of(context).size.width; final subtitleWidth = 0.70 * MediaQuery.of(context).size.width; final trailingWidth = 0.20 * MediaQuery.of(context).size.width; + final status = downloaded ? 'downloaded' : 'not downloaded'; return ListTile( leading: SizedBox( width: leadingWidth, @@ -77,7 +80,7 @@ class _ResourcesScreen extends State { title: Text(benchmark.info.taskName), subtitle: SizedBox( width: subtitleWidth, - child: const Text('Download progress...'), + child: Text(status), ), trailing: SizedBox( width: trailingWidth, @@ -86,6 +89,20 @@ class _ResourcesScreen extends State { ); } + Widget _listTileBuilder(Benchmark benchmark) { + return FutureBuilder( + future: state.validator.validateResourcesExist(benchmark), + builder: (BuildContext context, AsyncSnapshot snapshot) { + if (snapshot.hasData && snapshot.data != null) { + final downloaded = snapshot.data!; + return _listTile(benchmark, downloaded); + } else { + return const Text('Checking download status'); + } + }, + ); + } + Widget _downloadButton(Benchmark benchmark) { return ElevatedButton( onPressed: () { From 192b9ebbc9bce2114c4cbad7ddbb3b3ba90ad93d Mon Sep 17 00:00:00 2001 From: Anh Date: Wed, 13 Nov 2024 14:03:44 +0700 Subject: [PATCH 06/16] Remove BenchmarkStateEnum.downloading --- flutter/lib/benchmark/state.dart | 2 -- flutter/lib/ui/root/main_screen.dart | 2 -- 2 files changed, 4 deletions(-) diff --git a/flutter/lib/benchmark/state.dart b/flutter/lib/benchmark/state.dart index 0b72ca8ea..581491e80 100644 --- a/flutter/lib/benchmark/state.dart +++ b/flutter/lib/benchmark/state.dart @@ -22,7 +22,6 @@ import 'package:mlperfbench/state/task_runner.dart'; import 'package:mlperfbench/store.dart'; enum BenchmarkStateEnum { - downloading, waiting, running, aborting, @@ -214,7 +213,6 @@ class BenchmarkState extends ChangeNotifier { } BenchmarkStateEnum get state { - if (!resourceManager.done) return BenchmarkStateEnum.downloading; switch (_doneRunning) { case null: return BenchmarkStateEnum.waiting; diff --git a/flutter/lib/ui/root/main_screen.dart b/flutter/lib/ui/root/main_screen.dart index 0e262d0aa..9c8a9f3ac 100644 --- a/flutter/lib/ui/root/main_screen.dart +++ b/flutter/lib/ui/root/main_screen.dart @@ -21,8 +21,6 @@ class MainScreen extends StatelessWidget { } switch (state.state) { - case BenchmarkStateEnum.downloading: - return const ResourceLoadingScreen(); case BenchmarkStateEnum.waiting: return const BenchmarkStartScreen(); case BenchmarkStateEnum.aborting: From fae0adda6d92295c74e142664b1bf62f181fe017 Mon Sep 17 00:00:00 2001 From: Anh Date: Wed, 13 Nov 2024 17:35:40 +0700 Subject: [PATCH 07/16] Refactor validateResourcesExist() --- flutter/lib/resources/resource_manager.dart | 25 +++++++++------------ 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/flutter/lib/resources/resource_manager.dart b/flutter/lib/resources/resource_manager.dart index b0a7f3b08..5ea8d490e 100644 --- a/flutter/lib/resources/resource_manager.dart +++ b/flutter/lib/resources/resource_manager.dart @@ -49,7 +49,8 @@ class ResourceManager { return resourceSystemPath; } if (isInternetResource(uri)) { - return cacheManager.get(uri)!; + final resourceSystemPath = cacheManager.get(uri); + return resourceSystemPath ?? ''; } if (File(uri).isAbsolute) { return uri; @@ -87,16 +88,6 @@ class ResourceManager { return _dataPrefix; } - Future isResourceExist(String? uri) async { - if (uri == null) return false; - - final path = get(uri); - - return path == '' || - await File(path).exists() || - await Directory(path).exists(); - } - Future isChecksumMatched(String filePath, String md5Checksum) async { var fileStream = File(filePath).openRead(); final checksum = (await md5.bind(fileStream).first).toString(); @@ -175,9 +166,15 @@ class ResourceManager { Future> validateResourcesExist(List resources) async { final missingResources = []; for (var r in resources) { - if (!await isResourceExist(r.path)) { - final resolvedPath = get(r.path); - missingResources.add(resolvedPath); + final resolvedPath = get(r.path); + if (resolvedPath.isEmpty) { + missingResources.add(r.path); + } else { + final isResourceExist = await File(resolvedPath).exists() || + await Directory(resolvedPath).exists(); + if (!isResourceExist) { + missingResources.add(resolvedPath); + } } } return missingResources; From 53baa27970bad56c0c0982af66efb5318d39060d Mon Sep 17 00:00:00 2001 From: Anh Date: Wed, 13 Nov 2024 17:50:25 +0700 Subject: [PATCH 08/16] Add downloadMissing parameter to CacheManager --- flutter/lib/benchmark/state.dart | 10 +++++++--- flutter/lib/resources/cache_manager.dart | 12 +++++++---- flutter/lib/resources/resource_manager.dart | 20 +++++++++++-------- .../lib/ui/settings/task_config_section.dart | 2 +- .../resources/cache_manager_test.dart | 2 +- 5 files changed, 29 insertions(+), 17 deletions(-) diff --git a/flutter/lib/benchmark/state.dart b/flutter/lib/benchmark/state.dart index 581491e80..89dfa6d15 100644 --- a/flutter/lib/benchmark/state.dart +++ b/flutter/lib/benchmark/state.dart @@ -120,7 +120,7 @@ class BenchmarkState extends ChangeNotifier { // ignore: avoid_void_async void deferredLoadResources() async { try { - await loadResources(); + await loadResources(downloadMissing: false); } catch (e, trace) { print("can't load resources: $e"); print(trace); @@ -131,7 +131,7 @@ class BenchmarkState extends ChangeNotifier { } } - Future loadResources() async { + Future loadResources({required bool downloadMissing}) async { final newAppVersion = '${BuildInfoHelper.info.version}+${BuildInfoHelper.info.buildNumber}'; var needToPurgeCache = _store.previousAppVersion != newAppVersion; @@ -143,7 +143,11 @@ class BenchmarkState extends ChangeNotifier { modes: [taskRunner.perfMode, taskRunner.accuracyMode], benchmarks: benchmarks, ); - await resourceManager.handleResources(resources, needToPurgeCache); + await resourceManager.handleResources( + resources, + needToPurgeCache, + downloadMissing, + ); print('finished loading resources'); error = null; stackTrace = null; diff --git a/flutter/lib/resources/cache_manager.dart b/flutter/lib/resources/cache_manager.dart index ec8276349..48d93ab4c 100644 --- a/flutter/lib/resources/cache_manager.dart +++ b/flutter/lib/resources/cache_manager.dart @@ -81,8 +81,11 @@ class CacheManager { return deleteLoadedResources(currentResources, atLeastDaysOld); } - Future cache(List urls, - void Function(double, String) reportProgress, bool purgeOldCache) async { + Future cache( + List urls, + void Function(double, String) reportProgress, + bool purgeOldCache, + bool downloadMissing) async { final resourcesToDownload = []; _resourcesMap = {}; @@ -106,8 +109,9 @@ class CacheManager { continue; } - await _download(resourcesToDownload, reportProgress); - + if (downloadMissing) { + await _download(resourcesToDownload, reportProgress); + } if (purgeOldCache) { await purgeOutdatedCache(_oldFilesAgeInDays); } diff --git a/flutter/lib/resources/resource_manager.dart b/flutter/lib/resources/resource_manager.dart index 5ea8d490e..1957d0a06 100644 --- a/flutter/lib/resources/resource_manager.dart +++ b/flutter/lib/resources/resource_manager.dart @@ -94,8 +94,8 @@ class ResourceManager { return checksum == md5Checksum; } - Future handleResources( - List resources, bool purgeOldCache) async { + Future handleResources(List resources, bool purgeOldCache, + bool downloadMissing) async { _loadingPath = ''; _loadingProgress = 0.0; _done = false; @@ -112,12 +112,16 @@ class ResourceManager { } final internetPaths = internetResources.map((e) => e.path).toList(); - await cacheManager.cache(internetPaths, - (double currentProgress, String currentPath) { - _loadingProgress = currentProgress; - _loadingPath = currentPath; - _onUpdate(); - }, purgeOldCache); + await cacheManager.cache( + internetPaths, + (double currentProgress, String currentPath) { + _loadingProgress = currentProgress; + _loadingPath = currentPath; + _onUpdate(); + }, + purgeOldCache, + downloadMissing, + ); final checksumFailed = await validateResourcesChecksum(resources); if (checksumFailed.isNotEmpty) { diff --git a/flutter/lib/ui/settings/task_config_section.dart b/flutter/lib/ui/settings/task_config_section.dart index 428238bce..08ab8b8ae 100644 --- a/flutter/lib/ui/settings/task_config_section.dart +++ b/flutter/lib/ui/settings/task_config_section.dart @@ -75,7 +75,7 @@ class TaskConfigSection extends StatelessWidget { await state.setTaskConfig(name: configuration.name); if (!context.mounted) return; Navigator.of(context).popUntil((route) => route.isFirst); - await state.loadResources(); + await state.loadResources(downloadMissing: false); } catch (e) { if (!context.mounted) return; await showErrorDialog( diff --git a/flutter/unit_test/resources/cache_manager_test.dart b/flutter/unit_test/resources/cache_manager_test.dart index 6f5da8e02..c18ffcbbc 100644 --- a/flutter/unit_test/resources/cache_manager_test.dart +++ b/flutter/unit_test/resources/cache_manager_test.dart @@ -15,7 +15,7 @@ void main() async { setUp(() async { manager = CacheManager('/tmp/resources'); - await manager.cache(paths, (val, str) {}, true); + await manager.cache(paths, (val, str) {}, true, true); }); test('get', () async { From 3311bb0cef550845e218adaab479cb6824c63242 Mon Sep 17 00:00:00 2001 From: Anh Date: Wed, 13 Nov 2024 18:25:45 +0700 Subject: [PATCH 09/16] Show download status for each BenchmarkRunMode --- flutter/lib/resources/validation_helper.dart | 5 +- flutter/lib/ui/settings/resources_screen.dart | 63 ++++++++++--------- 2 files changed, 38 insertions(+), 30 deletions(-) diff --git a/flutter/lib/resources/validation_helper.dart b/flutter/lib/resources/validation_helper.dart index 00fecfe23..a90322b8e 100644 --- a/flutter/lib/resources/validation_helper.dart +++ b/flutter/lib/resources/validation_helper.dart @@ -55,9 +55,10 @@ class ValidationHelper { .join(); } - Future validateResourcesExist(Benchmark benchmark) async { + Future validateResourcesExist( + Benchmark benchmark, BenchmarkRunMode mode) async { final resources = benchmarkStore.listResources( - modes: [BenchmarkRunMode.performance, BenchmarkRunMode.accuracy], + modes: [mode], benchmarks: [benchmark], ); final missing = await resourceManager.validateResourcesExist(resources); diff --git a/flutter/lib/ui/settings/resources_screen.dart b/flutter/lib/ui/settings/resources_screen.dart index 142000853..ebb985d1f 100644 --- a/flutter/lib/ui/settings/resources_screen.dart +++ b/flutter/lib/ui/settings/resources_screen.dart @@ -37,16 +37,13 @@ class _ResourcesScreen extends State { state = context.watch(); l10n = AppLocalizations.of(context)!; - final loadingProgressText = - 'Loading progress: ${(state.loadingProgress * 100).round()}%'; - final children = []; for (var benchmark in state.benchmarks) { children.add(_listTileBuilder(benchmark)); children.add(const Divider(height: 20)); } - children.add(Text(loadingProgressText)); + children.add(_downloadButton()); children.add(const Divider(height: 20)); children.add(_clearCacheButton()); @@ -56,7 +53,7 @@ class _ResourcesScreen extends State { child: Container( color: Colors.white, child: ListView( - padding: const EdgeInsets.fromLTRB(0, 20, 0, 20), + padding: const EdgeInsets.fromLTRB(10, 20, 10, 20), children: children, ), ), @@ -64,11 +61,9 @@ class _ResourcesScreen extends State { ); } - Widget _listTile(Benchmark benchmark, bool downloaded) { + Widget _listTileBuilder(Benchmark benchmark) { final leadingWidth = 0.10 * MediaQuery.of(context).size.width; - final subtitleWidth = 0.70 * MediaQuery.of(context).size.width; - final trailingWidth = 0.20 * MediaQuery.of(context).size.width; - final status = downloaded ? 'downloaded' : 'not downloaded'; + final subtitleWidth = 0.90 * MediaQuery.of(context).size.width; return ListTile( leading: SizedBox( width: leadingWidth, @@ -80,22 +75,35 @@ class _ResourcesScreen extends State { title: Text(benchmark.info.taskName), subtitle: SizedBox( width: subtitleWidth, - child: Text(status), - ), - trailing: SizedBox( - width: trailingWidth, - child: _downloadButton(benchmark), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _downloadStatus(benchmark, BenchmarkRunMode.performance), + _downloadStatus(benchmark, BenchmarkRunMode.accuracy), + ], + ), ), ); } - Widget _listTileBuilder(Benchmark benchmark) { + Widget _downloadStatus(Benchmark benchmark, BenchmarkRunMode mode) { return FutureBuilder( - future: state.validator.validateResourcesExist(benchmark), + future: state.validator.validateResourcesExist(benchmark, mode), builder: (BuildContext context, AsyncSnapshot snapshot) { if (snapshot.hasData && snapshot.data != null) { final downloaded = snapshot.data!; - return _listTile(benchmark, downloaded); + const downloadedIcon = + Icon(Icons.check_circle, size: 16, color: Colors.green); + const notDownloadedIcon = + Icon(Icons.check_circle_outline, size: 16, color: Colors.grey); + return Row( + children: [ + downloaded ? downloadedIcon : notDownloadedIcon, + const SizedBox(width: 10), + Text(mode.readable), + ], + ); } else { return const Text('Checking download status'); } @@ -103,25 +111,20 @@ class _ResourcesScreen extends State { ); } - Widget _downloadButton(Benchmark benchmark) { + Widget _downloadButton() { return ElevatedButton( onPressed: () { - print('download files for ${benchmark.info.taskName}'); - print(benchmark.taskConfig.datasets.lite.inputPath); - print(benchmark.taskConfig.datasets.lite.groundtruthPath); + print('download resources'); }, - child: FittedBox( + child: const FittedBox( fit: BoxFit.scaleDown, - child: const Text('Download'), + child: Text('Download'), ), ); } Widget _clearCacheButton() { - return TextButton( - style: TextButton.styleFrom( - textStyle: const TextStyle(fontSize: 20), - ), + return ElevatedButton( onPressed: () async { final dialogAction = await showConfirmDialog(context, l10n.settingsClearCacheConfirm); @@ -139,7 +142,11 @@ class _ResourcesScreen extends State { break; } }, - child: Text(l10n.settingsClearCache), + style: ElevatedButton.styleFrom(backgroundColor: Colors.red), + child: FittedBox( + fit: BoxFit.scaleDown, + child: Text(l10n.settingsClearCache), + ), ); } } From d56a5309a441d060b0daef96ee0c5708276a8af5 Mon Sep 17 00:00:00 2001 From: Anh Date: Wed, 13 Nov 2024 18:56:26 +0700 Subject: [PATCH 10/16] Show download progress and url --- flutter/lib/l10n/app_en.arb | 3 + flutter/lib/ui/settings/resources_screen.dart | 114 ++++++++++++------ 2 files changed, 77 insertions(+), 40 deletions(-) diff --git a/flutter/lib/l10n/app_en.arb b/flutter/lib/l10n/app_en.arb index cd122b258..e614d8bd8 100644 --- a/flutter/lib/l10n/app_en.arb +++ b/flutter/lib/l10n/app_en.arb @@ -116,6 +116,9 @@ "benchInfoLanguageProcessingDesc": "Question Answering finds the best answer to an input question based on a body of text, and is commonly employed in applications such as virtual assistants and chatbots. The reference model, MobileBERT, is evaluated on the Stanford Question Answering Dataset (SQUAD) v1.1 Dev-mini. The task requires a minimum F1-score of 87.4% (93% of FP32 F1-score of 93.08%).\n\nMobileBERT is a streamlined, mobile-optimized version of the larger BERT_LARGE network. It features bottleneck structures and a carefully designed balance between self-attention and feed-forward networks. While BERT is task-agnostic and can be applied to various downstream natural language processing tasks, the MobileBERT variant used in MLPerf is specifically fine-tuned for question answering.", "benchInfoSuperResolutionDesc": "Image Super Resolution (SR) upscales a lower resolution input into a higher resolution output image, enhancing the quality and detail. It is a common task in many mobile applications such as digital zoom. The reference model, EDSR F32B5, is a lightweight member of the Enhanced Deep Super Resolution (EDSR) family that is trained for 2X super resolution on the DIV2K dataset with bicubic downsampling and tested on the OpenSR test-set which comprises 25 selected 1920x1080 HDR images. The benchmark requires a minimum accuracy of 33 dB Peak Signal to Noise Ratio (PSNR) relative to a 33.58 dB accuracy with FP32.\n\nThe EDSR family of models demonstrated excellent performance by winning a super resolution challenge at CVPR 2017. The EDSR F32B5 reference model features five EDSR blocks, each with 32 feature maps. The EDSR block is a simple residual block consisting of a residual connection on one branch and a convolution-ReLU-convolution on the other branch. The final upsampling layer is a depth-to-space operator, which facilitates the x2 super resolution process.", + "resourceDownload": "Download", + "resourceClear": "Clear", + "resourceChecking": "Checking download status", "resourceErrorMessage": "Some resources failed to load.\nIf you didn't change config from default you can try clearing the cache.\nIf you use a custom configuration file ensure that it has correct structure or switch back to default config.", "resourceErrorSelectTaskFile": "Update task configuration", "resourceErrorCurrentConfig": "Current task config file: ", diff --git a/flutter/lib/ui/settings/resources_screen.dart b/flutter/lib/ui/settings/resources_screen.dart index ebb985d1f..e3a62218c 100644 --- a/flutter/lib/ui/settings/resources_screen.dart +++ b/flutter/lib/ui/settings/resources_screen.dart @@ -1,23 +1,14 @@ -import 'dart:io'; - import 'package:bot_toast/bot_toast.dart'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:mlperfbench/benchmark/benchmark.dart'; import 'package:provider/provider.dart'; -import 'package:mlperfbench/app_constants.dart'; import 'package:mlperfbench/benchmark/run_mode.dart'; import 'package:mlperfbench/benchmark/state.dart'; -import 'package:mlperfbench/build_info.dart'; -import 'package:mlperfbench/firebase/firebase_manager.dart'; import 'package:mlperfbench/localizations/app_localizations.dart'; -import 'package:mlperfbench/resources/config_manager.dart'; import 'package:mlperfbench/store.dart'; -import 'package:mlperfbench/ui/app_styles.dart'; import 'package:mlperfbench/ui/confirm_dialog.dart'; -import 'package:mlperfbench/ui/settings/task_config_section.dart'; class ResourcesScreen extends StatefulWidget { const ResourcesScreen({super.key}); @@ -31,6 +22,9 @@ class _ResourcesScreen extends State { late BenchmarkState state; late Store store; + bool get downloading => + (state.loadingProgress > 0.0 && state.loadingProgress < 0.999); + @override Widget build(BuildContext context) { store = context.watch(); @@ -43,8 +37,10 @@ class _ResourcesScreen extends State { children.add(_listTileBuilder(benchmark)); children.add(const Divider(height: 20)); } + children.add(const SizedBox(height: 20)); + children.add(_downloadProgress()); children.add(_downloadButton()); - children.add(const Divider(height: 20)); + children.add(const SizedBox(height: 20)); children.add(_clearCacheButton()); return Scaffold( @@ -105,47 +101,85 @@ class _ResourcesScreen extends State { ], ); } else { - return const Text('Checking download status'); + return Text(l10n.resourceChecking); } }, ); } + Widget _downloadProgress() { + if (!downloading) { + return const SizedBox(height: 0); + } + return SizedBox( + height: 88, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + state.loadingPath, + maxLines: 5, + overflow: TextOverflow.ellipsis, + style: const TextStyle( + fontSize: 12.0, + ), + ), + const SizedBox(height: 8), + LinearProgressIndicator( + value: state.loadingProgress, + minHeight: 8, + ), + ], + ), + ); + } + Widget _downloadButton() { - return ElevatedButton( - onPressed: () { - print('download resources'); - }, - child: const FittedBox( - fit: BoxFit.scaleDown, - child: Text('Download'), + return AbsorbPointer( + absorbing: downloading, + child: ElevatedButton( + onPressed: () { + state.loadResources(downloadMissing: true); + }, + style: ElevatedButton.styleFrom( + backgroundColor: downloading ? Colors.grey : Colors.blue), + child: FittedBox( + fit: BoxFit.scaleDown, + child: Text(l10n.resourceDownload), + ), ), ); } + // TODO: add confirm dialog Widget _clearCacheButton() { - return ElevatedButton( - onPressed: () async { - final dialogAction = - await showConfirmDialog(context, l10n.settingsClearCacheConfirm); - switch (dialogAction) { - case ConfirmDialogAction.ok: - await state.clearCache(); - BotToast.showSimpleNotification( - title: l10n.settingsClearCacheFinished, - hideCloseButton: true, - ); - break; - case ConfirmDialogAction.cancel: - break; - default: - break; - } - }, - style: ElevatedButton.styleFrom(backgroundColor: Colors.red), - child: FittedBox( - fit: BoxFit.scaleDown, - child: Text(l10n.settingsClearCache), + return AbsorbPointer( + absorbing: downloading, + child: ElevatedButton( + onPressed: () async { + final dialogAction = + await showConfirmDialog(context, l10n.settingsClearCacheConfirm); + switch (dialogAction) { + case ConfirmDialogAction.ok: + await state.clearCache(); + BotToast.showSimpleNotification( + title: l10n.settingsClearCacheFinished, + hideCloseButton: true, + ); + break; + case ConfirmDialogAction.cancel: + break; + default: + break; + } + }, + style: ElevatedButton.styleFrom( + backgroundColor: downloading ? Colors.grey : Colors.red), + child: FittedBox( + fit: BoxFit.scaleDown, + child: Text(l10n.resourceClear), + ), ), ); } From 56ab75730eb591a3ebfec52d60946515cd771fa7 Mon Sep 17 00:00:00 2001 From: Anh Date: Fri, 15 Nov 2024 13:39:18 +0700 Subject: [PATCH 11/16] Show missing and existed resources --- flutter/lib/l10n/app_en.arb | 1 + flutter/lib/resources/resource_manager.dart | 17 ++- flutter/lib/resources/validation_helper.dart | 9 +- flutter/lib/ui/home/app_drawer.dart | 2 +- flutter/lib/ui/settings/resources_screen.dart | 118 ++++++++++++++++-- 5 files changed, 127 insertions(+), 20 deletions(-) diff --git a/flutter/lib/l10n/app_en.arb b/flutter/lib/l10n/app_en.arb index e614d8bd8..3f3c07eb6 100644 --- a/flutter/lib/l10n/app_en.arb +++ b/flutter/lib/l10n/app_en.arb @@ -119,6 +119,7 @@ "resourceDownload": "Download", "resourceClear": "Clear", "resourceChecking": "Checking download status", + "resourceDownloading": "Downloading", "resourceErrorMessage": "Some resources failed to load.\nIf you didn't change config from default you can try clearing the cache.\nIf you use a custom configuration file ensure that it has correct structure or switch back to default config.", "resourceErrorSelectTaskFile": "Update task configuration", "resourceErrorCurrentConfig": "Current task config file: ", diff --git a/flutter/lib/resources/resource_manager.dart b/flutter/lib/resources/resource_manager.dart index 1957d0a06..f4d6d561f 100644 --- a/flutter/lib/resources/resource_manager.dart +++ b/flutter/lib/resources/resource_manager.dart @@ -167,8 +167,11 @@ class ResourceManager { resultManager = await ResultManager.create(applicationDirectory); } - Future> validateResourcesExist(List resources) async { + // Returns a map of { true: [existedResources], false: [missingResources] } + Future>> validateResourcesExist( + List resources) async { final missingResources = []; + final existedResources = []; for (var r in resources) { final resolvedPath = get(r.path); if (resolvedPath.isEmpty) { @@ -176,12 +179,18 @@ class ResourceManager { } else { final isResourceExist = await File(resolvedPath).exists() || await Directory(resolvedPath).exists(); - if (!isResourceExist) { - missingResources.add(resolvedPath); + if (isResourceExist) { + existedResources.add(r.path); + } else { + missingResources.add(r.path); } } } - return missingResources; + final result = { + false: missingResources, + true: existedResources, + }; + return result; } Future> validateResourcesChecksum( diff --git a/flutter/lib/resources/validation_helper.dart b/flutter/lib/resources/validation_helper.dart index a90322b8e..ce577e4cd 100644 --- a/flutter/lib/resources/validation_helper.dart +++ b/flutter/lib/resources/validation_helper.dart @@ -34,7 +34,8 @@ class ValidationHelper { modes: selectedRunModes, benchmarks: activeBenchmarks, ); - final missing = await resourceManager.validateResourcesExist(resources); + final result = await resourceManager.validateResourcesExist(resources); + final missing = result[false] ?? []; if (missing.isEmpty) return ''; return errorDescription + @@ -55,13 +56,13 @@ class ValidationHelper { .join(); } - Future validateResourcesExist( + Future>> validateResourcesExist( Benchmark benchmark, BenchmarkRunMode mode) async { final resources = benchmarkStore.listResources( modes: [mode], benchmarks: [benchmark], ); - final missing = await resourceManager.validateResourcesExist(resources); - return missing.isEmpty; + final result = await resourceManager.validateResourcesExist(resources); + return result; } } diff --git a/flutter/lib/ui/home/app_drawer.dart b/flutter/lib/ui/home/app_drawer.dart index 1b92305b5..b657daa53 100644 --- a/flutter/lib/ui/home/app_drawer.dart +++ b/flutter/lib/ui/home/app_drawer.dart @@ -9,8 +9,8 @@ import 'package:mlperfbench/ui/app_styles.dart'; import 'package:mlperfbench/ui/history/history_list_screen.dart'; import 'package:mlperfbench/ui/home/user_profile.dart'; import 'package:mlperfbench/ui/settings/about_screen.dart'; -import 'package:mlperfbench/ui/settings/settings_screen.dart'; import 'package:mlperfbench/ui/settings/resources_screen.dart'; +import 'package:mlperfbench/ui/settings/settings_screen.dart'; class AppDrawer extends StatelessWidget { const AppDrawer({super.key}); diff --git a/flutter/lib/ui/settings/resources_screen.dart b/flutter/lib/ui/settings/resources_screen.dart index e3a62218c..d3341faae 100644 --- a/flutter/lib/ui/settings/resources_screen.dart +++ b/flutter/lib/ui/settings/resources_screen.dart @@ -1,9 +1,9 @@ -import 'package:bot_toast/bot_toast.dart'; import 'package:flutter/material.dart'; -import 'package:mlperfbench/benchmark/benchmark.dart'; +import 'package:bot_toast/bot_toast.dart'; import 'package:provider/provider.dart'; +import 'package:mlperfbench/benchmark/benchmark.dart'; import 'package:mlperfbench/benchmark/run_mode.dart'; import 'package:mlperfbench/benchmark/state.dart'; import 'package:mlperfbench/localizations/app_localizations.dart'; @@ -84,18 +84,43 @@ class _ResourcesScreen extends State { } Widget _downloadStatus(Benchmark benchmark, BenchmarkRunMode mode) { - return FutureBuilder( + return FutureBuilder>>( future: state.validator.validateResourcesExist(benchmark, mode), - builder: (BuildContext context, AsyncSnapshot snapshot) { + builder: (BuildContext context, + AsyncSnapshot>> snapshot) { if (snapshot.hasData && snapshot.data != null) { - final downloaded = snapshot.data!; + const double size = 18; const downloadedIcon = - Icon(Icons.check_circle, size: 16, color: Colors.green); + Icon(Icons.check_circle, size: size, color: Colors.green); const notDownloadedIcon = - Icon(Icons.check_circle_outline, size: 16, color: Colors.grey); + Icon(Icons.check_circle_outline, size: size, color: Colors.grey); + final result = snapshot.data!; + final missing = result[false] ?? []; + final existed = result[true] ?? []; + final downloaded = missing.isEmpty; return Row( children: [ - downloaded ? downloadedIcon : notDownloadedIcon, + SizedBox( + height: size, + width: size, + child: IconButton( + padding: const EdgeInsets.all(0), + icon: downloaded ? downloadedIcon : notDownloadedIcon, + onPressed: () { + showDialog( + context: context, + builder: (BuildContext context) { + return _ResourcesTable( + taskName: benchmark.info.taskName, + modeName: mode.readable, + missing: missing, + existed: existed, + ); + }, + ); + }, + ), + ), const SizedBox(width: 10), Text(mode.readable), ], @@ -117,13 +142,16 @@ class _ResourcesScreen extends State { mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ + Text( + l10n.resourceDownloading, + maxLines: 1, + style: const TextStyle(fontSize: 12), + ), Text( state.loadingPath, maxLines: 5, overflow: TextOverflow.ellipsis, - style: const TextStyle( - fontSize: 12.0, - ), + style: const TextStyle(fontSize: 12), ), const SizedBox(height: 8), LinearProgressIndicator( @@ -184,3 +212,71 @@ class _ResourcesScreen extends State { ); } } + +class _ResourcesTable extends StatelessWidget { + final String taskName; + final String modeName; + final List missing; + final List existed; + + const _ResourcesTable({ + required this.taskName, + required this.modeName, + required this.missing, + required this.existed, + }); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Column( + children: [ + Text(taskName), + Text(modeName), + ], + ), + ), + body: SingleChildScrollView( + scrollDirection: Axis.vertical, + child: Column( + children: [ + const SizedBox(height: 20), + Table( + columnWidths: const { + 0: FixedColumnWidth(40), + 1: FlexColumnWidth(), + }, + border: TableBorder.all(color: Colors.grey), + defaultVerticalAlignment: TableCellVerticalAlignment.top, + children: [ + for (var path in missing) _row(path, false), + for (var path in existed) _row(path, true), + ], + ), + ], + ), + ), + ); + } + + TableRow _row(String path, bool existed) { + return TableRow( + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: Icon( + existed ? Icons.check_circle : Icons.check_circle_outline, + color: existed + ? Colors.green + : Colors.grey, // Grey check mark for missing + ), + ), + Padding( + padding: const EdgeInsets.all(8.0), + child: Text(path), + ), + ], + ); + } +} From 94aef4fc999e8fa8400e833f9cecfebd1dc5698b Mon Sep 17 00:00:00 2001 From: Anh Date: Fri, 15 Nov 2024 15:13:16 +0700 Subject: [PATCH 12/16] Cleanup --- flutter/lib/resources/resource_manager.dart | 4 +++- flutter/lib/ui/root/main_screen.dart | 1 - flutter/lib/ui/settings/resources_screen.dart | 1 - flutter/lib/ui/settings/settings_screen.dart | 1 - 4 files changed, 3 insertions(+), 4 deletions(-) diff --git a/flutter/lib/resources/resource_manager.dart b/flutter/lib/resources/resource_manager.dart index f4d6d561f..431f8683d 100644 --- a/flutter/lib/resources/resource_manager.dart +++ b/flutter/lib/resources/resource_manager.dart @@ -97,7 +97,7 @@ class ResourceManager { Future handleResources(List resources, bool purgeOldCache, bool downloadMissing) async { _loadingPath = ''; - _loadingProgress = 0.0; + _loadingProgress = 0.001; _done = false; _onUpdate(); @@ -132,6 +132,8 @@ class ResourceManager { // delete downloaded archives to free up disk space await cacheManager.deleteArchives(internetPaths); + _loadingPath = ''; + _loadingProgress = 1.0; _done = true; _onUpdate(); } diff --git a/flutter/lib/ui/root/main_screen.dart b/flutter/lib/ui/root/main_screen.dart index 9c8a9f3ac..9d56e66ea 100644 --- a/flutter/lib/ui/root/main_screen.dart +++ b/flutter/lib/ui/root/main_screen.dart @@ -6,7 +6,6 @@ import 'package:mlperfbench/benchmark/state.dart'; import 'package:mlperfbench/ui/home/benchmark_result_screen.dart'; import 'package:mlperfbench/ui/home/benchmark_running_screen.dart'; import 'package:mlperfbench/ui/home/benchmark_start_screen.dart'; -import 'package:mlperfbench/ui/home/resource_loading_screen.dart'; import 'package:mlperfbench/ui/root/resource_error_screen.dart'; class MainScreen extends StatelessWidget { diff --git a/flutter/lib/ui/settings/resources_screen.dart b/flutter/lib/ui/settings/resources_screen.dart index d3341faae..0c8383123 100644 --- a/flutter/lib/ui/settings/resources_screen.dart +++ b/flutter/lib/ui/settings/resources_screen.dart @@ -180,7 +180,6 @@ class _ResourcesScreen extends State { ); } - // TODO: add confirm dialog Widget _clearCacheButton() { return AbsorbPointer( absorbing: downloading, diff --git a/flutter/lib/ui/settings/settings_screen.dart b/flutter/lib/ui/settings/settings_screen.dart index b834d48b8..3750cdec8 100644 --- a/flutter/lib/ui/settings/settings_screen.dart +++ b/flutter/lib/ui/settings/settings_screen.dart @@ -13,7 +13,6 @@ import 'package:mlperfbench/localizations/app_localizations.dart'; import 'package:mlperfbench/resources/config_manager.dart'; import 'package:mlperfbench/store.dart'; import 'package:mlperfbench/ui/app_styles.dart'; -import 'package:mlperfbench/ui/confirm_dialog.dart'; import 'package:mlperfbench/ui/settings/task_config_section.dart'; class SettingsScreen extends StatefulWidget { From 674377967fb75c93830b18ba58635eb1204fe536 Mon Sep 17 00:00:00 2001 From: Anh Date: Fri, 22 Nov 2024 13:32:22 +0700 Subject: [PATCH 13/16] Auto download resources when running integration test --- flutter/integration_test/utils.dart | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/flutter/integration_test/utils.dart b/flutter/integration_test/utils.dart index f53b9a5e4..d99a66000 100644 --- a/flutter/integration_test/utils.dart +++ b/flutter/integration_test/utils.dart @@ -68,6 +68,10 @@ Future runBenchmarks(WidgetTester tester) async { const downloadTimeout = 20 * 60; // 20 minutes const runBenchmarkTimeout = 30 * 60; // 30 minutes + final state = tester.state(find.byType(MaterialApp)); + final benchmarkState = state.context.read(); + await benchmarkState.loadResources(downloadMissing: true); + var goButtonIsPresented = await waitFor(tester, downloadTimeout, const Key(WidgetKeys.goButton)); From 0b2b4de7b9f935e63f4120d77bcf97ff77f6d5a0 Mon Sep 17 00:00:00 2001 From: Anh Date: Fri, 22 Nov 2024 13:45:37 +0700 Subject: [PATCH 14/16] refactor parameter name for more clarity --- flutter/lib/benchmark/state.dart | 4 ++-- flutter/lib/resources/cache_manager.dart | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/flutter/lib/benchmark/state.dart b/flutter/lib/benchmark/state.dart index 89dfa6d15..ebbd15608 100644 --- a/flutter/lib/benchmark/state.dart +++ b/flutter/lib/benchmark/state.dart @@ -138,7 +138,7 @@ class BenchmarkState extends ChangeNotifier { _store.previousAppVersion = newAppVersion; await Wakelock.enable(); - print('start loading resources'); + print('Start loading resources with downloadMissing=$downloadMissing'); final resources = _benchmarkStore.listResources( modes: [taskRunner.perfMode, taskRunner.accuracyMode], benchmarks: benchmarks, @@ -148,7 +148,7 @@ class BenchmarkState extends ChangeNotifier { needToPurgeCache, downloadMissing, ); - print('finished loading resources'); + print('Finished loading resources with downloadMissing=$downloadMissing'); error = null; stackTrace = null; taskConfigFailedToLoad = false; diff --git a/flutter/lib/resources/cache_manager.dart b/flutter/lib/resources/cache_manager.dart index 48d93ab4c..13602b267 100644 --- a/flutter/lib/resources/cache_manager.dart +++ b/flutter/lib/resources/cache_manager.dart @@ -28,7 +28,7 @@ class CacheManager { return archiveFilePath; } - Future deleteLoadedResources(List nonRemovableResources, + Future deleteLoadedResources(List excludes, [int atLeastDaysOld = 0]) async { final directory = Directory(loadedResourcesDir); @@ -40,8 +40,8 @@ class CacheManager { final relativePath = file.path .replaceAll('\\', '/') .substring(loadedResourcesDir.length + 1); - var nonRemovable = false; - for (var resource in nonRemovableResources) { + var keep = false; + for (var resource in excludes) { // relativePath.startsWith(resource): if we want to preserve a folder resource // resource.startsWith(relativePath): if we want to preserve a file resource // for example: @@ -49,11 +49,11 @@ class CacheManager { // resource is 'github.com/mlcommons/mobile_models/raw/main/v0_7/datasets/ade20k' if (relativePath.startsWith(resource) || resource.startsWith(relativePath)) { - nonRemovable = true; + keep = true; break; } } - if (nonRemovable) continue; + if (keep) continue; if (atLeastDaysOld > 0) { var stat = await file.stat(); if (DateTime.now().difference(stat.modified).inDays < atLeastDaysOld) { From 2cf8c671441691200666f5c430f98197528c340d Mon Sep 17 00:00:00 2001 From: Anh Date: Fri, 22 Nov 2024 13:52:16 +0700 Subject: [PATCH 15/16] refactor var name for more clarity --- flutter/android/android.mk | 2 +- flutter/flutter.mk | 2 +- flutter/integration_test/first_test.dart | 9 ++------- flutter/lib/app_constants.dart | 3 +++ 4 files changed, 7 insertions(+), 9 deletions(-) diff --git a/flutter/android/android.mk b/flutter/android/android.mk index effa10ab0..4347167bd 100644 --- a/flutter/android/android.mk +++ b/flutter/android/android.mk @@ -90,7 +90,7 @@ flutter_android_apk_test_main_path=${FLUTTER_ANDROID_APK_FOLDER}/${FLUTTER_ANDRO .PHONY: flutter/android/test-apk/main flutter/android/test-apk/main: mkdir -p $$(dirname ${flutter_android_apk_test_main_path}) - flutter_android_apk_test_perf_arg=$$(printf enable-perf-test=${PERF_TEST} | base64) && \ + flutter_android_apk_test_perf_arg=$$(printf PERF_TEST=${PERF_TEST} | base64) && \ cd flutter/android && \ ./gradlew app:assembleDebug \ -Ptarget=integration_test/first_test.dart \ diff --git a/flutter/flutter.mk b/flutter/flutter.mk index 414f6fbbe..fbc0db36c 100644 --- a/flutter/flutter.mk +++ b/flutter/flutter.mk @@ -159,7 +159,7 @@ flutter_test_device_arg=--device-id "${FLUTTER_TEST_DEVICE}" else flutter_test_device_arg= endif -flutter_perf_test_arg=--dart-define=enable-perf-test=${PERF_TEST} +flutter_perf_test_arg=--dart-define=PERF_TEST=${PERF_TEST} .PHONY: flutter/test/integration flutter/test/integration: cd flutter && ${_start_args} \ diff --git a/flutter/integration_test/first_test.dart b/flutter/integration_test/first_test.dart index 77c9ac3b0..e8ce57f3c 100644 --- a/flutter/integration_test/first_test.dart +++ b/flutter/integration_test/first_test.dart @@ -14,11 +14,6 @@ import 'expected_accuracy.dart'; import 'expected_throughput.dart'; import 'utils.dart'; -const enablePerfTest = bool.fromEnvironment( - 'enable-perf-test', - defaultValue: false, -); - void main() { final binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized(); binding.framePolicy = LiveTestWidgetsFlutterBindingFramePolicy.fullyLive; @@ -30,7 +25,7 @@ void main() { StoreConstants.testMinDuration: 1, StoreConstants.testMinQueryCount: 4, }; - if (enablePerfTest) { + if (DartDefine.perfTestEnabled) { prefs[StoreConstants.testMinDuration] = 15; prefs[StoreConstants.testMinQueryCount] = 64; prefs[StoreConstants.testCooldownDuration] = 2; @@ -72,7 +67,7 @@ void checkTasks(ExtendedResult extendedResult) { expect(benchmarkResult.performanceRun!.throughput, isNotNull); checkAccuracy(benchmarkResult); - if (enablePerfTest) { + if (DartDefine.perfTestEnabled) { checkThroughput(benchmarkResult, extendedResult.environmentInfo); } } diff --git a/flutter/lib/app_constants.dart b/flutter/lib/app_constants.dart index 5e4611750..91bb07abe 100644 --- a/flutter/lib/app_constants.dart +++ b/flutter/lib/app_constants.dart @@ -7,6 +7,9 @@ class DartDefine { bool.fromEnvironment('FIREBASE_CRASHLYTICS_ENABLED', defaultValue: false); static const isFastMode = bool.fromEnvironment('FAST_MODE', defaultValue: false); + + static const perfTestEnabled = + bool.fromEnvironment('PERF_TEST', defaultValue: false); } class WidgetKeys { From 1cddf49da7666567d3e5ca7b8a437802bb9a56df Mon Sep 17 00:00:00 2001 From: Anh Date: Mon, 25 Nov 2024 08:52:15 +0700 Subject: [PATCH 16/16] Change icon for download status --- flutter/lib/ui/settings/resources_screen.dart | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/flutter/lib/ui/settings/resources_screen.dart b/flutter/lib/ui/settings/resources_screen.dart index 0c8383123..58417d5f9 100644 --- a/flutter/lib/ui/settings/resources_screen.dart +++ b/flutter/lib/ui/settings/resources_screen.dart @@ -91,9 +91,9 @@ class _ResourcesScreen extends State { if (snapshot.hasData && snapshot.data != null) { const double size = 18; const downloadedIcon = - Icon(Icons.check_circle, size: size, color: Colors.green); + Icon(Icons.download_done, size: size, color: Colors.green); const notDownloadedIcon = - Icon(Icons.check_circle_outline, size: size, color: Colors.grey); + Icon(Icons.download_done, size: size, color: Colors.grey); final result = snapshot.data!; final missing = result[false] ?? []; final existed = result[true] ?? []; @@ -260,16 +260,13 @@ class _ResourcesTable extends StatelessWidget { } TableRow _row(String path, bool existed) { + const downloadedIcon = Icon(Icons.download_done, color: Colors.green); + const notDownloadedIcon = Icon(Icons.download_done, color: Colors.grey); return TableRow( children: [ Padding( padding: const EdgeInsets.all(8.0), - child: Icon( - existed ? Icons.check_circle : Icons.check_circle_outline, - color: existed - ? Colors.green - : Colors.grey, // Grey check mark for missing - ), + child: existed ? downloadedIcon : notDownloadedIcon, ), Padding( padding: const EdgeInsets.all(8.0),