Conduwuit servers send membership events for all members in a room, causing slow initial rendering of room buffers
OS/platform
Linux 6.10.6-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.10.6-1 (2024-08-19) x86_64 GNU/Linux
Emacs version and provenance
GNU Emacs 29.4 (build 1, x86_64-pc-linux-gnu, GTK+ Version 3.24.42, cairo version 1.18.0) of 2024-06-30, modified by Debian
Installed: "apt install emacs"
Emacs command
emacsclient -c
Emacs frame type
GUI
Ement package version and provenance
Version: 0.16pre from GitHub repository, on 0.15.1 (gnu) also
Actions taken
After succesfull login I select Emacs room on *Ement Room List*, pressing <RET>.
Observed results
CPU utilisation increases to 25% and emacs temporary stops responding. After a delay of 26 seconds, emacs regains control and displays the buffer. However, the content of the room buffer is incorrect, it lists all room members and their joining history. At the end of the buffer can the current conversation be found.
Expected results
Expected unmeasurable delay in displaying the room and correct buffer content as for other clients.
Backtrace
Error is not signaled.
Etc.
- The effect does not occur on 2 other clients, I checked Element Desktop and Fractal
- The effect occurs for remote rooms on the Conduwuit homeserver
- The effect does not occur on matrix.org homeserver (Synapse)
- The effect occurs when the room buffer is opened
- The length of the delay is proportional to the count of room members
- Latency has definitely decreased after updating Ement from v. 0.15.1 to v. 0.16pre
- The Emacs room is only used as an example to demonstrate the problem because it has many members
It would seem that the Conduwuit server is sending the client membership events for every member in the room instead of only those relevant to the events that have been sent to the client. That would seem to be a problem with the server, and I'd guess that it's a known one.
The reason that Ement.el seems slow there is that adjacent membership events are coalesced into groups, and as each one is rendered, the whole coalesced group is re-rendered; so as more membership events are coalesced into a group, the time required to render the group increases. Due to the underlying EWOC library used to render these events into buffers, rendering of the event groups can't be deferred until all of the events have been coalesced (to do so would require much work on EWOC, or much work on Ement to work around EWOC's design).
Hence the addition of the option to limit the size of coalesced groups in Ement. If it's still too slow for you on that server, you could set the limit very low, or even to 1. That would then mean that all of the membership events would be rendered individually, which would still be quite wasteful in large rooms.
We could also add various possible workarounds in Ement, but I'd prefer not to, as they'd all be hacky and special-casing for what seems to be a problem with a certain server implementation, one which will probably be fixed in the future. As well, the eventual implementation of Sliding Sync support might make such workarounds useless.
Having said that, if you wanted to disable rendering of member events entirely, you could put this in your config:
(ement-room-defevent "m.room.member" nil)
Or if you wanted to get fancy, you could use advice to the room-buffer-opening function that makes that event handler nil while the room is being first rendered, so subsequently received membership events would still be rendered.
Thanks. Seems to be accurate because after the configuration changes the remote rooms opens much more efficiently.
use advice to the room-buffer-opening function
Do you mean ement-room-view?
Maybe ement-room-view-hook would be a better place?
Do you mean
ement-room-view? Maybeement-room-view-hookwould be a better place?
I can't offer any more detailed advice than that. If you want to explore that kind of solution, you'll have to dig into the source code.