Neil Hodgson
2014-07-12 06:34:27 UTC
Scintilla uses periodic timers to flash the caret, automatically scroll, widen the scroll bar, and detect that the user has let the mouse sit in one spot.
The original implementation was based on Windows 95 where timers were a rare resource. So a single timer was created for each instance, was used for all timer tasks and was hung onto for Scintilla's whole life. The period was always 100 milliseconds as there didn't seem a need for any more accuracy than that. The caret normally changes state about every half second, a dwell should take that or more, and scrolling 10 lines a second looked OK.
The timer is always active, firing 10 times a second, while the Scintilla instance exists. Only on Cocoa does the timer stop ticking when the application is no longer the active application. It does still tick on Cocoa when the focus is moved to another control in the same application.
Continuously firing uses up power so isn't great on a laptop. There have been bug reports and patches for this but the patches only addressed the caret and not the other uses for timers.
Recent operating system releases have added APIs for timer coalescing which allow applications to specify a tolerance for each timer. The OS then uses this tolerance to try to schedule wake ups to serve more than one application. This can further save power.
Scintilla can be changed to use separate timers for each purpose, turning them on only when needed and setting their period to be the full time until a change is needed. Commonly, the only need for a timer is for the caret to blink once every 500 milliseconds or so and using a 500 millisecond timer instead of a 100 millisecond timer reduces wakes by 80%. When focus moves to another control, the caret blinking timer can be turned off.
Attached is an implementation of this concept that works for the Cocoa and Windows platforms. Each platform needs a small amount of code to enable the fine grained timers. This is currently optional with platforms opting in by implementing the virtual method FineTickerAvailable returning true. On Cocoa and Windows both the new and old techniques still work so experiments can be performed by changing the return value from FineTickerAvailable. Once the feature is working, the old code can be removed from these platforms.
There are other sources of wake ups such as scrolling on Cocoa. With these changes SciTE and ScintillaTest reduced average wake ups per second from 12 to around 4. Here's a (1 MB) screen shot of ScintillaTest being a better citizen while still being active and flashing its caret:
Loading Image...
Qt 5 also has coalescable timers although they only have a fixed 5% tolerance instead of a tolerance setting. GTK+ does not appear to have a similar feature although a quick search found some Linux kernel timers that have a tolerance measured in whole seconds. On Cocoa and Windows, the coalescable timer APIs are not supported on previous releases so the code has to check for the feature and fall back to non-coalescable timers.
While testing on Cocoa, a bug was found - Scintilla was not sending dwell events except when it had focus. The tracking rect used before was changed to the more recent tracking area API (10.5+) which fixed this.
This code is tricker with various conditions controlling when the timers are turned on or off so is more likely to have bugs then the old approach.
Neil
The original implementation was based on Windows 95 where timers were a rare resource. So a single timer was created for each instance, was used for all timer tasks and was hung onto for Scintilla's whole life. The period was always 100 milliseconds as there didn't seem a need for any more accuracy than that. The caret normally changes state about every half second, a dwell should take that or more, and scrolling 10 lines a second looked OK.
The timer is always active, firing 10 times a second, while the Scintilla instance exists. Only on Cocoa does the timer stop ticking when the application is no longer the active application. It does still tick on Cocoa when the focus is moved to another control in the same application.
Continuously firing uses up power so isn't great on a laptop. There have been bug reports and patches for this but the patches only addressed the caret and not the other uses for timers.
Recent operating system releases have added APIs for timer coalescing which allow applications to specify a tolerance for each timer. The OS then uses this tolerance to try to schedule wake ups to serve more than one application. This can further save power.
Scintilla can be changed to use separate timers for each purpose, turning them on only when needed and setting their period to be the full time until a change is needed. Commonly, the only need for a timer is for the caret to blink once every 500 milliseconds or so and using a 500 millisecond timer instead of a 100 millisecond timer reduces wakes by 80%. When focus moves to another control, the caret blinking timer can be turned off.
Attached is an implementation of this concept that works for the Cocoa and Windows platforms. Each platform needs a small amount of code to enable the fine grained timers. This is currently optional with platforms opting in by implementing the virtual method FineTickerAvailable returning true. On Cocoa and Windows both the new and old techniques still work so experiments can be performed by changing the return value from FineTickerAvailable. Once the feature is working, the old code can be removed from these platforms.
There are other sources of wake ups such as scrolling on Cocoa. With these changes SciTE and ScintillaTest reduced average wake ups per second from 12 to around 4. Here's a (1 MB) screen shot of ScintillaTest being a better citizen while still being active and flashing its caret:
Loading Image...
Qt 5 also has coalescable timers although they only have a fixed 5% tolerance instead of a tolerance setting. GTK+ does not appear to have a similar feature although a quick search found some Linux kernel timers that have a tolerance measured in whole seconds. On Cocoa and Windows, the coalescable timer APIs are not supported on previous releases so the code has to check for the feature and fall back to non-coalescable timers.
While testing on Cocoa, a bug was found - Scintilla was not sending dwell events except when it had focus. The tracking rect used before was changed to the more recent tracking area API (10.5+) which fixed this.
This code is tricker with various conditions controlling when the timers are turned on or off so is more likely to have bugs then the old approach.
Neil
--
You received this message because you are subscribed to the Google Groups "scintilla-interest" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scintilla-interest+***@googlegroups.com.
To post to this group, send email to scintilla-***@googlegroups.com.
Visit this group at http://groups.google.com/group/scintilla-interest.
For more options, visit https://groups.google.com/d/optout.
You received this message because you are subscribed to the Google Groups "scintilla-interest" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scintilla-interest+***@googlegroups.com.
To post to this group, send email to scintilla-***@googlegroups.com.
Visit this group at http://groups.google.com/group/scintilla-interest.
For more options, visit https://groups.google.com/d/optout.