Subject: Re: bug#14616: 24.3.50; Excessive cursor movement on non-X Emacs

From: Eli Zaretskii <[email-masked]>
Date: Fri, 02 Aug 2013 17:28:09 +0300

> From: Lars Magne Ingebrigtsen <[email-masked]>
> Cc: [email-masked]
> Date: Fri, 02 Aug 2013 15:46:23 +0200
> 
> While this is going on, I can't see anything visibly changing in Emacs.
> 
> Looking at the lines included below, I see lots of clear_to_end_of_line
> and cursor_to...  and write_glyphs...

clear_to_end_of_line is not the problem, because it actually does
nothing:

  #0  clear_end_of_line (f=0xb7fbe0, first_unused_hpos=80) at terminal.c:153

The last argument is 80, i.e. the position beyond the end of the line.
In this case, clear_end_of_line (more accurately, its TTY
implementation) returns immediately without writing anything to the
screen.

The real problem is the series of calls to write_glyphs, with ever
increasing numbers of screen lines (the vpos argument of
update_frame_line):

  #0  write_glyphs (f=0xb7fbe0, string=0x145e6f0, len=63) at terminal.c:163
  #1  0x0000000000415639 in update_frame_line (f=f@entry=0xb7fbe0, 
      vpos=vpos@entry=0) at dispnew.c:4816
  ...
  #0  write_glyphs (f=0xb7fbe0, string=0x145f5f0, len=80) at terminal.c:163
  #1  0x0000000000415639 in update_frame_line (f=f@entry=0xb7fbe0, 
      vpos=vpos@entry=1) at dispnew.c:4816
  ...
  #0  write_glyphs (f=0xb7fbe0, string=0x14604f0, len=66) at terminal.c:163
  #1  0x0000000000415639 in update_frame_line (f=f@entry=0xb7fbe0, 
      vpos=vpos@entry=2) at dispnew.c:4816

etc.  Can you throw together a test case that causes this part and
doesn't require to have Gnus set up, i.e. which I could try from
"emacs -Q"?

These calls come from line 4816 of dispnew.c, in this snippet:

  /* If display line has unknown contents, write the whole line.  */
  if (must_write_whole_line_p)
    {
      /* Ignore spaces at the end, if we can.  */
      if (!write_spaces_p)
	while (nlen > 0 && CHAR_GLYPH_SPACE_P (nbody[nlen - 1]))
	  --nlen;

      /* Write the contents of the desired line.  */
      if (nlen)
	{
          cursor_to (f, vpos, 0);
	  write_glyphs (f, nbody, nlen);  <<<<<<<<<<<<<<<<<<<<<
	}

The fact that must_write_whole_line_p is non-zero is the key: it means
that Emacs believes the screen lines in the 'current' glyph matrix are
invalid.  The question is: who and why invalidates them?  One way to
find out is to put a watchpoint on the enabled_p flag of some screen
line, and see which code changes it.  Something like this:

 (gdb) watch -l current_row->enabled_p
 (gdb) commands
   > bt 10
   > continue
   > end

You must set the watchpoint when you are in the above code snippet, so
begin by setting a breakpoint on the line marked above that calls
write_glyphs; when that breakpoint breaks, set the watchpoint as
above, and then delete or disable the breakpoint.  Then let Emacs do
what you did here, and see which code resets the enabled_p flags.

Also, I see that this is an optimized build.  Could you please try all
that in an unoptimized build, so that I could trust the backtraces and
the values of variables 100%?

Thanks.