perf(#306): measure the per-contact conversation load

The startup loads are now clean (all steps ~0ms, down from 37792ms), but the
contact pull still stalls in multi-second bursts: 8.0s and 7.7s at +25s..+52s
on the last run, matching the reported freeze from ~15s to ~49s.

No frame handler exceeds 100ms, because the work is not in one.
_loadMessagesForContact is fired unawaited from the contact handler, so it runs
after the handler returns and escapes that timing entirely.

This times it directly and reports cumulative store time versus merge+notify
time every 25 contacts, so the next run says which half is responsible rather
than requiring another guess. Two candidates it will discriminate:
  - store: prefs read + jsonDecode per contact
  - merge+notify: the per-contact notifyListeners, i.e. one full widget tree
    rebuild per contact, each of which walks the contact list

Diagnostics only, no behaviour change.

flutter analyze clean, dart format clean.
integration/290-306-335
Strycher 1 day ago
parent 5eded9e33c
commit a7ef7b3325

@ -703,11 +703,30 @@ class MeshCoreConnector extends ChangeNotifier {
notifyListeners();
}
/// Aggregate cost of the per-contact conversation load, which runs once per
/// contact during a pull. It is fired unawaited from the contact handler, so
/// it escapes the frame-handler timing and has to be measured here.
int _convLoadCount = 0;
int _convLoadStoreMs = 0;
int _convLoadMergeMs = 0;
Future<void> _loadMessagesForContact(String contactKeyHex) async {
if (_loadedConversationKeys.contains(contactKeyHex)) return;
_loadedConversationKeys.add(contactKeyHex);
final storeWatch = Stopwatch()..start();
final allMessages = await _messageStore.loadMessages(contactKeyHex);
storeWatch.stop();
final mergeWatch = Stopwatch()..start();
_convLoadCount++;
_convLoadStoreMs += storeWatch.elapsedMilliseconds;
if (_convLoadCount % 25 == 0) {
appLogger.info(
'conversation loads: $_convLoadCount contacts, '
'store=${_convLoadStoreMs}ms merge=${_convLoadMergeMs}ms cumulative',
tag: 'Perf',
);
}
if (allMessages.isNotEmpty) {
// Keep only the most recent N messages in memory to bound memory usage
final windowedMessages = allMessages.length > _messageWindowSize
@ -748,6 +767,8 @@ class MeshCoreConnector extends ChangeNotifier {
_conversations[contactKeyHex] = windowedMergedMessages;
notifyListeners();
}
mergeWatch.stop();
_convLoadMergeMs += mergeWatch.elapsedMilliseconds;
}
String _messageMergeKey(Message message) {

Loading…
Cancel
Save

Powered by TurnKey Linux.