Subject: bug#62352: Very slow scroll-down-line with a lot of text properties

From: Herman, Géza <[email-masked]>
Date: Sat, 25 Mar 2023 18:38:19 +0100

On 3/25/23 17:20, Eli Zaretskii wrote:
>> Properties don't appear out of thin air, emacs is the one who puts the
>> properties to characters. So Emacs could build a parallel data structure
>> which contains this information in a better searchable way. This data
>> structure can be lazily constructed/updated, if it's needed.
> It is not easy to maintain such a cache.  It needs to be kept up to
> date at all times, and discarded/recreated when no longer accurate.
> Any Lisp program can in principle add or remove text properties at any
> moment, even inside a hook called by the display engine itself, such
> as fontification-functions.
>
> IOW, it is not as simple as you seem to think.
I didn't meant to imply that it is easy. It is certainly not. But, tbh, 
while emacs is fluid most of the time, it can be very stuttery 
sometimes. In my experience, this is usually caused by some lisp code. 
But when it isn't, it is usually caused by some code in this area. When 
I profile emacs, these functions (next_property_change and similar) are 
usually on the top of the list. So it would make sense to optimize 
around this area. Not just because of this issue, but in general.

I'm not necessarily suggesting a cache. Maybe it's better to actually 
always manage additional data structures. So, if a text property is 
added, it's not just set for the specific character area, but it will 
also modify search structures right away. So additional data structures 
were always in sync. Sure, it has some overhead. But if emacs does a lot 
of linear searches (and having a look at these functions, I see a lot of 
linear searches), this overhead will be quickly mitigated by the much 
faster searches. For example, if emacs had a list which only contained 
text segments with the composition property, the current 500-char area 
search will be much faster.

I'd definitely trade some CPU time in a way that emacs will use some 
more CPU time in general (to manage additional data structures), but it 
will never freeze (because corner cases are handled much better). But 
maybe that's just me, others have different opinions about this.

Anyways, this is not the best place to discuss this, and I also don't 
know too much about emacs's internals. My intuition is that these 
problems can be solved in faster way, that's all.
>> Even, for my example problem, a simple
>> "does-this-buffer-have-any-characters-with-composition-property" would
>> be enough.
> That would be a one-time condition.  It could become false before the
> next redisplay cycle.  And checking this condition even once in a
> large buffer with many text properties takes non-negligible time.

I'm not sure I understand. If a composition text property is added to a 
character, then emacs would increase a buffer-local counter (I mean a 
counter at the C side, not a buffer-local lisp variable). If a 
composition text property is removed from a character, then emacs would 
decrease the buffer-local counter. And of course there are other events 
that modifies the value of the counter (char copy, delete, etc.). So 
this counter would always contain the number of composition characters 
in a buffer, or in other words, whether a buffer has a composition char 
or not. So, if find_composition sees that this counter is zero, it can 
return right away. I'm sure that this extra check won't take any 
significant CPU time. Why wouldn't this work, why does the redisplay 
cycle break this idea?

(I'm not acutally suggesting this idea, of course, because it's just a 
bandaid instead of a proper solution. I'm just asking because I'm 
curious why this wouldn't work)

> There's a performance problem, I agree.  But as long as the design of
> the display engine is what it is, I don't see how that can be helped,
> in a way that will cope much better with the massive amount of face
> properties as in these examples.
Yeah, I understand this. This is what I meant in one of my previous 
comments: if this is a large work, then it makes sense to close this bug 
report, because maybe it's not worth fixing this. Too much work for a 
small gain.

>> This is the file for which emacs freezed
>> for 40 seconds, when I moved the point to the bottom, and pressed and
>> hold Shift-up for 1-2 seconds.
> Here it "freezes" for just 4 to 5 seconds, not 40.
Ok, cool, at least you can reproduce the problem now. I'm not sure what 
causes the large difference (4/5 sec vs. 40 sec). Maybe window size, or 
something else. But it doesn't matter too much. The point is, that for 
some buffers, scroll-down-line can cause some freezing.

(In my real life code, emacs freezes for about a second, so it's not too 
bad. But it's annoying if I hit by this too often, that's why I reported 
this issue)