Open memeplex opened 2 months ago
I've been investigating this. I'm quite sure the problem is in Polylux, specifically in #let polylux-slide(max-repetitions: 10, body)
in logic.typ
. Just change the number of iterations first to 1 and then to 100 and you will see the opposite reactions in terms of memory usage. Perhaps it's memoizing a lot of stuff because of the frequent state updates (and maybe you need some cache eviction policy or something like that). And this while I'm not using any dynamic feature at all! Also, from a cursory look, logical-slide.step()
seems to be ever increasing.
It may be that when adding/removing one slide, specially one near the top, the logical-slide count increases/decreases for all the following ones (since there is one more/less state update above them), so a large part of the document gets invalidated, and each one of the slides there has to do the ten iterations dance again. An effect like this will be particularly evident when refreshing the preview on type, I guess, since the document is changing and broken half of the time, although other parts of the LSP may be as well affected. This is arguably not desirable, but if possible tinymist should deal with the situation in a more robust fashion (without scaling memory usage to quite a few GB).
Thanks for investigation. Both can do better from the result.
Alternative solution: From view of performance, touying should do much better, though I haven't use it. I only maintained some deadly-simple polylux slides so I didn't go in depth of optimizing lsp for polylux.
Ok, thanks, I'm already looking into touying or just a "hand-made" slideshow template. So, to recap, the most reliable way to reproduce this is to change max-repetitions to 100 in logic.typ, restart the extension host and boom. You don't even need to open the previewer. I guess having that multiplier there is equivalent to having a large document with page numbers in the footer, the would require almost full renumbering if you added or removed a line from a page near the beginning. One can't blame polylux on keeping the logical-slide count, although the way it then iterates over each slide certainly doesn't seem to help a memoization strategy. Even worse, a long-running, incremental one, that may be keeping lots of stale data from one moment to the next. Moreover, the fact that each slide is wrapped inside a polylux function that is wrapped inside a theme function that is wrapped inside an end-user function, may be hard on the caching strategy if it works at the function call level, but I'm just guessing.
Also be aware that in the development branch they removed the max-iterations logic and are now iterating as required for each slide https://github.com/andreasKroepelin/polylux/blob/main/logic.typ. Although according to the commit history the motivation for the change was not optimization but getting rid of an artificial limit. So please use the same polylux version than me in order to reproduce the issue, which is the current stable one.
I don't think the problem is limited to Polylux. Tinymist is currently using 8.9 GB of RAM for a relatively simple 19 slide presentation designed with Touying, and I've seen it reach ~5 GB for standard non-presentation documents as well.
This is on Tinymist v0.11.19, Neovim v0.10.1, Arch Linux, all default settings, installed using Mason/lspconfig.
Let me know if you need any extra specs/logs. I would like to profile this, but I don't have any Rust memory profiling experience or a lot of time unfortunately. Would Valgrind be the go?
It would be great to track this down to a minimal document without external dependencies. I didn't have the time yet but the example of polylux with regard to the number of iterations may be a good lead.
Another take is that we may want to know who's fault it is in this case. If it already takes a lot of RAM when using typst watch
, tinymist cannot do much to prevent this.
Still working on a reliable way to reproduce this - on my laptop which has the exact same software config as my desktop, I can't reliably get a Touying presentation to trigger the RAM usage issue. However, I was able to use another document (~17 pages) to use ~4 GB of RAM using Tinymist, whereas typst watch
uses only ~108 MB.
Using /usr/bin/time -v typst watch <document>.typ
to report max resident RAM, I get:
Command being timed: "typst watch <document>.typ"
User time (seconds): 0.86
System time (seconds): 0.22
Percent of CPU this job got: 2%
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:42.94
Average shared text size (kbytes): 0
Average unshared data size (kbytes): 0
Average stack size (kbytes): 0
Average total size (kbytes): 0
Maximum resident set size (kbytes): 108156
Average resident set size (kbytes): 0
Major (requiring I/O) page faults: 0
Minor (reclaiming a frame) page faults: 26842
Voluntary context switches: 254
Involuntary context switches: 19
Swaps: 0
File system inputs: 0
File system outputs: 3736
Socket messages sent: 0
Socket messages received: 0
Signals delivered: 0
Page size (bytes): 4096
Exit status: 0
So typst watch
uses ~108 MB of RAM, whereas Tinymist uses ~4 GB.
edit: I should also note this is with previewing disabled in the Tinymist LSP config.
yup, I'm sitting here with 10.8 GB RAM usage of tinymist, only change I did was configuring "onSave" trigger instead of "onType"..
I miss an option to configure the delay for the LSP update.. I don't want to fire an update with EACH character I type
I have checked it again and find nothing new. I performed following steps:
https://github.com/user-attachments/assets/783943a3-5e78-4982-9acb-2fbb4c165dff
The only difference between typst-cli and tinymist I can remeber soonly is this arguments, the max age of cache. This number won't be exported as setting, to prevent bad settings. But If somebody have interest, they could build tinymist from source and turns down the number for experiment. For performance concerning tinymist definitely needs higher max age, but it is arguable. Btw, tinymist was petty laggy when I followed the setting of typst-cli.
https://github.com/Myriad-Dreamin/tinymist/blob/main/crates/tinymist/src/task/cache.rs#L14
I still have building a minimal example in my TODO list, but have you tried increasing the number of repetitions of polylux as described in https://github.com/Myriad-Dreamin/tinymist/issues/513#issuecomment-2279680018? That's a reliable way of moving into the zone of a handful of GB.
but have you tried increasing the number of repetitions of polylux as described in https://github.com/Myriad-Dreamin/tinymist/issues/513#issuecomment-2279680018?
I have increased it, and this is the result.
DHAT Viewer - dhat-heap.json - Total (blocks).zip
std::Vec<T>
. When tinymist uses most memory, 43% of memory (1.5GB) are held by std::Vec<T>
.typst::compile
and about 6% of memory is directly allocated by tinymist_query
.For anyone who is wondering on what max-repetitions
is about:
You may want to create slides in which the content gets revealed one by one (for example). Because polylux bases on typst which produces PDF results, this cannot be animated, instead, there need to be a separated PDF page per "step", so called subslides.
The maximum amount of these subslides can be configured by max-repetitions
, the default is 10. This setting tells the compiler, how many times it should repeat the compilation for each slide.
Source: Polylux Docs: Dynamic Slides - Internals
TL;DR: max-repetitions
sets the maximum amount of so called subslides
Describe the bug
This is a continuation of https://github.com/Myriad-Dreamin/tinymist/issues/419
I'm attaching a document that, when previewing, quickly scales tinymist memory usage from 500MB up to, sometimes, 5GB.
The issue is very easy to reproduce for me: just work a bit with the document. But, anyway, I'm providing precise reproduction steps for one instance:
// #slide[Foo][Bar]
and saveThere is nothing too specific to this line, many other changes produce the same or worse effects. Also, refreshing on type accelerates the ramp up.
I've provided more information in #419 from this comment downward.
Archive.zip
Package/Software version:
VSCode version(Help -> About):
tinymist extension version:
v0.11.0
. Get it bytinymist --version
in terminal.Logs:
tinymist server log(Output Panel -> tinymist):
tinymist client log(Help -> Toggle Developer Tools -> Console):