#1299 Idle wrapping too aggressive on Windows platform

Scintilla (792)

Working on a larger file (10MB, half million lines) in Scintilla with word wrap enabled on Windows platform is almost impossible. If you try to write something at the beginning of the file, there will be a considerable lag between typing and actual modification being shown on screen. At first I thought that this is a general Scintilla limitation considering the size of file, however I tested the same file in Scintilla running on Linux under virtual machine and general experience was much better to the point that you could actually work on the file in question.

That made me look at the source code and while comparing how idle processing is implemented on different platforms, it became clear that on Windows it is simply too aggressive. On GTK and OSX, Editor::Idle() is being called only once on regular intervals, while on Windows once idling has started, it won't stop until finishing completely as message queue will get quickly saturated with idle messages. I did not look far back if there is an actual reason why idle messages are constantly being resent on Windows implementation instead of triggering only once on set timer intervals. As a result, I simply changed the timing values so that idle processing is more similar to the two other platforms and so it doesn't hog the message loop. Besides making word wrap actually usable on larger files the patch will approximately halve the CPU utilization, at the expense of needing more time to process everything obviously, but still processing everything faster than other two platforms due to repeated idle messages. You can try it for yourself on a larger file (10MB+) and see the difference in response time when typing before and after the patch (also compare word wrap between platforms to see the difference). The patch also fixes Editor::MovePositionTo() so it works properly on a line that has not yet been processed by wrapping.


  • Neil Hodgson

    Neil Hodgson - 2012-02-13
    • assigned_to: nobody --> nyamatongwe
  • Neil Hodgson

    Neil Hodgson - 2012-02-13

    Idle messages aren't supposed to saturate the message queue. It'd be an idea to look back and see if/when this changed.

  • Marko Njezic

    Marko Njezic - 2012-02-14

    After looking a little deeper at the history, it appears that idle wrapping on Windows has been flawed since its introduction. And from that I can only assume that it actually hasn't been even tested on larger files so far.

    More precisely, three initial commits that implemented idle wrapping of Windows have progressively made things worse.

    1. Change set 1712. Initial work that calls Idle() every 20ms by relying on WM_TIMER message.
    2. Change set 1713. Delay between Idle() calls shortened to 10ms (actually minimum allowed timer value on Windows), thus increasing the load, but still bearable.
    3. Change set 1715. This change has basically converted idle operation to operation with high priority by posting insane amount of messages in short period of time with almost no stops. It relies only on the fact that posted messages are added to a queue and processed after other messages, but depending on document size the amount of posted idle messages can saturate message queue. This code should have been written differently, so it actually pause certain amount of time between posting idle messages and also lowering the limit of maximum time it will take priority over other messages to a value much lower than 200ms.

    On a file that I have been trying to edit, each modification at the start of document causes almost four thousand idle messages to be posted in very short amount of time. I did not debug further how many of them have been waiting in the queue, but I guess that depending on document size you'll eventually end up with no spare room in posted messages queue (there's a default limit of 10000 messages per queue).

    Judging from all this I can only conclude that idle support should be completely rewritten on Windows in order to be truly low priority, but I won't be spending my time on this. Therefore, the only sensible modification for the time being is to change timing values like I did in my patch that's attached. It changes initial idle timer trigger message to fire on default tickSize value and limits maximum time spent by further idle messages to half the size of tickSize in order to reduce hot stops generated by huge amount of posted messages in short time without delay in between. Further tweaks are still possible, but I'm leaving that to someone else.

  • Neil Hodgson

    Neil Hodgson - 2012-02-15

    How are you determining that there are large numbers of idle messages in the queue? I added a variable to count the idle messages in flight and only ever see a maximum of 1. The intent of the code was to only have 1 idle message in the queue at a time.

  • Marko Njezic

    Marko Njezic - 2012-02-15

    In previous message I have mentioned that I did not debug if there have been some idle messages that were left waiting, since the primary issue I was concentrating on is the huge amount of idle messages generated consecutively in very short amount of time without any delay in between (4K messages in less than 1sec in my case). Current code implements “idling” like this: initial WM_TIMER trigger message is being fired each 10ms, once initial SC_WIN_IDLE message is sent, the next 200ms of time in message loop will be almost completely occupied with consecutively posted SC_WIN_IDLE messages without any delay. After that there is a short window of 10ms or less before new trigger message is sent, starting the occupation once again. Even with provisional code that aborts this on user input, allocated 200ms for idle work is a very long period of time, which is responsible for higher CPU utilization and the lack of visual updates since WM_PAINT messages are lower priority (they are only above WM_TIMER, which is last). In its current state background idling on Windows is not very different than calling WrapLines(true, -1) right from the start instead. Short of implementing true idle functionality by performing it in a separate thread, only way to make work on larger files with word wrap enabled even possible is to reduce timing values and make them less aggressive, so they don’t hog the main execution thread. In addition to reducing timing values, adding a delay between SC_WIN_IDLE messages will also help greatly.

    All this talk aside, if you haven’t done this so far, compare how idle wrapping behaves with large files on Windows vs. Linux (GTK) and you’ll see that it is rather frustrating trying to type anything on Windows.

  • Neil Hodgson

    Neil Hodgson - 2012-02-16

    A problem with this patch is that it halves the amount of processing done in idle. Most of the advantage of the patch appears to be from reducing the lag from 200 to 50 milliseconds. While allowing through more messages would be useful, reducing the speed of idle tasks to half appears to be too much to me.

  • Marko Njezic

    Marko Njezic - 2012-02-16

    You should at least apply the changes to the Editor.cxx from the patch, as they fix bug in MovePositionTo() so it works properly on a line that has not yet been processed by wrapping and make EnsureLineVisible() only call full wrap if line has not been processed.

    The timing issue should probably be left open until a proper idling solution is found. A short term solution may be to add an option, which will control the amount of time idle can spend sending messages consecutively, so that container can change it depending on the size of loaded document. Or Scintilla could change those 200ms automatically depending on the document size.

  • Neil Hodgson

    Neil Hodgson - 2012-02-18

    Merged in the wrap for MovePositionTo.

    Decreased idle processing before allowing paint from 200 to 50 milliseconds.

  • Neil Hodgson

    Neil Hodgson - 2012-02-18
    • priority: 5 --> 3
    • milestone: --> Bug
    • status: open --> open-accepted

Get latest updates about Open Source Projects, Conferences and News.

Sign up for the SourceForge newsletter:

No, thanks