unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
* bug#16129: 24.3.50; Emacs slow with follow-mode when buffer ends before last window
@ 2013-12-13 14:34 Anders Lindgren
  2013-12-13 15:32 ` Eli Zaretskii
  2013-12-13 16:38 ` Stefan Monnier
  0 siblings, 2 replies; 22+ messages in thread
From: Anders Lindgren @ 2013-12-13 14:34 UTC (permalink / raw)
  To: 16129

[-- Attachment #1: Type: text/plain, Size: 7244 bytes --]

When follow-mode is enabled and the displayed buffer ends before the last
window, Emacs becomes extremely slow.

This broke on revision 115272 (see log below).

Steps to repeat the problem:

    emacs -Q
    C-u 10 RET
    C-x 3
    M-x follow-mode RET
         Here, moving the cursor up or down one line takes about one
second. Holding and the arrow keys cause the cursor to disappear until the
key is released or the edge of the buffer has been reached.

The problem disappears as soon as some parts of the buffer is shown in the
rightmost window.

I am the original author of follow-mode, so I can share one interesting
implementation detail. When the viewed buffer ends before the last window,
follow-mode tries to display this window without any content (by setting
the window start to point-max). Unfortunately, the Emacs display engine
always tries ensure that windows are not empty so it repositions it... So,
follow-mode hammers in its view of the world every chance it gets,
currrently in post-command hook and window-scroll-functions.

Sincerely,
     Anders Lindgren

Ps. Log for revision 115272:

revno: 115272

committer: Stefan Monnier <monnier@iro.umontreal.ca>

branch nick: trunk

timestamp: Thu 2013-11-28 17:43:09 -0500

message:

  Refine redisplay optimizations to only redisplay *some* frames/windows

  rather than all of them.

  * src/xdisp.c (REDISPLAY_SOME): New constant.

  (redisplay_other_windows, wset_redisplay, fset_redisplay)

  (bset_redisplay, bset_update_mode_line): New functions.

  (message_dolog): Use bset_redisplay.

  (clear_garbaged_frames): Use fset_redisplay.

  (echo_area_display): Use wset_redisplay.

  (buffer_shared_and_changed): Remove.

  (prepare_menu_bars): Call Vpre_redisplay_function before updating

  frame titles.  Compute the actual set of windows redisplayed.

  Don't update frame titles and menu bars for frames that don't need to

  be redisplayed.

  (propagate_buffer_redisplay): New function.

  (AINC): New macro.

  (redisplay_internal): Use it.  Be more selective in the set of windows

  we redisplay.  Propagate windows_or_buffers_changed to

  update_mode_lines a bit later to simplify the code.

  (mark_window_display_accurate_1): Reset window and buffer's

  `redisplay' flag.

  (redisplay_window): Do nothing if neither the window nor the buffer nor

  the frame needs redisplay.

  * src/window.h (struct window): Add `redisplay' field.

  (wset_redisplay, fset_redisplay, bset_redisplay, bset_update_mode_line)

  (redisplay_other_windows, window_list): New declarations.

  * src/window.c (select_window, Fset_window_start): Use wset_redisplay.

  (window_list): Not static any more.

  (grow_mini_window, shrink_mini_window): Use fset_redisplay.

  * src/minibuf.c (read_minibuf_unwind): Don't redisplay everything.

  * src/insdel.c (prepare_to_modify_buffer_1): Use bset_redisplay.

  * src/frame.c (Fmake_frame_visible): Don't redisplay everything.

  * src/frame.h (struct frame): Add `redisplay' field.

  Move `external_menu_bar' bitfield next to other bit-fields.

  (SET_FRAME_GARBAGED): Use fset_redisplay.

  (SET_FRAME_VISIBLE): Don't garbage the frame;

  Use redisplay_other_windows.

  * src/buffer.h (struct buffer): Add `redisplay' field.

  * src/buffer.c (Fforce_mode_line_update): Pay attention to the `all' flag.

  (modify_overlay): Use bset_redisplay.

  * src/alloc.c (gc_sweep): Don't unmark strings while sweeping symbols.



  * lisp/doc-view.el (doc-view-goto-page): Update mode-line.




In GNU Emacs 24.3.50.1 (x86_64-apple-darwin13.0.0, NS apple-appkit-1265.00)
 of 2013-12-13 on macpro.lan
Bzr revision: 115272
monnier@iro.umontreal.ca-20131128224309-jg2ar5frhpri4yow
Windowing system distributor `Apple', version 10.3.1265
Configured using:
 `configure --with-ns'

Important settings:
  value of $LC_CTYPE: UTF-8
  locale-coding-system: utf-8-unix
  default enable-multibyte-characters: t

Major mode: Lisp Interaction

Minor modes in effect:
  follow-mode: t
  tooltip-mode: t
  mouse-wheel-mode: t
  tool-bar-mode: t
  menu-bar-mode: t
  file-name-shadow-mode: t
  global-font-lock-mode: t
  font-lock-mode: t
  blink-cursor-mode: t
  auto-composition-mode: t
  auto-encryption-mode: t
  auto-compression-mode: t
  line-number-mode: t
  transient-mark-mode: t

Recent input:
<up> <up> <up> <up> <up> <up> <up> <up> <up> <up> <up>
<up> <down> <down> <down> <down> <down> <down> <down>
<down> <down> <down> <down> <down> <down> <down> <down>
C-x 3 <up> <up> <up> <up> <up> <up> <up> <up> <escape>
x f o l l o w - d e <backspace> <backspace> m o d e
<return> <up> <up> <up> <up> <up> <up> <up> <up> <up>
<up> <down> <down> <down> <down> <down> <down> <down>
<down> <down> <down> <down> <down> <down> <down> <down>
<down> <down> <down> <down> <down> <down> <down> <down>
<down> <down> <down> <down> <up> <up> <up> <up> <up>
<up> <up> <up> <up> <up> C-h v e m a c s - b z <tab>
<return> <up> <up> <up> <up> <up> <up> <up> <up> <down>
<down> <down> <down> <down> <down> <down> <down> <down>
<down> <down> <down> <down> <down> <down> <down> <down>
<down> <up> <up> <up> <up> <up> <up> C-x o C-x b *
s c <tab> <return> <up> <up> <up> <up> <up> <up> <up>
<up> <up> <up> <up> <up> <up> <up> <down> <down> C-x
1 <down> <down> <down> <down> <down> <down> <down>
<down> <down> <menu-bar> <help-menu> <send-emacs-bug-report>
F o l l o w - m o d e SPC s <backspace> i s SPC <backspace>
<backspace> <backspace> <backspace> <backspace> <backspace>
<backspace> <backspace> <backspace> <backspace> <backspace>
<backspace> <backspace> <backspace> <backspace> R e
d i d <backspace> <backspace> <backspace> <backspace>
<backspace> E m a c s SPC i s SPC s l o w SPC w h e
n SPC f o l l o w - m o d e SPC i s SPC a <backspace>
e n a b l e d SPC a n d SPC b u f f e r SPC t a i l
C-a <right> <right> <right> <right> <right> <right>
<right> <right> <right> <s-backspace> <menu-bar> <help-menu>
<send-emacs-bug-report>

Recent messages:
Beginning of buffer
End of buffer
Follow mode enabled
Beginning of buffer [4 times]
End of buffer [13 times]
Type "q" in help window to restore its previous buffer.
Beginning of buffer [4 times]
End of buffer [4 times]
Beginning of buffer [6 times]
<s-backspace> is undefined
Quit

Load-path shadows:
None found.

Features:
(shadow sort gnus-util mail-extr emacsbug message format-spec rfc822 mml
mml-sec mm-decode mm-bodies mm-encode mail-parse rfc2231 mailabbrev
gmm-utils mailheader sendmail rfc2047 rfc2045 ietf-drums mm-util
mail-prsvr mail-utils pp help-mode help-fns follow easymenu time-date
tooltip ediff-hook vc-hooks lisp-float-type mwheel ns-win tool-bar dnd
fontset image regexp-opt fringe tabulated-list newcomment lisp-mode
prog-mode register page menu-bar rfn-eshadow timer select scroll-bar
mouse jit-lock font-lock syntax facemenu font-core frame cham georgian
utf-8-lang misc-lang vietnamese tibetan thai tai-viet lao korean
japanese hebrew greek romanian slovak czech european ethiopic indian
cyrillic chinese case-table epa-hook jka-cmpr-hook help simple abbrev
minibuffer nadvice loaddefs button faces cus-face macroexp files
text-properties overlay sha1 md5 base64 format env code-pages mule
custom widget hashtable-print-readable backquote make-network-process
cocoa ns multi-tty emacs)

[-- Attachment #2: Type: text/html, Size: 10709 bytes --]

^ permalink raw reply	[flat|nested] 22+ messages in thread

* bug#16129: 24.3.50; Emacs slow with follow-mode when buffer ends before last window
  2013-12-13 14:34 bug#16129: 24.3.50; Emacs slow with follow-mode when buffer ends before last window Anders Lindgren
@ 2013-12-13 15:32 ` Eli Zaretskii
  2013-12-13 15:36   ` Eli Zaretskii
  2013-12-13 16:38 ` Stefan Monnier
  1 sibling, 1 reply; 22+ messages in thread
From: Eli Zaretskii @ 2013-12-13 15:32 UTC (permalink / raw)
  To: Anders Lindgren; +Cc: 16129

> Date: Fri, 13 Dec 2013 15:34:07 +0100
> From: Anders Lindgren <andlind@gmail.com>
> 
> I am the original author of follow-mode, so I can share one interesting
> implementation detail. When the viewed buffer ends before the last window,
> follow-mode tries to display this window without any content (by setting
> the window start to point-max). Unfortunately, the Emacs display engine
> always tries ensure that windows are not empty so it repositions it...

You cannot have window-start and point-max, sorry.  Remember:
point-max is a buffer position that doesn't really exist, it's beyond
the end of buffer text.  So it cannot be treated as any other buffer
position.





^ permalink raw reply	[flat|nested] 22+ messages in thread

* bug#16129: 24.3.50; Emacs slow with follow-mode when buffer ends before last window
  2013-12-13 15:32 ` Eli Zaretskii
@ 2013-12-13 15:36   ` Eli Zaretskii
  0 siblings, 0 replies; 22+ messages in thread
From: Eli Zaretskii @ 2013-12-13 15:36 UTC (permalink / raw)
  To: andlind; +Cc: 16129

> Date: Fri, 13 Dec 2013 17:32:22 +0200
> From: Eli Zaretskii <eliz@gnu.org>
> Cc: 16129@debbugs.gnu.org
> 
> You cannot have window-start and point-max, sorry.
                               ^^^
Should be "at", not "and".

Btw, why this restriction requires follow-mode to hook all over the
place, is not entirely clear to me.  Perhaps if you tell the
reason(s), a better solution could be found.





^ permalink raw reply	[flat|nested] 22+ messages in thread

* bug#16129: 24.3.50; Emacs slow with follow-mode when buffer ends before last window
  2013-12-13 14:34 bug#16129: 24.3.50; Emacs slow with follow-mode when buffer ends before last window Anders Lindgren
  2013-12-13 15:32 ` Eli Zaretskii
@ 2013-12-13 16:38 ` Stefan Monnier
  2013-12-13 17:55   ` Anders Lindgren
  1 sibling, 1 reply; 22+ messages in thread
From: Stefan Monnier @ 2013-12-13 16:38 UTC (permalink / raw)
  To: Anders Lindgren; +Cc: 16129

> I am the original author of follow-mode, so I can share one interesting
> implementation detail. When the viewed buffer ends before the last window,
> follow-mode tries to display this window without any content (by setting
> the window start to point-max). Unfortunately, the Emacs display engine
> always tries ensure that windows are not empty so it repositions it... So,
> follow-mode hammers in its view of the world every chance it gets,
> currrently in post-command hook and window-scroll-functions.

Hmm.. so we have 2 things to do:
1- figure out why my patch slowed things down so much.
2- change follow-mode to use a different approach.  Maybe a good way is
   to do the following: put window-point at point-max, and add an overlay
   on window-start...point-max that makes the text invisible (with
   a `window' property, so it's only invisible in that window).
   Of course, maybe that won't work either.  But hooking everywhere
   doesn't sound like a good idea.


-- Stefab





^ permalink raw reply	[flat|nested] 22+ messages in thread

* bug#16129: 24.3.50; Emacs slow with follow-mode when buffer ends before last window
  2013-12-13 16:38 ` Stefan Monnier
@ 2013-12-13 17:55   ` Anders Lindgren
  2014-01-02 13:55     ` Anders Lindgren
  0 siblings, 1 reply; 22+ messages in thread
From: Anders Lindgren @ 2013-12-13 17:55 UTC (permalink / raw)
  To: Stefan Monnier, Eli Zaretskii; +Cc: 16129

[-- Attachment #1: Type: text/plain, Size: 2567 bytes --]

Hi!

I agree that we would need to find out why the patch makes Emacs slow. (In
fact, I only supplied the information about the internals of follow-mode to
help you track down the problems with the slowdown.)

However, I don't agree with Eli -- it is possible to place window-start at
point-max! However, there is code in the display engine that explicitly
recenters such windows, after a while, or when something happens. For
example:

     emacs -Q
     C-x 3
     C-x o
     M-: (set-window-start (selected-window) (point-max)) RET
     C-x o
     M-<
     blablabla     (type some text)

As you type text in the left window at the beginning of the scratch buffer,
the right window is recentered. Follow-mode needs its windows to stay put
(even the empty ones), as this is essential in creating the illusion that a
number of windows make up a very tall virtual window.

When I originally wrote follow-mode (some 18 years ago), I suggested to the
Emacs maintainers to add a feature to make the recentering of empty windows
conditional, so that follow-mode could control this. However, at the time
they were not interested so I continued with the current system, which has
worked flawlessly since then.

If you are interested in making the change in the display engine,
follow-mode should of course be rewritten to use it. Otherwise, I suggest
that we keep it as it is today -- solutions using overlays etc. don't
appeal to me at all.

    -- Anders



On Fri, Dec 13, 2013 at 5:38 PM, Stefan Monnier <monnier@iro.umontreal.ca>wrote:

> > I am the original author of follow-mode, so I can share one interesting
> > implementation detail. When the viewed buffer ends before the last
> window,
> > follow-mode tries to display this window without any content (by setting
> > the window start to point-max). Unfortunately, the Emacs display engine
> > always tries ensure that windows are not empty so it repositions it...
> So,
> > follow-mode hammers in its view of the world every chance it gets,
> > currrently in post-command hook and window-scroll-functions.
>
> Hmm.. so we have 2 things to do:
> 1- figure out why my patch slowed things down so much.
> 2- change follow-mode to use a different approach.  Maybe a good way is
>    to do the following: put window-point at point-max, and add an overlay
>    on window-start...point-max that makes the text invisible (with
>    a `window' property, so it's only invisible in that window).
>    Of course, maybe that won't work either.  But hooking everywhere
>    doesn't sound like a good idea.
>
>
> -- Stefab
>

[-- Attachment #2: Type: text/html, Size: 3254 bytes --]

^ permalink raw reply	[flat|nested] 22+ messages in thread

* bug#16129: 24.3.50; Emacs slow with follow-mode when buffer ends before last window
  2013-12-13 17:55   ` Anders Lindgren
@ 2014-01-02 13:55     ` Anders Lindgren
  2014-01-02 18:39       ` Anders Lindgren
  0 siblings, 1 reply; 22+ messages in thread
From: Anders Lindgren @ 2014-01-02 13:55 UTC (permalink / raw)
  To: Stefan Monnier, Eli Zaretskii; +Cc: 16129

[-- Attachment #1: Type: text/plain, Size: 3897 bytes --]

Hi again!

In addition to the problems I originally reported, I realized today that
the modification also made follow-mode place windows incorrectly, which
indicates that some primitive display-related function returns incorrect
values.

Do you want me to report a new bug, or should we see this as a second
symptom?

You can verify this by doing the following steps:

    emacs -Q
    C-h t
    M->
    M-x follow-delete-other-windows-and-split RET
    C-p
    C-p

After the second C-p, the left window is recentered, which is shouldn't.
This typically occurs when follow-mode thinks the point is not visible in
any window, which probably is due to incorrect values being reported from
primitive functions. (For example, in bug #15957 `window-end' didn't honour
it's FORCE argument, since some display functions didn't mark the end value
as being dirty.)

I will try to track this down in more detail. However, I wanted to give you
a heads up since it's appears as though you are close to a release -- it
might take me a couple of days to find the problem, as I have very limited
time to spend on Emacs-related things.

Sincerely,
    Anders Lindgren



On Fri, Dec 13, 2013 at 6:55 PM, Anders Lindgren <andlind@gmail.com> wrote:

> Hi!
>
> I agree that we would need to find out why the patch makes Emacs slow. (In
> fact, I only supplied the information about the internals of follow-mode to
> help you track down the problems with the slowdown.)
>
> However, I don't agree with Eli -- it is possible to place window-start at
> point-max! However, there is code in the display engine that explicitly
> recenters such windows, after a while, or when something happens. For
> example:
>
>      emacs -Q
>      C-x 3
>      C-x o
>      M-: (set-window-start (selected-window) (point-max)) RET
>      C-x o
>      M-<
>      blablabla     (type some text)
>
> As you type text in the left window at the beginning of the scratch
> buffer, the right window is recentered. Follow-mode needs its windows to
> stay put (even the empty ones), as this is essential in creating the
> illusion that a number of windows make up a very tall virtual window.
>
> When I originally wrote follow-mode (some 18 years ago), I suggested to
> the Emacs maintainers to add a feature to make the recentering of empty
> windows conditional, so that follow-mode could control this. However, at
> the time they were not interested so I continued with the current system,
> which has worked flawlessly since then.
>
> If you are interested in making the change in the display engine,
> follow-mode should of course be rewritten to use it. Otherwise, I suggest
> that we keep it as it is today -- solutions using overlays etc. don't
> appeal to me at all.
>
>     -- Anders
>
>
>
> On Fri, Dec 13, 2013 at 5:38 PM, Stefan Monnier <monnier@iro.umontreal.ca>wrote:
>
>> > I am the original author of follow-mode, so I can share one interesting
>> > implementation detail. When the viewed buffer ends before the last
>> window,
>> > follow-mode tries to display this window without any content (by setting
>> > the window start to point-max). Unfortunately, the Emacs display engine
>> > always tries ensure that windows are not empty so it repositions it...
>> So,
>> > follow-mode hammers in its view of the world every chance it gets,
>> > currrently in post-command hook and window-scroll-functions.
>>
>> Hmm.. so we have 2 things to do:
>> 1- figure out why my patch slowed things down so much.
>> 2- change follow-mode to use a different approach.  Maybe a good way is
>>    to do the following: put window-point at point-max, and add an overlay
>>    on window-start...point-max that makes the text invisible (with
>>    a `window' property, so it's only invisible in that window).
>>    Of course, maybe that won't work either.  But hooking everywhere
>>    doesn't sound like a good idea.
>>
>>
>> -- Stefab
>>
>
>

[-- Attachment #2: Type: text/html, Size: 5171 bytes --]

^ permalink raw reply	[flat|nested] 22+ messages in thread

* bug#16129: 24.3.50; Emacs slow with follow-mode when buffer ends before last window
  2014-01-02 13:55     ` Anders Lindgren
@ 2014-01-02 18:39       ` Anders Lindgren
  2014-01-05 23:13         ` Anders Lindgren
  0 siblings, 1 reply; 22+ messages in thread
From: Anders Lindgren @ 2014-01-02 18:39 UTC (permalink / raw)
  To: Stefan Monnier, Eli Zaretskii; +Cc: 16129

[-- Attachment #1: Type: text/plain, Size: 5728 bytes --]

Hi again!

I've dug a bit more into this. It looks like it's not follow-mode that
repositions the window, instead I guess it's some kind of recentering code
in the display engine that have gone "crazy".

I've managed to reproduce the problem with an extremely cut-down version of
the code, which simply reads and restores window-start of windows when
windows-start is point-max.

To reproduce, do the following:

    emacs -Q
    Enter and evaluate the following:

(defun my-avoid-tail-recenter (&rest _rest)
  (let* ((orig-buffer (current-buffer))
 (top (frame-first-window))
 (win top))
    ;; If the only window in the frame is a minibuffer
    ;; window, `next-window' will never find it again...
    (unless (window-minibuffer-p top)
      (while
  (let ((start (window-start win)))
    (set-buffer (window-buffer win))
    (if (eq (point-max) start)
;; Write the same window start back, but don't
;; set the NOFORCE flag.
(set-window-start win start))
    (setq win (next-window win 'not t))
    (not (eq win top))))  ;; Loop while this is true.
      (set-buffer orig-buffer))))

(add-hook 'post-command-hook 'my-avoid-tail-recenter)

    C-x 3
    M-: (set-window-start (selected-window) (point-max)) RET
    C-x o
    C-p

Here, the window will be recentered without there being any reason for it.

Note that this will apply to any window in any frame, as long as there is a
window where window-start == point-max, even if the window displays a
different buffer.

As this now falls outside of follow-mode, I think that I have reached the
end of what I can contribute...

Sincerely,
     Anders Lindgren



On Thu, Jan 2, 2014 at 2:55 PM, Anders Lindgren <andlind@gmail.com> wrote:

> Hi again!
>
> In addition to the problems I originally reported, I realized today that
> the modification also made follow-mode place windows incorrectly, which
> indicates that some primitive display-related function returns incorrect
> values.
>
> Do you want me to report a new bug, or should we see this as a second
> symptom?
>
> You can verify this by doing the following steps:
>
>     emacs -Q
>     C-h t
>     M->
>     M-x follow-delete-other-windows-and-split RET
>     C-p
>     C-p
>
> After the second C-p, the left window is recentered, which is shouldn't.
> This typically occurs when follow-mode thinks the point is not visible in
> any window, which probably is due to incorrect values being reported from
> primitive functions. (For example, in bug #15957 `window-end' didn't honour
> it's FORCE argument, since some display functions didn't mark the end value
> as being dirty.)
>
> I will try to track this down in more detail. However, I wanted to give
> you a heads up since it's appears as though you are close to a release --
> it might take me a couple of days to find the problem, as I have very
> limited time to spend on Emacs-related things.
>
> Sincerely,
>     Anders Lindgren
>
>
>
> On Fri, Dec 13, 2013 at 6:55 PM, Anders Lindgren <andlind@gmail.com>wrote:
>
>> Hi!
>>
>> I agree that we would need to find out why the patch makes Emacs slow.
>> (In fact, I only supplied the information about the internals of
>> follow-mode to help you track down the problems with the slowdown.)
>>
>> However, I don't agree with Eli -- it is possible to place window-start
>> at point-max! However, there is code in the display engine that explicitly
>> recenters such windows, after a while, or when something happens. For
>> example:
>>
>>      emacs -Q
>>      C-x 3
>>      C-x o
>>      M-: (set-window-start (selected-window) (point-max)) RET
>>      C-x o
>>      M-<
>>      blablabla     (type some text)
>>
>> As you type text in the left window at the beginning of the scratch
>> buffer, the right window is recentered. Follow-mode needs its windows to
>> stay put (even the empty ones), as this is essential in creating the
>> illusion that a number of windows make up a very tall virtual window.
>>
>> When I originally wrote follow-mode (some 18 years ago), I suggested to
>> the Emacs maintainers to add a feature to make the recentering of empty
>> windows conditional, so that follow-mode could control this. However, at
>> the time they were not interested so I continued with the current system,
>> which has worked flawlessly since then.
>>
>> If you are interested in making the change in the display engine,
>> follow-mode should of course be rewritten to use it. Otherwise, I suggest
>> that we keep it as it is today -- solutions using overlays etc. don't
>> appeal to me at all.
>>
>>     -- Anders
>>
>>
>>
>> On Fri, Dec 13, 2013 at 5:38 PM, Stefan Monnier <monnier@iro.umontreal.ca
>> > wrote:
>>
>>> > I am the original author of follow-mode, so I can share one interesting
>>> > implementation detail. When the viewed buffer ends before the last
>>> window,
>>> > follow-mode tries to display this window without any content (by
>>> setting
>>> > the window start to point-max). Unfortunately, the Emacs display engine
>>> > always tries ensure that windows are not empty so it repositions it...
>>> So,
>>> > follow-mode hammers in its view of the world every chance it gets,
>>> > currrently in post-command hook and window-scroll-functions.
>>>
>>> Hmm.. so we have 2 things to do:
>>> 1- figure out why my patch slowed things down so much.
>>> 2- change follow-mode to use a different approach.  Maybe a good way is
>>>    to do the following: put window-point at point-max, and add an overlay
>>>    on window-start...point-max that makes the text invisible (with
>>>    a `window' property, so it's only invisible in that window).
>>>    Of course, maybe that won't work either.  But hooking everywhere
>>>    doesn't sound like a good idea.
>>>
>>>
>>> -- Stefab
>>>
>>
>>
>

[-- Attachment #2: Type: text/html, Size: 8230 bytes --]

^ permalink raw reply	[flat|nested] 22+ messages in thread

* bug#16129: 24.3.50; Emacs slow with follow-mode when buffer ends before last window
  2014-01-02 18:39       ` Anders Lindgren
@ 2014-01-05 23:13         ` Anders Lindgren
  2014-01-06  3:45           ` Eli Zaretskii
  0 siblings, 1 reply; 22+ messages in thread
From: Anders Lindgren @ 2014-01-05 23:13 UTC (permalink / raw)
  To: Stefan Monnier, Eli Zaretskii; +Cc: 16129

[-- Attachment #1: Type: text/plain, Size: 7198 bytes --]

Hi again!

As I haven't heard anything on this bug for a while, I tried to track down
the problem myself. I have found something that looks like the cause of the
problem, however, I haven't looked into a way to solve it.

When "redisplay_window" is called, it goes into the case where
"try_cursor_movement" is called.

Inside this routine, the row is picked up. The row (when using the TUTORIAL
example) has start and end at 46229. The point and last_point, however, are
46228, so it assumes that the point haven't moved since the last redisplay.

Clearly, "last_point" and "row" are not consistent with each other, which
is assumed by try_cursor_movement (if I read it correctly).

The routine first declare this to be a "success" (in the neither forward
nor backward case). Later in the function it comes to the following
statement:

  if (PT < MATRIX_ROW_START_CHARPOS (row)
      || PT > MATRIX_ROW_END_CHARPOS (row))

This fails, making the function return " CURSOR_MOVEMENT_MUST_SCROLL",
which is turn cause "redisplay_window" to recenter the window.

Please respond if this is enough information for you to track down the
problem.

Sincerely,
    Anders Lindgren



On Thu, Jan 2, 2014 at 7:39 PM, Anders Lindgren <andlind@gmail.com> wrote:

> Hi again!
>
> I've dug a bit more into this. It looks like it's not follow-mode that
> repositions the window, instead I guess it's some kind of recentering code
> in the display engine that have gone "crazy".
>
> I've managed to reproduce the problem with an extremely cut-down version
> of the code, which simply reads and restores window-start of windows when
> windows-start is point-max.
>
> To reproduce, do the following:
>
>     emacs -Q
>     Enter and evaluate the following:
>
> (defun my-avoid-tail-recenter (&rest _rest)
>   (let* ((orig-buffer (current-buffer))
>  (top (frame-first-window))
>  (win top))
>     ;; If the only window in the frame is a minibuffer
>     ;; window, `next-window' will never find it again...
>     (unless (window-minibuffer-p top)
>       (while
>   (let ((start (window-start win)))
>     (set-buffer (window-buffer win))
>     (if (eq (point-max) start)
> ;; Write the same window start back, but don't
>  ;; set the NOFORCE flag.
> (set-window-start win start))
>     (setq win (next-window win 'not t))
>     (not (eq win top))))  ;; Loop while this is true.
>       (set-buffer orig-buffer))))
>
> (add-hook 'post-command-hook 'my-avoid-tail-recenter)
>
>     C-x 3
>     M-: (set-window-start (selected-window) (point-max)) RET
>     C-x o
>     C-p
>
> Here, the window will be recentered without there being any reason for it.
>
> Note that this will apply to any window in any frame, as long as there is
> a window where window-start == point-max, even if the window displays a
> different buffer.
>
> As this now falls outside of follow-mode, I think that I have reached the
> end of what I can contribute...
>
> Sincerely,
>      Anders Lindgren
>
>
>
> On Thu, Jan 2, 2014 at 2:55 PM, Anders Lindgren <andlind@gmail.com> wrote:
>
>> Hi again!
>>
>> In addition to the problems I originally reported, I realized today that
>> the modification also made follow-mode place windows incorrectly, which
>> indicates that some primitive display-related function returns incorrect
>> values.
>>
>> Do you want me to report a new bug, or should we see this as a second
>> symptom?
>>
>> You can verify this by doing the following steps:
>>
>>     emacs -Q
>>     C-h t
>>     M->
>>     M-x follow-delete-other-windows-and-split RET
>>     C-p
>>     C-p
>>
>> After the second C-p, the left window is recentered, which is shouldn't.
>> This typically occurs when follow-mode thinks the point is not visible in
>> any window, which probably is due to incorrect values being reported from
>> primitive functions. (For example, in bug #15957 `window-end' didn't honour
>> it's FORCE argument, since some display functions didn't mark the end value
>> as being dirty.)
>>
>> I will try to track this down in more detail. However, I wanted to give
>> you a heads up since it's appears as though you are close to a release --
>> it might take me a couple of days to find the problem, as I have very
>> limited time to spend on Emacs-related things.
>>
>> Sincerely,
>>     Anders Lindgren
>>
>>
>>
>> On Fri, Dec 13, 2013 at 6:55 PM, Anders Lindgren <andlind@gmail.com>wrote:
>>
>>> Hi!
>>>
>>> I agree that we would need to find out why the patch makes Emacs slow.
>>> (In fact, I only supplied the information about the internals of
>>> follow-mode to help you track down the problems with the slowdown.)
>>>
>>> However, I don't agree with Eli -- it is possible to place window-start
>>> at point-max! However, there is code in the display engine that explicitly
>>> recenters such windows, after a while, or when something happens. For
>>> example:
>>>
>>>      emacs -Q
>>>      C-x 3
>>>      C-x o
>>>      M-: (set-window-start (selected-window) (point-max)) RET
>>>      C-x o
>>>      M-<
>>>      blablabla     (type some text)
>>>
>>> As you type text in the left window at the beginning of the scratch
>>> buffer, the right window is recentered. Follow-mode needs its windows to
>>> stay put (even the empty ones), as this is essential in creating the
>>> illusion that a number of windows make up a very tall virtual window.
>>>
>>> When I originally wrote follow-mode (some 18 years ago), I suggested to
>>> the Emacs maintainers to add a feature to make the recentering of empty
>>> windows conditional, so that follow-mode could control this. However, at
>>> the time they were not interested so I continued with the current system,
>>> which has worked flawlessly since then.
>>>
>>> If you are interested in making the change in the display engine,
>>> follow-mode should of course be rewritten to use it. Otherwise, I suggest
>>> that we keep it as it is today -- solutions using overlays etc. don't
>>> appeal to me at all.
>>>
>>>     -- Anders
>>>
>>>
>>>
>>> On Fri, Dec 13, 2013 at 5:38 PM, Stefan Monnier <
>>> monnier@iro.umontreal.ca> wrote:
>>>
>>>> > I am the original author of follow-mode, so I can share one
>>>> interesting
>>>> > implementation detail. When the viewed buffer ends before the last
>>>> window,
>>>> > follow-mode tries to display this window without any content (by
>>>> setting
>>>> > the window start to point-max). Unfortunately, the Emacs display
>>>> engine
>>>> > always tries ensure that windows are not empty so it repositions
>>>> it... So,
>>>> > follow-mode hammers in its view of the world every chance it gets,
>>>> > currrently in post-command hook and window-scroll-functions.
>>>>
>>>> Hmm.. so we have 2 things to do:
>>>> 1- figure out why my patch slowed things down so much.
>>>> 2- change follow-mode to use a different approach.  Maybe a good way is
>>>>    to do the following: put window-point at point-max, and add an
>>>> overlay
>>>>    on window-start...point-max that makes the text invisible (with
>>>>    a `window' property, so it's only invisible in that window).
>>>>    Of course, maybe that won't work either.  But hooking everywhere
>>>>    doesn't sound like a good idea.
>>>>
>>>>
>>>> -- Stefab
>>>>
>>>
>>>
>>
>

[-- Attachment #2: Type: text/html, Size: 10286 bytes --]

^ permalink raw reply	[flat|nested] 22+ messages in thread

* bug#16129: 24.3.50; Emacs slow with follow-mode when buffer ends before last window
  2014-01-05 23:13         ` Anders Lindgren
@ 2014-01-06  3:45           ` Eli Zaretskii
  2014-01-06  8:20             ` Anders Lindgren
  0 siblings, 1 reply; 22+ messages in thread
From: Eli Zaretskii @ 2014-01-06  3:45 UTC (permalink / raw)
  To: Anders Lindgren; +Cc: 16129

> Date: Mon, 6 Jan 2014 00:13:38 +0100
> From: Anders Lindgren <andlind@gmail.com>
> Cc: 16129@debbugs.gnu.org
> 
> When "redisplay_window" is called, it goes into the case where
> "try_cursor_movement" is called.
> 
> Inside this routine, the row is picked up. The row (when using the TUTORIAL
> example) has start and end at 46229. The point and last_point, however, are
> 46228, so it assumes that the point haven't moved since the last redisplay.
> 
> Clearly, "last_point" and "row" are not consistent with each other, which
> is assumed by try_cursor_movement (if I read it correctly).
> 
> The routine first declare this to be a "success" (in the neither forward
> nor backward case). Later in the function it comes to the following
> statement:
> 
>   if (PT < MATRIX_ROW_START_CHARPOS (row)
>       || PT > MATRIX_ROW_END_CHARPOS (row))
> 
> This fails, making the function return " CURSOR_MOVEMENT_MUST_SCROLL",
> which is turn cause "redisplay_window" to recenter the window.

Thanks.  Your description is correct, and I already found that this is
what happens.  (The silence doesn't necessarily mean no one is doing
anything about the bug report ;-)

I didn't yet have the time to figure out why the last_point field of
the window is equal to point, while last_cursor_vpos points to the
screen line that does not contain point; my current suspicion is that
the post-command-hook somehow causes that.  But given that this is
what happens, you will always see a recenter, because it means Emacs
lost track of where point is in the window.  When Emacs is confused
about this, it always recenters as the last resort.

This still doesn't say why redisplay is so slow in this case, which
was the initial bug reported here.  Stay tuned.





^ permalink raw reply	[flat|nested] 22+ messages in thread

* bug#16129: 24.3.50; Emacs slow with follow-mode when buffer ends before last window
  2014-01-06  3:45           ` Eli Zaretskii
@ 2014-01-06  8:20             ` Anders Lindgren
  2014-01-06 16:33               ` Eli Zaretskii
  0 siblings, 1 reply; 22+ messages in thread
From: Anders Lindgren @ 2014-01-06  8:20 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 16129

[-- Attachment #1: Type: text/plain, Size: 2204 bytes --]

Hi!

I think the incorrect state occurs when the new early exit occurs from
redsplay_window. When I added the condition "&& PT == w->last_point", both
the recentering problem and speed issues were solved. However, I don't know
if this is the correct way to handle this, or if it breaks anything else.

    -- Anders


On Mon, Jan 6, 2014 at 4:45 AM, Eli Zaretskii <eliz@gnu.org> wrote:

> > Date: Mon, 6 Jan 2014 00:13:38 +0100
> > From: Anders Lindgren <andlind@gmail.com>
> > Cc: 16129@debbugs.gnu.org
> >
> > When "redisplay_window" is called, it goes into the case where
> > "try_cursor_movement" is called.
> >
> > Inside this routine, the row is picked up. The row (when using the
> TUTORIAL
> > example) has start and end at 46229. The point and last_point, however,
> are
> > 46228, so it assumes that the point haven't moved since the last
> redisplay.
> >
> > Clearly, "last_point" and "row" are not consistent with each other, which
> > is assumed by try_cursor_movement (if I read it correctly).
> >
> > The routine first declare this to be a "success" (in the neither forward
> > nor backward case). Later in the function it comes to the following
> > statement:
> >
> >   if (PT < MATRIX_ROW_START_CHARPOS (row)
> >       || PT > MATRIX_ROW_END_CHARPOS (row))
> >
> > This fails, making the function return " CURSOR_MOVEMENT_MUST_SCROLL",
> > which is turn cause "redisplay_window" to recenter the window.
>
> Thanks.  Your description is correct, and I already found that this is
> what happens.  (The silence doesn't necessarily mean no one is doing
> anything about the bug report ;-)
>
> I didn't yet have the time to figure out why the last_point field of
> the window is equal to point, while last_cursor_vpos points to the
> screen line that does not contain point; my current suspicion is that
> the post-command-hook somehow causes that.  But given that this is
> what happens, you will always see a recenter, because it means Emacs
> lost track of where point is in the window.  When Emacs is confused
> about this, it always recenters as the last resort.
>
> This still doesn't say why redisplay is so slow in this case, which
> was the initial bug reported here.  Stay tuned.
>

[-- Attachment #2: Type: text/html, Size: 2951 bytes --]

^ permalink raw reply	[flat|nested] 22+ messages in thread

* bug#16129: 24.3.50; Emacs slow with follow-mode when buffer ends before last window
  2014-01-06  8:20             ` Anders Lindgren
@ 2014-01-06 16:33               ` Eli Zaretskii
  2014-01-07  8:13                 ` Anders Lindgren
  0 siblings, 1 reply; 22+ messages in thread
From: Eli Zaretskii @ 2014-01-06 16:33 UTC (permalink / raw)
  To: Anders Lindgren; +Cc: 16129-done

> Date: Mon, 6 Jan 2014 09:20:03 +0100
> From: Anders Lindgren <andlind@gmail.com>
> Cc: Stefan Monnier <monnier@iro.umontreal.ca>, 16129@debbugs.gnu.org
> 
> I think the incorrect state occurs when the new early exit occurs from
> redsplay_window. When I added the condition "&& PT == w->last_point", both
> the recentering problem and speed issues were solved.

Indeed, this was my conclusion as well.  (Except that PT is not quite
right, as the window could be displaying a buffer that is not the
current one at that early point in redisplay_window.)

What this caused was that the window redisplay was mistakenly skipped,
but then we marked that window's display "accurate", which confused
the heck out of the display engine.

So I installed the patch below to fix this regression, and I'm marking
this bug done.  Feel free to reopen if there are any leftovers.

Btw, I strongly recommend against messing with window-start (or
anything else that potentially requires redisplay) in a
post-command-hook: doing so disables some important redisplay
optimizations, and can easily trigger subtle misfeatures.  I suggest
to look for a better method to do what follow-mode needs to do, even
if that means we'd have to implement a special hook we don't yet have.

Thanks.

=== modified file 'src/xdisp.c'
--- src/xdisp.c	2014-01-01 17:44:48 +0000
+++ src/xdisp.c	2014-01-06 16:21:39 +0000
@@ -15621,7 +15621,8 @@ redisplay_window (Lisp_Object window, bo
       && REDISPLAY_SOME_P ()
       && !w->redisplay
       && !f->redisplay
-      && !buffer->text->redisplay)
+      && !buffer->text->redisplay
+      && BUF_PT (buffer) == w->last_point)
     return;
 
   /* Make sure that both W's markers are valid.  */






^ permalink raw reply	[flat|nested] 22+ messages in thread

* bug#16129: 24.3.50; Emacs slow with follow-mode when buffer ends before last window
  2014-01-06 16:33               ` Eli Zaretskii
@ 2014-01-07  8:13                 ` Anders Lindgren
  2014-01-10  9:31                   ` Eli Zaretskii
  0 siblings, 1 reply; 22+ messages in thread
From: Anders Lindgren @ 2014-01-07  8:13 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 16129-done

[-- Attachment #1: Type: text/plain, Size: 3561 bytes --]

Hi!

Thanks, I tried it out on the trunk, and it seems to be working correctly!


I'm open to reimplementing follow-mode in another way, if you think that
it's necessary. However, there are two different uses of set-window-start,
and maybe we don't need to change both:

* Normally, when the position of the active window change, the start of the
other windows are updated. This occurs very infrequent, and it would
require a redisplay anyway.
* When a window shows the empty tail of a buffer, point-max is "hammered"
into window-start to ensure that the display engine doesn't recenter the
window.

Of the two uses, I only consider the second a problem. However, it would
probably be easy to handle if there would be a windows-specific option or
call-back that could control if the window should  be recentered or not.


While I'm at it, I realized today that the responsiveness when using
follow-mode was better when running the cursor up and down compared to left
and right. When looking into the details I saw that the arrow keys no
longer were bound to previous- and next-char, so we need to apply the patch
below to follow-mode (I don't have write-access to the archives).

Thanks for your help,
    Anders

=== modified file 'lisp/follow.el'

--- lisp/follow.el 2014-01-01 07:43:34 +0000

+++ lisp/follow.el 2014-01-07 07:48:40 +0000

@@ -311,7 +311,7 @@

  (set-default symbol value)))



 (defvar follow-cache-command-list

-  '(next-line previous-line forward-char backward-char)

+  '(next-line previous-line forward-char backward-char right-char
left-char)

   "List of commands that don't require recalculation.



 In order to be able to use the cache, a command should not change the




On Mon, Jan 6, 2014 at 5:33 PM, Eli Zaretskii <eliz@gnu.org> wrote:

> > Date: Mon, 6 Jan 2014 09:20:03 +0100
> > From: Anders Lindgren <andlind@gmail.com>
> > Cc: Stefan Monnier <monnier@iro.umontreal.ca>, 16129@debbugs.gnu.org
> >
> > I think the incorrect state occurs when the new early exit occurs from
> > redsplay_window. When I added the condition "&& PT == w->last_point",
> both
> > the recentering problem and speed issues were solved.
>
> Indeed, this was my conclusion as well.  (Except that PT is not quite
> right, as the window could be displaying a buffer that is not the
> current one at that early point in redisplay_window.)
>
> What this caused was that the window redisplay was mistakenly skipped,
> but then we marked that window's display "accurate", which confused
> the heck out of the display engine.
>
> So I installed the patch below to fix this regression, and I'm marking
> this bug done.  Feel free to reopen if there are any leftovers.
>
> Btw, I strongly recommend against messing with window-start (or
> anything else that potentially requires redisplay) in a
> post-command-hook: doing so disables some important redisplay
> optimizations, and can easily trigger subtle misfeatures.  I suggest
> to look for a better method to do what follow-mode needs to do, even
> if that means we'd have to implement a special hook we don't yet have.
>
> Thanks.
>
> === modified file 'src/xdisp.c'
> --- src/xdisp.c 2014-01-01 17:44:48 +0000
> +++ src/xdisp.c 2014-01-06 16:21:39 +0000
> @@ -15621,7 +15621,8 @@ redisplay_window (Lisp_Object window, bo
>        && REDISPLAY_SOME_P ()
>        && !w->redisplay
>        && !f->redisplay
> -      && !buffer->text->redisplay)
> +      && !buffer->text->redisplay
> +      && BUF_PT (buffer) == w->last_point)
>      return;
>
>    /* Make sure that both W's markers are valid.  */
>
>

[-- Attachment #2: Type: text/html, Size: 4876 bytes --]

^ permalink raw reply	[flat|nested] 22+ messages in thread

* bug#16129: 24.3.50; Emacs slow with follow-mode when buffer ends before last window
  2014-01-07  8:13                 ` Anders Lindgren
@ 2014-01-10  9:31                   ` Eli Zaretskii
  2014-01-10 18:52                     ` Anders Lindgren
  0 siblings, 1 reply; 22+ messages in thread
From: Eli Zaretskii @ 2014-01-10  9:31 UTC (permalink / raw)
  To: Anders Lindgren; +Cc: 16129

> Date: Tue, 7 Jan 2014 09:13:19 +0100
> From: Anders Lindgren <andlind@gmail.com>
> Cc: Stefan Monnier <monnier@iro.umontreal.ca>, 16129-done@debbugs.gnu.org
> 
> Thanks, I tried it out on the trunk, and it seems to be working correctly!

Thanks for testing.

> I'm open to reimplementing follow-mode in another way, if you think that
> it's necessary. However, there are two different uses of set-window-start,
> and maybe we don't need to change both:
> 
> * Normally, when the position of the active window change, the start of the
> other windows are updated. This occurs very infrequent, and it would
> require a redisplay anyway.
> * When a window shows the empty tail of a buffer, point-max is "hammered"
> into window-start to ensure that the display engine doesn't recenter the
> window.
> 
> Of the two uses, I only consider the second a problem.

I think we should consider both, because they both are detrimental to
the efficiency of redisplay.

You see, the Emacs redisplay has a very complex problem to solve,
because there are a gazillion of ways to change some obscure Lisp data
structure that can potentially change what should be on the glass.
However, if redisplay needed to examine all those potential changes
and decide whether they actually change the displayed portion of the
buffer, redisplay would become painfully slow.

So we have a lot of optimizations in the display engine, each of which
basically says: if none of the following events happened since last
redisplay cycle, then this and that potential changes don't need to be
considered.  Each optimization comes with a list of events that
invalidate it.  Redisplay basically tries to apply each optimization
in sequence, starting from the most aggressive one, until it finds one
that can be applied, or falls back to the unoptimized code, which
redisplays the entire window.

To be able to pull this trick, the display engine maintains a set of
flags, each one of which tells whether a particular kind of event
happened since last redisplay.  These flags are consulted when the
display engine must decide which optimization, if any, is applicable.

One of these flag variables is the window start point: as long as it
stays put, Emacs does not need to bother recomputing it, and does not
need to invalidate the information it keeps about where in the buffer
text is the window start point, given the current value of point.

When a post-command-hook forces a value of window-start, some of these
optimizations are inapplicable, so Emacs responsiveness suffers.  For
example, when follow-mode is on, Emacs frequently needs to redisplay
the same window twice in a row, instead of just once.

> However, it would probably be easy to handle if there would be a
> windows-specific option or call-back that could control if the
> window should be recentered or not.

That's not what I had in mind.  Instead, we could have special code in
the display engine that would automatically scroll the other window(s)
when follow-mode says they should.  IOW, when Emacs redisplays some
window because something changed in it, the display engine could
decide right there and then that some other windows need to be
redisplayed, and moreover, compute their window-start point
automatically or by calling some Lisp.  After all, the relations that
determine the window-start of the windows which participate in
follow-mode is quite simple: the next window should begin where the
previous one ends.  All of this could be done in a single redisplay
cycle, thereby avoiding the need for a post-command-hook in the first
place.  The benefit would be not only a more efficient redisplay, but
also faster Emacs, because many commands do not affect any display,
and many others do not affect windows that are under follow-mode, so
in this case a post-command-hook forces Emacs to perform unnecessary
redisplay.

> While I'm at it, I realized today that the responsiveness when using
> follow-mode was better when running the cursor up and down compared to left
> and right. When looking into the details I saw that the arrow keys no
> longer were bound to previous- and next-char, so we need to apply the patch
> below to follow-mode (I don't have write-access to the archives).

I installed this in your name.  Thanks.





^ permalink raw reply	[flat|nested] 22+ messages in thread

* bug#16129: 24.3.50; Emacs slow with follow-mode when buffer ends before last window
  2014-01-10  9:31                   ` Eli Zaretskii
@ 2014-01-10 18:52                     ` Anders Lindgren
  2014-01-10 19:00                       ` Eli Zaretskii
  0 siblings, 1 reply; 22+ messages in thread
From: Anders Lindgren @ 2014-01-10 18:52 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 16129

[-- Attachment #1: Type: text/plain, Size: 5537 bytes --]

Eli,

I agree that follow-mode slows down Emacs, even though the effect is more
visible now compared to earlier. Up to Emacs 22, it really was fast. With
Emacs 23 it feels like there is a definitive slowdown, which is visible
e.g. when typing plain text fast and when scrolling window. (In fact, at
work where I use Windows, I still use Emacs 22.)

Implementing follow-mode in the display engine sounds like a wonderful
idea! In fact, when I originally wrote it (back in 1995) I intended it to
be a prototype, but I envisioned the real implementation to be done in the
display engine. Unfortunately, the people responsible for the display
engine at the time didn't like the idea, so I made follow-mode to an
all-lisp package.

Concretely, how do we proceed from here? I don't have the necessary
knowledge of the internals of the display engine and I don't have much time
to spend on a major rewrite like this. However, if someone decides to
proceed with this, I will try to support them as much that I can.

    -- Anders


On Fri, Jan 10, 2014 at 10:31 AM, Eli Zaretskii <eliz@gnu.org> wrote:

> > Date: Tue, 7 Jan 2014 09:13:19 +0100
> > From: Anders Lindgren <andlind@gmail.com>
> > Cc: Stefan Monnier <monnier@iro.umontreal.ca>,
> 16129-done@debbugs.gnu.org
> >
> > Thanks, I tried it out on the trunk, and it seems to be working
> correctly!
>
> Thanks for testing.
>
> > I'm open to reimplementing follow-mode in another way, if you think that
> > it's necessary. However, there are two different uses of
> set-window-start,
> > and maybe we don't need to change both:
> >
> > * Normally, when the position of the active window change, the start of
> the
> > other windows are updated. This occurs very infrequent, and it would
> > require a redisplay anyway.
> > * When a window shows the empty tail of a buffer, point-max is "hammered"
> > into window-start to ensure that the display engine doesn't recenter the
> > window.
> >
> > Of the two uses, I only consider the second a problem.
>
> I think we should consider both, because they both are detrimental to
> the efficiency of redisplay.
>
> You see, the Emacs redisplay has a very complex problem to solve,
> because there are a gazillion of ways to change some obscure Lisp data
> structure that can potentially change what should be on the glass.
> However, if redisplay needed to examine all those potential changes
> and decide whether they actually change the displayed portion of the
> buffer, redisplay would become painfully slow.
>
> So we have a lot of optimizations in the display engine, each of which
> basically says: if none of the following events happened since last
> redisplay cycle, then this and that potential changes don't need to be
> considered.  Each optimization comes with a list of events that
> invalidate it.  Redisplay basically tries to apply each optimization
> in sequence, starting from the most aggressive one, until it finds one
> that can be applied, or falls back to the unoptimized code, which
> redisplays the entire window.
>
> To be able to pull this trick, the display engine maintains a set of
> flags, each one of which tells whether a particular kind of event
> happened since last redisplay.  These flags are consulted when the
> display engine must decide which optimization, if any, is applicable.
>
> One of these flag variables is the window start point: as long as it
> stays put, Emacs does not need to bother recomputing it, and does not
> need to invalidate the information it keeps about where in the buffer
> text is the window start point, given the current value of point.
>
> When a post-command-hook forces a value of window-start, some of these
> optimizations are inapplicable, so Emacs responsiveness suffers.  For
> example, when follow-mode is on, Emacs frequently needs to redisplay
> the same window twice in a row, instead of just once.
>
> > However, it would probably be easy to handle if there would be a
> > windows-specific option or call-back that could control if the
> > window should be recentered or not.
>
> That's not what I had in mind.  Instead, we could have special code in
> the display engine that would automatically scroll the other window(s)
> when follow-mode says they should.  IOW, when Emacs redisplays some
> window because something changed in it, the display engine could
> decide right there and then that some other windows need to be
> redisplayed, and moreover, compute their window-start point
> automatically or by calling some Lisp.  After all, the relations that
> determine the window-start of the windows which participate in
> follow-mode is quite simple: the next window should begin where the
> previous one ends.  All of this could be done in a single redisplay
> cycle, thereby avoiding the need for a post-command-hook in the first
> place.  The benefit would be not only a more efficient redisplay, but
> also faster Emacs, because many commands do not affect any display,
> and many others do not affect windows that are under follow-mode, so
> in this case a post-command-hook forces Emacs to perform unnecessary
> redisplay.
>
> > While I'm at it, I realized today that the responsiveness when using
> > follow-mode was better when running the cursor up and down compared to
> left
> > and right. When looking into the details I saw that the arrow keys no
> > longer were bound to previous- and next-char, so we need to apply the
> patch
> > below to follow-mode (I don't have write-access to the archives).
>
> I installed this in your name.  Thanks.
>

[-- Attachment #2: Type: text/html, Size: 6540 bytes --]

^ permalink raw reply	[flat|nested] 22+ messages in thread

* bug#16129: 24.3.50; Emacs slow with follow-mode when buffer ends before last window
  2014-01-10 18:52                     ` Anders Lindgren
@ 2014-01-10 19:00                       ` Eli Zaretskii
  2014-01-13 11:41                         ` Anders Lindgren
  0 siblings, 1 reply; 22+ messages in thread
From: Eli Zaretskii @ 2014-01-10 19:00 UTC (permalink / raw)
  To: Anders Lindgren; +Cc: 16129

> Date: Fri, 10 Jan 2014 19:52:18 +0100
> From: Anders Lindgren <andlind@gmail.com>
> Cc: Stefan Monnier <monnier@iro.umontreal.ca>, 16129@debbugs.gnu.org
> 
> Concretely, how do we proceed from here? I don't have the necessary
> knowledge of the internals of the display engine and I don't have much time
> to spend on a major rewrite like this. However, if someone decides to
> proceed with this, I will try to support them as much that I can.

I suggest to file a separate feature request bug report about this,
and include in it the requirements for the display engine to support
follow-mode.  That is, given a set of windows that are "following"
each other, what should redisplay do when certain display-related
events happen.  Then interested volunteers can implement that.





^ permalink raw reply	[flat|nested] 22+ messages in thread

* bug#16129: 24.3.50; Emacs slow with follow-mode when buffer ends before last window
  2014-01-10 19:00                       ` Eli Zaretskii
@ 2014-01-13 11:41                         ` Anders Lindgren
  2014-01-13 14:47                           ` Stefan Monnier
  2014-01-13 16:16                           ` Eli Zaretskii
  0 siblings, 2 replies; 22+ messages in thread
From: Anders Lindgren @ 2014-01-13 11:41 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 16129

[-- Attachment #1: Type: text/plain, Size: 1696 bytes --]

Sounds like a good idea to post this feature request. However, being a
realist, I doubt that this will happen anytime soon.

I would suggest that we also post feature requests for things that would
help the situation on a shorter time scale. Primarily, I would like to be
able, on a window-by-window basis, control whether or not a window should
be recentered, when empty. Also, we might look into the speed issues, we
might be able to avoid double redraws with little effort, for the common
cases.

While I'm at it. I updated to the latest trunk today and saw that cursor
movements are a lot faster now, including the when the tail is showing.
However, I noticed that when the region is active, the region highlight is
not updated as fast as it is when follow-mode is off, when running the
cursor.

    -- Anders


On Fri, Jan 10, 2014 at 8:00 PM, Eli Zaretskii <eliz@gnu.org> wrote:

> > Date: Fri, 10 Jan 2014 19:52:18 +0100
> > From: Anders Lindgren <andlind@gmail.com>
> > Cc: Stefan Monnier <monnier@iro.umontreal.ca>, 16129@debbugs.gnu.org
> >
> > Concretely, how do we proceed from here? I don't have the necessary
> > knowledge of the internals of the display engine and I don't have much
> time
> > to spend on a major rewrite like this. However, if someone decides to
> > proceed with this, I will try to support them as much that I can.
>
> I suggest to file a separate feature request bug report about this,
> and include in it the requirements for the display engine to support
> follow-mode.  That is, given a set of windows that are "following"
> each other, what should redisplay do when certain display-related
> events happen.  Then interested volunteers can implement that.
>

[-- Attachment #2: Type: text/html, Size: 2311 bytes --]

^ permalink raw reply	[flat|nested] 22+ messages in thread

* bug#16129: 24.3.50; Emacs slow with follow-mode when buffer ends before last window
  2014-01-13 11:41                         ` Anders Lindgren
@ 2014-01-13 14:47                           ` Stefan Monnier
  2014-01-13 16:16                           ` Eli Zaretskii
  1 sibling, 0 replies; 22+ messages in thread
From: Stefan Monnier @ 2014-01-13 14:47 UTC (permalink / raw)
  To: Anders Lindgren; +Cc: 16129

> While I'm at it. I updated to the latest trunk today and saw that cursor
> movements are a lot faster now, including the when the tail is showing.
> However, I noticed that when the region is active, the region highlight is
> not updated as fast as it is when follow-mode is off, when running the
> cursor.

Please make a separate bug-report about this.  The region highlighting
has been moved to Elisp, and it seems that follow-mode's highlighting
code seems to interact poorly with the new behavior.
But the good news is that follow-mode could use the new Elisp
highlighting to "do it right" (no need to use hacks to try and coerce
the redisplay to highlight the region over more than one window).


        Stefan





^ permalink raw reply	[flat|nested] 22+ messages in thread

* bug#16129: 24.3.50; Emacs slow with follow-mode when buffer ends before last window
  2014-01-13 11:41                         ` Anders Lindgren
  2014-01-13 14:47                           ` Stefan Monnier
@ 2014-01-13 16:16                           ` Eli Zaretskii
  2014-01-14 12:34                             ` Anders Lindgren
  1 sibling, 1 reply; 22+ messages in thread
From: Eli Zaretskii @ 2014-01-13 16:16 UTC (permalink / raw)
  To: Anders Lindgren; +Cc: 16129

> Date: Mon, 13 Jan 2014 12:41:14 +0100
> From: Anders Lindgren <andlind@gmail.com>
> Cc: Stefan Monnier <monnier@iro.umontreal.ca>, 16129@debbugs.gnu.org
> 
> Sounds like a good idea to post this feature request. However, being a
> realist, I doubt that this will happen anytime soon.

You mean, the list of requirements, or their implementation?  I hoped
the former should not be too hard to come up with, especially for
someone who is familiar with follow-mode.

> I would suggest that we also post feature requests for things that would
> help the situation on a shorter time scale. Primarily, I would like to be
> able, on a window-by-window basis, control whether or not a window should
> be recentered, when empty.

What should Emacs do instead of recentering a window?

> While I'm at it. I updated to the latest trunk today and saw that cursor
> movements are a lot faster now, including the when the tail is showing.
> However, I noticed that when the region is active, the region highlight is
> not updated as fast as it is when follow-mode is off, when running the
> cursor.

This might be worth a separate bug report (with a recipe, please).





^ permalink raw reply	[flat|nested] 22+ messages in thread

* bug#16129: 24.3.50; Emacs slow with follow-mode when buffer ends before last window
  2014-01-13 16:16                           ` Eli Zaretskii
@ 2014-01-14 12:34                             ` Anders Lindgren
  2014-01-14 16:25                               ` Eli Zaretskii
  0 siblings, 1 reply; 22+ messages in thread
From: Anders Lindgren @ 2014-01-14 12:34 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 16129

[-- Attachment #1: Type: text/plain, Size: 2635 bytes --]

>
> > Sounds like a good idea to post this feature request. However, being a
> > realist, I doubt that this will happen anytime soon.
>
> You mean, the list of requirements, or their implementation?  I hoped
> the former should not be too hard to come up with, especially for
> someone who is familiar with follow-mode.
>

I mean the implementation -- adding this to the display engine is a major
undertaking. If it gets put on hold, or prove more complicated then
anticipated, I think that we can improve the current implementation with a
relatively small effort.

I think that we can come up with a list of requirements relatively easy.
Basically, it is supposed to do whatever Follow mode does today, with a few
exceptions (well, right now I can only think of one):

* It should be applied to all visible windows where Follow mode is active.
(Follow mode today only act upon the selected window -- Mainly for
efficiency reasons.)


> I would suggest that we also post feature requests for things that would
> > help the situation on a shorter time scale. Primarily, I would like to be
> > able, on a window-by-window basis, control whether or not a window should
> > be recentered, when empty.
>
> What should Emacs do instead of recentering a window?
>

It should keep the window empty.

Follow mode tries to create the illusion of a combining several windows
into one very tall window. When the tail of the buffer doesn't reach the
last window(s), for example when you have opened a very small file, follow
mode wants the remaining window(s) to be empty. Today, Emacs prevents this
by recentering them, breaking the illusion. (This, of course, does not
apply to the first window in a sequence of windows, because then you still
want the normal recentering.) Follow mode, today, sets the window-start to
point-max in those windows whenever it has a chance, to prevent the
recentering.

Stefan wrote:
> The region highlighting
> has been moved to Elisp, and it seems that follow-mode's highlighting
> code seems to interact poorly with the new behavior.
> But the good news is that follow-mode could use the new Elisp
> highlighting to "do it right" (no need to use hacks to try and coerce
> the redisplay to highlight the region over more than one window).

I will look into it the first chance I get! Where is the implementation
located, and what interface do I have to make it appear in more than one
window?

The current Follow mode implementation of getting the highlight region into
more than one window stopped working years ago (when Emacs decided that it
should only show the region in the selected window).

    -- Anders

[-- Attachment #2: Type: text/html, Size: 4139 bytes --]

^ permalink raw reply	[flat|nested] 22+ messages in thread

* bug#16129: 24.3.50; Emacs slow with follow-mode when buffer ends before last window
  2014-01-14 12:34                             ` Anders Lindgren
@ 2014-01-14 16:25                               ` Eli Zaretskii
  2014-01-16 12:24                                 ` Anders Lindgren
  0 siblings, 1 reply; 22+ messages in thread
From: Eli Zaretskii @ 2014-01-14 16:25 UTC (permalink / raw)
  To: Anders Lindgren; +Cc: 16129

> Date: Tue, 14 Jan 2014 13:34:23 +0100
> From: Anders Lindgren <andlind@gmail.com>
> Cc: Stefan Monnier <monnier@iro.umontreal.ca>, 16129@debbugs.gnu.org
> 
> I mean the implementation -- adding this to the display engine is a major
> undertaking.

Depending on the requirements, it might not be that major.

> Basically, it is supposed to do whatever Follow mode does today

That is not specific enough, especially if you take into consideration
that I have only a vague idea about what Follow mode does.  Moreover,
I'm not sure we should ask the display engine do everything it does.
For example, selecting the next/previous window when point moves off
the limits of the current window seems to be something that is easy to
do in Lisp.

So please do try to come up with a list of requirements that should be
moved to the display engine.  I guess setting the window start point
when scrolling would be one; what else?

> > I would suggest that we also post feature requests for things that would
> > > help the situation on a shorter time scale. Primarily, I would like to be
> > > able, on a window-by-window basis, control whether or not a window should
> > > be recentered, when empty.
> >
> > What should Emacs do instead of recentering a window?
> >
> 
> It should keep the window empty.

Shouldn't be hard to implement, given some buffer-local variable.





^ permalink raw reply	[flat|nested] 22+ messages in thread

* bug#16129: 24.3.50; Emacs slow with follow-mode when buffer ends before last window
  2014-01-14 16:25                               ` Eli Zaretskii
@ 2014-01-16 12:24                                 ` Anders Lindgren
  2014-01-16 14:42                                   ` Stefan Monnier
  0 siblings, 1 reply; 22+ messages in thread
From: Anders Lindgren @ 2014-01-16 12:24 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 16129

[-- Attachment #1: Type: text/plain, Size: 2455 bytes --]

>
> > Basically, it is supposed to do whatever Follow mode does today
>
> That is not specific enough, especially if you take into consideration
> that I have only a vague idea about what Follow mode does.  Moreover,
> I'm not sure we should ask the display engine do everything it does.
> For example, selecting the next/previous window when point moves off
> the limits of the current window seems to be something that is easy to
> do in Lisp.
>
> So please do try to come up with a list of requirements that should be
> moved to the display engine.  I guess setting the window start point
> when scrolling would be one; what else?
>

You're absolutely correct. Most of Follow mode functions could be kept in
elisp. In fact, most of them are trivial, take scrolling for example, it
simple moves the current window down a suitable amount, and let the
post-command hook take care of the rest.

As a starting point, I would say that it's main responsibility is to keep
the windows aligned, so that one window start where the previous left of.
The second thing it should do is that it should "auto select" other windows
when, for example, the cursor moved down below the end of the window.

In short, do what the post-command-hook does.

I will try to give you a deeper description as soon as I can find some time
to do it.



> > > I would suggest that we also post feature requests for things that
> would
> > > > help the situation on a shorter time scale. Primarily, I would like
> to be
> > > > able, on a window-by-window basis, control whether or not a window
> should
> > > > be recentered, when empty.
> > >
> > > What should Emacs do instead of recentering a window?
> > >
> >
> > It should keep the window empty.
>
> Shouldn't be hard to implement, given some buffer-local variable.
>

Great. I would suggest that it should be implemented so that the actual
test could be written in elisp. In the Follow mode case, the test should be
that the buffer is in Follow mode and that it's not the first window.
However, I could think of other modes -- one example being Two-column mode,
another Scroll all mode -- where this could be useful, but with other
criterias.

In the simplest form it could be a symbol, nil for "no", t for "yes", and
for all other cases call the function it is bound to. Of course, one could
make it into a hook, so that more than one mode could have a say, but I
think that might be overengineering it a bit...

    -- Anders

[-- Attachment #2: Type: text/html, Size: 3277 bytes --]

^ permalink raw reply	[flat|nested] 22+ messages in thread

* bug#16129: 24.3.50; Emacs slow with follow-mode when buffer ends before last window
  2014-01-16 12:24                                 ` Anders Lindgren
@ 2014-01-16 14:42                                   ` Stefan Monnier
  0 siblings, 0 replies; 22+ messages in thread
From: Stefan Monnier @ 2014-01-16 14:42 UTC (permalink / raw)
  To: Anders Lindgren; +Cc: 16129

> Great.  I would suggest that it should be implemented so that the actual
> test could be written in elisp.

Yes, clearly.

> In the Follow mode case, the test should be that the buffer is in
> Follow mode and that it's not the first window.

If we can avoid running Elisp code redisplay, it's always better.
So since the behavior is not the same for all windows of a buffer, maybe
a window-parameter is a better option than a buffer-local value.

> In the simplest form it could be a symbol, nil for "no", t for "yes", and
> for all other cases call the function it is bound to. Of course, one could
> make it into a hook, so that more than one mode could have a say, but I
> think that might be overengineering it a bit...

A single function is sufficient since you can "share" it with
add-function.


        Stefan





^ permalink raw reply	[flat|nested] 22+ messages in thread

end of thread, other threads:[~2014-01-16 14:42 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-12-13 14:34 bug#16129: 24.3.50; Emacs slow with follow-mode when buffer ends before last window Anders Lindgren
2013-12-13 15:32 ` Eli Zaretskii
2013-12-13 15:36   ` Eli Zaretskii
2013-12-13 16:38 ` Stefan Monnier
2013-12-13 17:55   ` Anders Lindgren
2014-01-02 13:55     ` Anders Lindgren
2014-01-02 18:39       ` Anders Lindgren
2014-01-05 23:13         ` Anders Lindgren
2014-01-06  3:45           ` Eli Zaretskii
2014-01-06  8:20             ` Anders Lindgren
2014-01-06 16:33               ` Eli Zaretskii
2014-01-07  8:13                 ` Anders Lindgren
2014-01-10  9:31                   ` Eli Zaretskii
2014-01-10 18:52                     ` Anders Lindgren
2014-01-10 19:00                       ` Eli Zaretskii
2014-01-13 11:41                         ` Anders Lindgren
2014-01-13 14:47                           ` Stefan Monnier
2014-01-13 16:16                           ` Eli Zaretskii
2014-01-14 12:34                             ` Anders Lindgren
2014-01-14 16:25                               ` Eli Zaretskii
2014-01-16 12:24                                 ` Anders Lindgren
2014-01-16 14:42                                   ` Stefan Monnier

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).