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

Re: w3m tab line constantly consumes CPU


> In [emacs-w3m : No.12198] Michael Heerdegen wrote:
> > From time to time, I see Emacs constantly consuming CPU, ca. 10%.  Emacs
> > doesn't hang, but consumes enough CPU to let my ventilator run all the
> > time.
> > It took some time to identify that w3m was the culprit, its tab line,
> > to be more precise.  When the tab line is visible, `w3m-tab-line' and
> > `w3m-force-window-update' are constantly run, ca. 10 times per second.
> > Use `trace-function' to verify.
> Yes, I knew the tab line eats CPU not a little.  I also tried `elp':
> M-x elp-instrument-package RET w3m RET
> Run emacs-w3m for a while...
> M-x elp-results RET
> (If necessary, do `M-x elp-reset-all RET' to reset the result.)
> According to the result, `w3m-tab-line' and `w3m-force-window-update'
> seem to waste time not so much.  So, I was thinking we have nothing
> to have to do if those appetites don't grow anymore.

What you did doesn't necessarily reveal the misery, I think.  The loop
causes a _redisplay_ every 0.1 seconds, and this is what eats CPU.
Presumably this isn't shown in your results, because `w3m-tab-line' is
fast, and `w3m-force-window-update' terminates immediately before the
redisplay was performed.

How much CPU it costs depends on the contents of the current w3m window,
and what it displays.  A complex page is more critical as "about:".

I checked with profiler.el, M-x profiler-start, etc.  When I did nothing
with Emacs, 90% of the CPU time used by Emacs was consumed by the loop.
Absolutely, it makes ca. 5% of CPU usage at my (quite new) laptop.

> > 3. So, after 0.1 seconds, `w3m-force-window-update' is called.  This
> > redraws the window's header line, too, so we are back to 1.  Ouch!
> > I don't want to make a suggestion on how to fix this because I don't
> > know the code well.  We have to avoid the loop somehow.
> As you might think, another way to update the header line would
> be to make it event-driven.  That is, to modify all the functions,
> that change the header line appearance, so as to call `w3m-tab-line'
> if and only if it is necessary.

When I analyze the current code, it makes no sense.

Grep for `w3m-tab-line'.  It is only called at one single place in all
w3m files: in the :eval of the header line format of w3m buffers.  This
is only called when a redisplay is performed - so why do we need to
trigger another redisplay some time later?

All functions that do stuff making a refresh of the header line
necessary should trigger a redisplay - and that's what they already do,
I think (else, we would never enter any loop).

So, my guess is that removing

                   (run-at-time 0.1 nil
		     (lambda (buffer)
		       (when (buffer-live-p buffer)
			 (with-current-buffer buffer
			   (inline (w3m-force-window-update))
			   (setq w3m-tab-timer nil))))

from `w3m-tab-line' would do nothing harmful but prevent successive
unnecessary redisplays.  A short test seems to confirm that.

If we really face a situation where the tab line doesn't get updated, we
will just have to add an explicit redisplay.  The current code is only
helpful in a situation where a w3m function does something that changes
the tabs, performs redisplay, and then does another thing changing
the tabs a second time.  If there is really such a case, then we should
IMHO handle this case.

Or, do you mean we should even get rid of the :eval in the header-line
format?  This would increase performance even more, but this is a
separate issue.

Do you really think that would be hard?  I would think that we would
just need to recalculate the header line every time we explicitly
perform redisplay from the code.