Subject: bug#15876: 24.3.50; Highly degraded performance between rev 114715 and 115006

From: Eli Zaretskii <[email-masked]>
Date: Sun, 01 Dec 2013 18:31:51 +0200

> From: "Sebastien Vauban" <[email-masked]>
> Cc: [email-masked]
> Date: Fri, 29 Nov 2013 22:01:10 +0100
> 
> Eli Zaretskii wrote:
> >> From: "Sebastien Vauban" <[email-masked]>
> >> Cc: [email-masked]
> >> Date: Tue, 26 Nov 2013 21:52:05 +0100
> >> 
> >> > So what is the minimum .emacs that will cause the problem?
> >> 
> >> That does it:
> >> 
> >> --8<---------------cut here---------------start------------->8---
> >> ;; highlight trailing whitespaces in all modes
> >> (setq-default show-trailing-whitespace t)
> >> 
> >> (setq org-ellipsis " \u25B7")           ; string
> >> --8<---------------cut here---------------end--------------->8---
> >
> > And this makes Emacs slow in scrolling for any file you visit?  Or
> > just in Org buffers?
> 
> No problem, with the same files, if I put them in `text-mode'. So, it becomes
> apparent with Org.
> 
> Remember I told there were similar speed problems with some Gnus buffer, but I
> haven't tested them again.
> 
> > If the latter, perhaps your Org files are special in some way, because
> > the ones I tried don't show any slowdown I could sense.
> 
> They aren't special, for two reasons:
> 
> - They're not mine; they're public Org files taken from the Worg project ("Wiki
>   Org").
> 
> - They work perfectly in Emacs rev 114715: no performance degradation
>   whatsoever.
> 
> For the sake of clarity, I've redone a comparison of the two different Emacs
> (r114715 and the recent r115235) on the same two Org files:
> 
> - ChangeLog.org (1,156 bytes)
>   http://code.ohloh.net/file?fid=s6NzuuiKK0Nlga9EF-Vh8KzVXiw&cid=SNfK_pTfQmo&s=&fp=19410&mp=&projSelected=true#L0
> 
> - org-faq.org (164,174 bytes)
>   http://code.ohloh.net/file?fid=Jk4U4mwQtJT_5LfYpl3sBLhj42s&cid=SNfK_pTfQmo&s=&fp=19410&mp=&projSelected=true#L0

I looked at this issue.

It has nothing to do with org-ellipsis, or the Org mode in general.
To reproduce it, it's enough to do just this:

  emacs -Q
  C-x 8 RET 25b7 RET

Now try moving the cursor across the line that displays the triangle
character u+25B7.  If you are on Windows 7, this will use the
BatangChe font for the triangle, and every redisplay operation, even
cursor motion, will be extremely slow.  (On XP, this font is not
installed, and even if I install it, I'm unable to trigger the same
problem, for some reason.)

This slowdown seems to be caused by this commit:

  revno: 114735
  committer: Dmitry Antipov <[email-masked]>
  branch nick: trunk
  timestamp: Mon 2013-10-21 14:11:25 +0000
  message:
    Do not allow font caches to grow too large.
    * alloc.c (compact_font_cache_entry, compact_font_caches):
    New functions or stub if not HAVE_WINDOW_SYSTEM.
    (compact_undo_list): Factor out from Fgarbage_collect.
    Add comment.
    (mark_face_cache): Mark face font.  Move down to avoid
    extra prototypes.
    (mark_terminals): Do not mark font cache here.
    (Fgarbage_collect): Call compaction functions described
    above.  Adjust comment.

What happens is that the above-mentioned font causes a lot of consing,
when loaded (perhaps because it supports many different Unicode
blocks).  That triggers GC immediately after redisplay; GC calls
compact_font_caches, which for some reason decides that the font-specs
in the font cache can be removed.  Then the next redisplay needs the
deleted font again, so it again loads it, which causes consing, which
triggers GC, etc. etc.

If I disable the compacting, like this:

  static void
  compact_font_caches (void)
  {
    struct terminal *t;

    for (t = terminal_list; t; t = t->next_terminal)
      {
	Lisp_Object cache = TERMINAL_FONT_CACHE (t);

  #if 0
	if (CONSP (cache))
	  {
	    Lisp_Object entry;

	    for (entry = XCDR (cache); CONSP (entry); entry = XCDR (entry))
	      XSETCAR (entry, compact_font_cache_entry (XCAR (entry)));
	  }
  #endif
	mark_object (cache);
      }
  }

then the problem goes away.

Dmitry, can you please look into this?  I'm not familiar enough with
the font stuff, so I don't see how was the font-spec and its
font-entities stored in the font cache supposed to be referenced from
some other Lisp object, to make sure they are marked and not GC'ed.
In any case, it seems like they are never marked on Windows, because
if I set a breakpoint in the line marked below:

	  /* If font-spec is not marked, most likely all font-entities
	     are not marked too.  But we must be sure that nothing is
	     marked within OBJ before we really drop it.  */
	  for (i = 0; i < size; i++)
	    if (VECTOR_MARKED_P (XFONT_ENTITY (AREF (XCDR (obj), i))))
	      break;

	  if (i == size)  <<<<<<<<<<<<<<<<<<<<<
	    drop = 1;
	}

with a condition i != size, that breakpoint never breaks.  If you see
something different on X, please tell which code is responsible for
marking those font-entities and/or the font-spec's in the font cache.
(I guess you meant mark_face_cache to do that, but it marks fonts, not
font-entities or font-spec's.)