Various performance tweaks (#474)

* Store and reuse room list placeholder avatars and last messages

* Cache and reuse HomeScreenRooms

* Reduce RoomSummaryProvider diff collection time

* Promote more logs to info

* Slighty tweak RustTracing to make it easier to configure

* Move TimelineProvider and RoomTimelineController item processing to background queues

* Prevent the timeline from stopping an ogoing decelerating scroll when starting backpaginating
This commit is contained in:
Stefan Ceriu
2023-01-20 16:40:23 +02:00
committed by GitHub
parent 70920550e7
commit ae8009d040
15 changed files with 167 additions and 95 deletions
@@ -29,6 +29,7 @@ private class RoomTimelineListener: TimelineListener {
class RoomTimelineProvider: RoomTimelineProviderProtocol {
private let roomProxy: RoomProxyProtocol
private var cancellables = Set<AnyCancellable>()
private let serialDispatchQueue: DispatchQueue
let itemsPublisher = CurrentValueSubject<[TimelineItemProxy], Never>([])
@@ -40,6 +41,7 @@ class RoomTimelineProvider: RoomTimelineProviderProtocol {
init(roomProxy: RoomProxyProtocol) {
self.roomProxy = roomProxy
serialDispatchQueue = DispatchQueue(label: "io.element.elementx.roomtimelineprovider")
itemProxies = []
Task {
@@ -47,8 +49,8 @@ class RoomTimelineProvider: RoomTimelineProviderProtocol {
roomTimelineListener
.itemsUpdatePublisher
.receive(on: DispatchQueue.main)
.sink { [weak self] in self?.updateItemsWithDiff($0) }
.collect(.byTime(serialDispatchQueue, 0.025))
.sink { [weak self] in self?.updateItemsWithDiffs($0) }
.store(in: &cancellables)
switch await roomProxy.addTimelineListener(listener: roomTimelineListener) {
@@ -63,22 +65,25 @@ class RoomTimelineProvider: RoomTimelineProviderProtocol {
// MARK: - Private
private func updateItemsWithDiff(_ diff: TimelineDiff) {
private func updateItemsWithDiffs(_ diffs: [TimelineDiff]) {
MXLog.verbose("Received timeline diff")
guard let collectionDiff = buildDiff(from: diff, on: itemProxies) else {
MXLog.error("Failed building CollectionDifference from \(diff)")
return
}
guard let updatedItems = itemProxies.applying(collectionDiff) else {
MXLog.error("Failed applying diff: \(collectionDiff)")
return
}
MXLog.verbose("Applied diff \(collectionDiff), new count: \(updatedItems.count)")
itemProxies = updatedItems
itemProxies = diffs
.reduce(itemProxies) { currentItems, diff in
guard let collectionDiff = buildDiff(from: diff, on: currentItems) else {
MXLog.error("Failed building CollectionDifference from \(diff)")
return currentItems
}
guard let updatedItems = currentItems.applying(collectionDiff) else {
MXLog.error("Failed applying diff: \(collectionDiff)")
return currentItems
}
MXLog.verbose("Applied diff \(collectionDiff), new count: \(updatedItems.count)")
return updatedItems
}
MXLog.verbose("Finished applying diff")
}
@@ -21,10 +21,11 @@ import UniformTypeIdentifiers
class RoomTimelineController: RoomTimelineControllerProtocol {
private let userId: String
private let roomProxy: RoomProxyProtocol
private let timelineProvider: RoomTimelineProviderProtocol
private let timelineItemFactory: RoomTimelineItemFactoryProtocol
private let mediaProvider: MediaProviderProtocol
let roomProxy: RoomProxyProtocol
private let serialDispatchQueue: DispatchQueue
private var cancellables = Set<AnyCancellable>()
private var timelineItemsUpdateTask: Task<Void, Never>? {
@@ -51,10 +52,11 @@ class RoomTimelineController: RoomTimelineControllerProtocol {
self.timelineItemFactory = timelineItemFactory
self.mediaProvider = mediaProvider
self.roomProxy = roomProxy
serialDispatchQueue = DispatchQueue(label: "io.element.elementx.roomtimelineprovider")
self.timelineProvider
.itemsPublisher
.receive(on: DispatchQueue.main)
.receive(on: serialDispatchQueue)
.sink { [weak self] _ in
guard let self else { return }
@@ -236,14 +238,8 @@ class RoomTimelineController: RoomTimelineControllerProtocol {
updateTimelineItems()
}
private func updateTimelineItems() {
timelineItemsUpdateTask = Task {
await asyncUpdateTimelineItems()
}
}
// swiftlint:disable:next cyclomatic_complexity
private func asyncUpdateTimelineItems() async {
private func updateTimelineItems() {
var newTimelineItems = [RoomTimelineItemProtocol]()
var canBackPaginate = true
var isBackPaginating = false