From 23049b69bc3d2205e3df2d1e4dbbc060e68d1fee Mon Sep 17 00:00:00 2001 From: Airyzz <36567925+Airyzz@users.noreply.github.com> Date: Tue, 25 Jun 2024 07:54:42 +0000 Subject: [PATCH] Improve Diagnostics + Measure DB Performance (#281) --- .../matrix/database/matrix_database_io.dart | 9 ++- commet/lib/client/matrix/matrix_client.dart | 9 +-- commet/lib/diagnostic/diagnostics.dart | 61 +++++++++++----- commet/lib/main.dart | 2 +- .../account_management_tab.dart | 21 ++++-- .../cumulative_diagnostics_widget.dart | 70 +++++++++++++++++++ .../developer/developer_settings_page.dart | 19 ++--- commet/pubspec.lock | 2 +- 8 files changed, 151 insertions(+), 42 deletions(-) create mode 100644 commet/lib/ui/pages/settings/categories/developer/cumulative_diagnostics_widget.dart diff --git a/commet/lib/client/matrix/database/matrix_database_io.dart b/commet/lib/client/matrix/database/matrix_database_io.dart index 0112f770..2d79f349 100644 --- a/commet/lib/client/matrix/database/matrix_database_io.dart +++ b/commet/lib/client/matrix/database/matrix_database_io.dart @@ -3,6 +3,7 @@ import 'dart:isolate'; import 'dart:ui'; import 'package:commet/config/app_config.dart'; +import 'package:commet/diagnostic/diagnostics.dart'; import 'package:drift/drift.dart'; import 'package:drift/isolate.dart'; import 'package:flutter/services.dart'; @@ -19,7 +20,13 @@ Future getMatrixDatabaseImplementation(String clientName) async { var isolate = DriftIsolate.fromConnectPort( port ?? (await _createIsolate(clientName)).connectPort); - return MatrixSdkDriftDatabase.init(await isolate.connect()); + return MatrixSdkDriftDatabase.init(await isolate.connect(), clientName, + benchmark: benchmarkFunc); +} + +Future benchmarkFunc(String name, Future Function() func, + [int? itemCount]) { + return Diagnostics.databaseDiagnostics.timeAsync(name, func); } Future _createIsolate(String clientName) async { diff --git a/commet/lib/client/matrix/matrix_client.dart b/commet/lib/client/matrix/matrix_client.dart index 0ae6f9fe..e48c7910 100644 --- a/commet/lib/client/matrix/matrix_client.dart +++ b/commet/lib/client/matrix/matrix_client.dart @@ -15,6 +15,7 @@ import 'package:commet/client/profile.dart'; import 'package:commet/client/room_preview.dart'; import 'package:commet/config/build_config.dart'; import 'package:commet/debug/log.dart'; +import 'package:commet/diagnostic/diagnostics.dart'; import 'package:commet/main.dart'; import 'package:commet/ui/navigation/adaptive_dialog.dart'; import 'package:commet/ui/pages/matrix/authentication/matrix_uia_request.dart'; @@ -142,7 +143,7 @@ class MatrixClient extends Client { static Future loadFromDB(ClientManager manager, {bool isBackgroundService = false}) async { - await diagnostics.timeAsync("loadFromDB", () async { + await Diagnostics.general.timeAsync("loadFromDB", () async { var clients = preferences.getRegisteredMatrixClients(); List futures = List.empty(growable: true); @@ -153,8 +154,8 @@ class MatrixClient extends Client { for (var clientName in clients) { var client = MatrixClient(identifier: clientName); manager.addClient(client); - futures.add(diagnostics.timeAsync("Initializing client $clientName", - () async { + futures.add(Diagnostics.general + .timeAsync("Initializing client $clientName", () async { try { await client.init(true, isBackgroundService: isBackgroundService); } catch (error, trace) { @@ -196,7 +197,7 @@ class MatrixClient extends Client { Future init(bool loadingFromCache, {bool isBackgroundService = false}) async { if (!_matrixClient.isLogged()) { - await diagnostics.timeAsync("Matrix client init", () async { + await Diagnostics.general.timeAsync("Matrix client init", () async { await _matrixClient.init( waitForFirstSync: !loadingFromCache, waitUntilLoadCompletedLoaded: true, diff --git a/commet/lib/diagnostic/diagnostics.dart b/commet/lib/diagnostic/diagnostics.dart index de1fd08d..e4077d60 100644 --- a/commet/lib/diagnostic/diagnostics.dart +++ b/commet/lib/diagnostic/diagnostics.dart @@ -1,29 +1,24 @@ -import 'package:commet/debug/log.dart'; import 'package:commet/main.dart'; -class TimerResult { - final String name; - final Duration time; - - const TimerResult(this.name, this.time); +class CumulativeMeasurement { + int numCalls = 0; + Duration totalDuration = Duration.zero; + String name = ""; } -class Diagnostics { - List results = List.empty(growable: true); - - void addResult(String name, Duration time) { - results.add(TimerResult(name, time)); +class CumulativeDiagnostics { + CumulativeDiagnostics(this.name); - Log.i("Diagnostics: $name took ${time.inMilliseconds}ms"); - } + String name; + Map measurements = {}; - Future timeAsync(String name, Future Function() func) async { + T time(String name, T Function() func) { if (!preferences.developerMode) return func(); - Stopwatch s = Stopwatch(); + s.start(); - var result = await func(); + var result = func(); s.stop(); @@ -31,17 +26,45 @@ class Diagnostics { return result; } - T time(String name, T Function() func) { + Future timeAsync(String name, Future Function() func) async { if (!preferences.developerMode) return func(); - Stopwatch s = Stopwatch(); + Stopwatch s = Stopwatch(); s.start(); - var result = func(); + var result = await func(); s.stop(); addResult(name, s.elapsed); return result; } + + void addResult(String name, Duration elapsed) { + var m = measurements[name] ?? CumulativeMeasurement(); + m.numCalls += 1; + m.totalDuration += elapsed; + m.name = name; + measurements[name] = m; + } +} + +class Diagnostics { + static bool _isPostInit = false; + + static void setPostInit() { + _isPostInit = true; + } + + static CumulativeDiagnostics initialLoadDatabaseDiagnostics = + CumulativeDiagnostics("Initial Load Database Diagnostics"); + + static CumulativeDiagnostics postLoadDatabaseDiagnostics = + CumulativeDiagnostics("Post Load Database Diagnostics"); + + static CumulativeDiagnostics general = CumulativeDiagnostics("General"); + + static CumulativeDiagnostics get databaseDiagnostics => _isPostInit + ? postLoadDatabaseDiagnostics + : initialLoadDatabaseDiagnostics; } diff --git a/commet/lib/main.dart b/commet/lib/main.dart index 6a23cd2a..b4676c25 100644 --- a/commet/lib/main.dart +++ b/commet/lib/main.dart @@ -43,7 +43,6 @@ FileCache? fileCache; Preferences preferences = Preferences(); ShortcutsManager shortcutsManager = ShortcutsManager(); BackgroundTaskManager backgroundTaskManager = BackgroundTaskManager(); -Diagnostics diagnostics = Diagnostics(); ClientManager? clientManager; bool isHeadless = false; @@ -153,6 +152,7 @@ Future initNecessary() async { ]); clientManager = await ClientManager.init(); + Diagnostics.setPostInit(); shortcutsManager.init(); NotificationManager.init(); diff --git a/commet/lib/ui/pages/settings/categories/account/account_management/account_management_tab.dart b/commet/lib/ui/pages/settings/categories/account/account_management/account_management_tab.dart index a3de25f8..91089952 100644 --- a/commet/lib/ui/pages/settings/categories/account/account_management/account_management_tab.dart +++ b/commet/lib/ui/pages/settings/categories/account/account_management/account_management_tab.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'package:commet/client/client_manager.dart'; import 'package:commet/client/stale_info.dart'; +import 'package:commet/main.dart'; import 'package:commet/ui/molecules/user_panel.dart'; import 'package:commet/ui/pages/login/login_page.dart'; import 'package:flutter/material.dart'; @@ -121,6 +122,7 @@ class _AccountManagementSettingsTabState displayName: clients[index].self!.displayName, avatar: clients[index].self!.avatar, detail: clients[index].self!.identifier, + internalId: clients[index].identifier, onLogoutClicked: () => clientmanager.logoutClient(clients[index])), ); @@ -132,16 +134,27 @@ class _AccountManagementSettingsTabState {required String displayName, ImageProvider? avatar, String? detail, + String? internalId, Function? onLogoutClicked}) { + String detailString = detail ?? ""; + + if (preferences.developerMode && internalId != null) { + detailString = "$detail - ($internalId)"; + } + return Padding( padding: const EdgeInsets.fromLTRB(8.0, 4, 12, 4), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - UserPanelView( - displayName: displayName, - avatar: avatar, - detail: detail, + Column( + children: [ + UserPanelView( + displayName: displayName, + avatar: avatar, + detail: detailString, + ), + ], ), tiamat.Button.danger( text: promptLogoutSingleAccount, diff --git a/commet/lib/ui/pages/settings/categories/developer/cumulative_diagnostics_widget.dart b/commet/lib/ui/pages/settings/categories/developer/cumulative_diagnostics_widget.dart new file mode 100644 index 00000000..8581f049 --- /dev/null +++ b/commet/lib/ui/pages/settings/categories/developer/cumulative_diagnostics_widget.dart @@ -0,0 +1,70 @@ +import 'package:commet/diagnostic/diagnostics.dart'; +import 'package:flutter/material.dart'; + +import 'package:tiamat/tiamat.dart' as tiamat; + +class CumulativeDiagnosticsWidget extends StatefulWidget { + const CumulativeDiagnosticsWidget({required this.diagnostics, super.key}); + + final CumulativeDiagnostics diagnostics; + + @override + State createState() => + _CumulativeDiagnosticsWidgetState(); +} + +class _CumulativeDiagnosticsWidgetState + extends State { + late List measurements; + + @override + void initState() { + measurements = widget.diagnostics.measurements.values.toList(); + measurements.sort( + (a, b) => b.totalDuration.compareTo(a.totalDuration), + ); + + super.initState(); + } + + @override + Widget build(BuildContext context) { + return ExpansionTile( + title: tiamat.Text.labelEmphasised(widget.diagnostics.name), + initiallyExpanded: false, + backgroundColor: Theme.of(context).colorScheme.surfaceContainerLow, + collapsedBackgroundColor: + Theme.of(context).colorScheme.surfaceContainerLow, + children: measurements + .mapIndexed((e, i) => Container( + color: i % 2 == 0 + ? Theme.of(context).colorScheme.surfaceDim + : Theme.of(context).colorScheme.surfaceContainerHigh, + child: Padding( + padding: const EdgeInsets.fromLTRB(20, 2, 20, 2), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Flexible( + child: Padding( + padding: const EdgeInsets.fromLTRB(0, 2, 8, 2), + child: tiamat.Text.labelLow( + e.name, + color: Theme.of(context).colorScheme.onSurface, + ), + )), + tiamat.Text.labelLow( + [ + "${e.numCalls} calls", + "${(e.totalDuration.inMilliseconds / e.numCalls).round()}ms avg", + "${e.totalDuration.inMilliseconds}ms total", + ].join(" - "), + color: Theme.of(context).colorScheme.onSurfaceVariant, + ) + ], + ), + ), + )) + .toList()); + } +} diff --git a/commet/lib/ui/pages/settings/categories/developer/developer_settings_page.dart b/commet/lib/ui/pages/settings/categories/developer/developer_settings_page.dart index c61dbfdc..3d2a793f 100644 --- a/commet/lib/ui/pages/settings/categories/developer/developer_settings_page.dart +++ b/commet/lib/ui/pages/settings/categories/developer/developer_settings_page.dart @@ -2,9 +2,11 @@ import 'dart:io'; import 'package:commet/client/components/push_notification/notification_content.dart'; import 'package:commet/client/components/push_notification/notification_manager.dart'; import 'package:commet/config/app_config.dart'; +import 'package:commet/diagnostic/diagnostics.dart'; import 'package:commet/main.dart'; import 'package:commet/ui/navigation/navigation_utils.dart'; import 'package:commet/ui/pages/developer/benchmarks/timeline_viewer_benchmark.dart'; +import 'package:commet/ui/pages/settings/categories/developer/cumulative_diagnostics_widget.dart'; import 'package:commet/utils/background_tasks/background_task_manager.dart'; import 'package:commet/utils/background_tasks/mock_tasks.dart'; import 'package:file_picker/file_picker.dart'; @@ -50,18 +52,11 @@ class _DeveloperSettingsPageState extends State { backgroundColor: Theme.of(context).colorScheme.surfaceContainerLow, collapsedBackgroundColor: Theme.of(context).colorScheme.surfaceContainerLow, - children: diagnostics.results - .map((e) => Padding( - padding: const EdgeInsets.all(8.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Flexible(child: tiamat.Text.labelEmphasised(e.name)), - tiamat.Text.label("${e.time.inMilliseconds}ms") - ], - ), - )) - .toList()); + children: [ + Diagnostics.general, + Diagnostics.initialLoadDatabaseDiagnostics, + Diagnostics.postLoadDatabaseDiagnostics, + ].map((e) => CumulativeDiagnosticsWidget(diagnostics: e)).toList()); } Widget rendering() { diff --git a/commet/pubspec.lock b/commet/pubspec.lock index 8d6e39ff..3f75f7d8 100644 --- a/commet/pubspec.lock +++ b/commet/pubspec.lock @@ -912,7 +912,7 @@ packages: description: path: "." ref: HEAD - resolved-ref: "6de337a57d191780be02079ba476024acdff0052" + resolved-ref: "8b60e925966b6e0ca29baa3ebc9c560ce9f828b1" url: "https://github.com/commetchat/matrix-dart-sdk-drift-db.git" source: git version: "0.0.1"