[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Understanding filter function calls

From: Karthik Chikmagalur
Subject: Re: Understanding filter function calls
Date: Sat, 29 Jul 2023 15:16:49 -0700

>> Setting it to nil essentially fixes the problem!  The filter function is
>> now called 80+ times instead of 35 times, the string it's called with
>> each time is of variable length, generally under 500 characters, but
>> overall the process is much, much faster.
>> Total preview time:
>> | process-adaptive-read-buffering | t         | nil       |
>> |---------------------------------+-----------+-----------|
>> | TeXLive 2022                    | 2.65 secs | 1.88 secs |
>> | TeXLive 2023                    | 4.03 secs | 1.80 secs |
>> We get a huge speed-up, up to 120%.
> Then I guess you need to bind process-adaptive-read-buffering to nil
> when you perform this processing.  (But please also see what happens
> if process-connection-type is set to nil, thus using pipes instead of
> PTY to read subprocess output: it could change the picture.)

I've tested out all combinations of pty/pipe and adaptive-read/no
adaptive read now, here is a full picture of what the filter calls look
like: https://i.imgur.com/MkszXbT.png

(mirror for future reference if the above link is dead:

Each block is a call to the filter function.  
- The horizontal position is when in the timeline it is called.
- The height of each block is the amount of data it is called with.
- The width of each block is how long the filter takes to run.

The abnormally wide blocks might involve garbage collection, I don't
know how to account for that.  The largest time gaps between filter
function calls are also probably because of GC, because I turned off as
many timers as I could and there was no user input during the tests.

Here's what I've discerned from this picture:

1. A pty connection + adaptive-read is the slowest (by a fair bit).  All
other combinations are equally fast.

2. Despite the value of read-process-output-max, a pty connection calls
the filter function with at most 4 KB of data most of the time.

3. With a pipe connection, we indeed see reads of up to
read-process-output-max (64 KB in my tests).

4. Which combination is best depends on what we value more: Emacs'
degree of responsiveness during the generation or the overall preview
generation time.
   - pty + adaptive read is the slowest but Emacs remains fully
   - A pipe connection + adaptive-read is fast but the least responsive
     because of the large reads + associated processing.
   - Setting process-adaptive-read-buffering to nil is a reasonable
     balance of speed and responsiveness.

>> My only goal here is to provide the most responsive user experience
>> possible when writing LaTeX math in Org mode, under the constraint
>> that this needs to be done by gluing together two (actually three)
>> processes.  I care about where the bottleneck is -- or was -- only
>> so that I may address it.
> I understand, but clearly the change responsible for this was in
> dvisvgm, not in Emacs, so expecting Emacs to rectify it is not really
> fair.

On reflection what I said isn't correct -- this was not my only goal.  I
also wanted to understand some of the intricacies of subprocess
communication in Emacs, which your comments have helped me with.  My
prior knowledge of it was all theoretical and limited to reading the
Elisp manual sections on the Command Loop and "Receiving Output From

>> The filter function needs to read the output file name for the purposes
>> of updating LaTeX previews in the buffer.  The rest is superfluous to us
>> -- but it's possible that the sizing information is useful to other
>> applications.
> Then maybe ask the dvisvgm developers to provide the level of
> verbosity that only shows the file name.  Emacs in general and Org in
> particular are important applications, and so it would be reasonable
> for the dvisvgm developers to cater to our needs, not only to the
> needs of other programs.

Yes, this is on the docket for me.

> I very much doubt that 0.2 sec makes a difference when the overall
> time is about 4 sec.

The difference in preview generation time was about 1.4 seconds (2.6 ->
4.0), so I'm not sure why you mentioned 0.4.

>> Because of `process-adaptive-read-buffering', I'm not sure this is all
>> there is to it, because I wouldn't expect a difference in how long the
>> preview generation run takes otherwise.  Am I correct?  The
>> documentation for this variable states:
>> "If non-nil, improve receive buffering by delaying after short reads."
> I didn't assume dvisvgm will start by sending very small chunks of
> text, so I didn't think the delays introduced by
> process-adaptive-read-buffering would matter in your case.

Indeed, dvisvgm's behavior misled me.  We can see the small initial
chunks as the early tiny spikes in the charts at the above link.

> In any case, Emacs _checks_ for subprocess output as frequently as
> possible, it just sometimes refrains from reading it (and thus
> refrains from calling the filter), if the adaptive-reading feature
> requires that.

This is good to know for the future.

>> 1. So why is the run faster with `process-adaptive-read-buffering' set
>> to nil?  I understand that this reduces read latency, but not why the
>> process is so much faster overall.
> Because we don't delay reading subprocess output, but instead process
> it as it comes in, regardless of the size.

This makes sense, thank you for clarifying.

>> But I was able to use Emacs normally (typing, calling M-x etc) when the
>> previews were being updated, which is great.  So I'm not sure what the
>> performance implications are here.
> You don't want to rewind the long history of this and re-live all the
> issues we experienced and investigated before we settled on the
> current default.  If you can solve this particular problem by binding
> the variable to nil around the code which invokes dvisvgm, that is all
> I suggest doing.

I agree that it's not important, I was just curious since I didn't
notice any immediate issues.  I'll search the archives for prior
dicussions about this when I have more time.  For now I'm just going to
remember to check process-adaptive-read-buffering when I care about


reply via email to

[Prev in Thread] Current Thread [Next in Thread]