Bug: Improve performance of listing and querying messages
Status: RESOLVED
Priority: --
Resolution: MOVED
Created: 2023-09-18 09:04:10+00:00
Resolved: 2023-10-26 18:46:35+00:00

Following a discussion on the mailing list, I took a performance profile, and then noticed some issues.

STR

1. Have at least one add-on installed, and use "Debug Add-ons" to inspect it.
2. Get a folder object for a folder with a large amount of messages (mine has ~73500 messages). e.g. In the opened console:

```
// Find an account where there is a folder with large amount of messages
await browser.accounts.list()
// Find the folders in that account
await browser.accounts.get("account1", true)
// Get the folder details
folder = (await browser.accounts.get("account1", true)).folders[2]
```
3. Open up the normal developer toolkit, and start the profiler recording.
4. Enter this in the console

```
start = Date.now(); msgs = await browser.messages.list(folder); console.log("took", Date.now() - start)
```

On my machine I'm seeing around 5 seconds to list ~73500 messages which gives [this profile](https://share.firefox.dev/48gyANJ).

Looking through the profile, I noticed some areas for improvements (this might want to be a meta bug):

* The `list` and `query` functions (and a few others) use [the `startList` function](https://searchfox.org/comm-central/rev/5d1046f87660df06657108f44684865a359fd60f/mail/components/extensions/parent/ext-mail.js#2675-2691) which creates a paged list of messages to be returned in batched calls.
  * The way `startList` does this is to iterate through the entire supplied message list, and converting each message to an extension object and then inserting into pages.
  * Converting a single message can take up to 50ms on my machine, and it is all synchronous.
  * Proposal: Only enumerate and convert the messages required for the current page. This would avoid doing everything at once, and use the message passing between extension & main processes to provide a natural break to split up the yank. This also allows the extension to decide it is not interested in the rest of the list, and hence avoid unnecessary work.
  * Additional proposal: Use `MessageManager.convert` rather than `convertMessage` directly. This way any already obtained messages should be able to be loaded from the cache.
* `convertFolder` gets [`folder.flags` multiple times in a loop](https://searchfox.org/comm-central/rev/5d1046f87660df06657108f44684865a359fd60f/mail/components/extensions/parent/ext-mail.js#2142). I'm pretty sure that because it is an XPCOM function, it will be called every time around the loop, rather than being optimised out. Therefore, getting the flags before going around the loop should be quicker (though a small improvement overall).
  * Additionally, consider exiting the loop as soon as a type is matched, unless there's some expected prioritisation of types (I don't think so).
* [`convertFolder` is called many times](https://searchfox.org/comm-central/rev/5d1046f87660df06657108f44684865a359fd60f/mail/components/extensions/parent/ext-mail.js#2267-2272) which may be for the same folder especially for `messages.list()`. Overall it takes about 10% of the time for `convertMessage` to run.
  * Consider some form of caching or other improvement to avoid having to keep crossing the xpcom boundaries, and keep converting URIs.
* `getId` also takes up about 10% of the time.
  * Avoid crossing the [xpcom boundary twice when checking for the folder and getting the URI](https://searchfox.org/comm-central/rev/5d1046f87660df06657108f44684865a359fd60f/mail/components/extensions/parent/ext-mail.js#2393,2395).
  * Consider not using [`JSON.stringify` for the hash](https://searchfox.org/comm-central/rev/5d1046f87660df06657108f44684865a359fd60f/mail/components/extensions/parent/ext-mail.js#2367-2373). `JSON.stringify` is taking about 30% of the time of `getId`. Looking at the msgIdentifier values, I think a simple string addition would be sufficient and avoid the expensive call.
* [Avoid calling into `splitRecipients`](https://searchfox.org/comm-central/rev/5d1046f87660df06657108f44684865a359fd60f/mail/components/extensions/parent/ext-mail.js#2142,2250-2251) if `msgHdr.cc` and/or `msgHdr.bcc` are empty (and avoid calling the xpcom attributes twice). Crossing the xpcom boundary is expensive, and there's some work done there even if the header is empty.
* Investigate if there's any optimisations to be made in `mime2DecodedAuthor`, `mime2DecodedRecipients,` and `mime2DecodedSubject`. These are both relatively expensive functions taking a bit over 10% of the time when combined.

There may be more optimisations that will become apparent once some of the initial issues are resolved.