Discussion:
Fine control over timer ticking
Neil Hodgson
2014-07-12 06:34:27 UTC
Permalink
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
--
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.
Mike Lischke
2014-07-12 09:30:50 UTC
Permalink
Hey Neil,
Post by Neil Hodgson
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.
Is this supported on other OSes than Mavericks and up?
Post by Neil Hodgson
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.
This sounds like a sensible optimization. Would be interesting what real effect this has on the runtime of a laptop, say, with an app having multiple scintilla windows.
Post by Neil Hodgson
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.
Btw, do you use real tabs in your code? The patch looks a bit messed up. It starts with nice indentation:



then changes to much larger indentation:



and finally goes havoc:



Better don't use tabs at all.
Post by Neil Hodgson
http://scintilla.org/WellBehaved.png
That sounds like a nice achievement, but still I'm unsure how much real life impact this has. There won't be many instances of Scintilla in an application (if there are 20 then it's already a high number). But on the other hand it's like an entry to newer OS features with the option to remove outdated stuff later when older OSes are no longer supported.
Post by Neil Hodgson
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.
Should it send dwell events also if it doesn't have focus? That would mean you get, e.g. tooltips while a different window is the active one. Sounds not right to me. IMO all mouse interaction should stop if scintilla lost focus.

Mike
--
www.soft-gems.net
--
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.
Colomban Wendling
2014-07-12 12:25:04 UTC
Permalink
Post by Mike Lischke
Post by Neil Hodgson
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.
This sounds like a sensible optimization. Would be interesting what real
effect this has on the runtime of a laptop, say, with an app having
multiple scintilla windows.
Indeed, yet I would imagine it can be non-negligible on an otherwise
idle machine :)
Post by Mike Lischke
Post by Neil Hodgson
[...]
Btw, do you use real tabs in your code? The patch looks a bit messed up.
Better don't use tabs at all.
Looks like a nice troll :)
That patch looks fine when using a tab width of 4, which is what
Scintilla always used.
Post by Mike Lischke
Post by Neil Hodgson
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
http://scintilla.org/WellBehaved.png
That sounds like a nice achievement, but still I'm unsure how much real
life impact this has. There won't be many instances of Scintilla in an
application (if there are 20 then it's already a high number).
This depends on how applications are written, but if it uses one
Scintilla instance per open document, there can easily be more, and it
only depends on how many documents the user opens. So if Scintilla
could not use any resources when not the focused widget it would be
awesome for such apps and their users.
Post by Mike Lischke
Post by Neil Hodgson
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.
Should it send dwell events also if it doesn't have focus? That would
mean you get, e.g. tooltips while a different window is the active one.
Sounds not right to me. IMO all mouse interaction should stop if
scintilla lost focus.
That may (or may not) be a platform consistency issue. On Linux
platforms, applications are expected to respond to events either being
the active window or not -- if they get an event, thy are supposed to
handle it. BTW, if really the platform didn't want the unfocused
application to handle any input events, it could prevent even sending
them to the application.
But I guess that Scintilla should follow the common practice on the
platform, maybe unless it makes the code a lot more complex.

Regards,
Colomban
--
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.
Neil Hodgson
2014-07-12 13:11:34 UTC
Permalink
Post by Mike Lischke
Is this supported on other OSes than Mavericks and up?
This form of timer coalescing works on Mavericks and up although I haven't checked on Yosemite. For Windows, it works on 8 or later and its been checked on 8.1 and 7 where it falls back to non-coalescing.
Post by Mike Lischke
Btw, do you use real tabs in your code? The patch looks a bit messed up. It starts with nice indentation:\
Yes, all the files I originated use tabs which is how I have Xcode set up. Then I edit one of the files in the Cocoa directory which uses spaces (and is indented all wrong) so it gets messed up.
Post by Mike Lischke
That sounds like a nice achievement, but still I'm unsure how much real life impact this has.
Real world testing would take a long time to run the machine down to zero - the GUI showing the battery percentage can't really be trusted.
Post by Mike Lischke
There won't be many instances of Scintilla in an application (if there are 20 then it's already a high number). But on the other hand it's like an entry to newer OS features with the option to remove outdated stuff later when older OSes are no longer supported.
Its quite reasonable to support timer coalescing just on the versions of OS X where it works with a runtime check for the feature:

if (tolerance && [fineTimer respondsToSelector: @selector(setTolerance:)])
{
[fineTimer setTolerance: tolerance / 1000.0];
}

-- Just checked this and had to change it from the published patch - on 10.7 it didn't like fineTimer.tolerance = ...
There is still a warning building on 10.7 that setTolerance: isn't declared. It builds and runs, sees that the timer can't respond to setTolerance so doesn't call it.

One question here is what to set the tolerance to - its currently using 10% but a higher value may be fine. Its likely that the foreground application is given more of a say in where the wake up will occur with background applications being harmonised to it. Watching the Energy Impact page in the debugger when the Scintilla app is in the background or (even better) hidden shows it receiving less regular wake ups particularly once it goes into 'nap' mode.
Post by Mike Lischke
Should it send dwell events also if it doesn't have focus? That would mean you get, e.g. tooltips while a different window is the active one. Sounds not right to me. IMO all mouse interaction should stop if scintilla lost focus.
One of the main purposes of dwell events was value tips in debuggers where you move the cursor over a variable and leave it there a little and the value appears in a small window. You may have the focus in a different pane where you are changing a setting or using cursor keys to expand and look inside other variables.

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.
Mike Lischke
2014-07-12 14:20:02 UTC
Permalink
Post by Neil Hodgson
Post by Mike Lischke
Is this supported on other OSes than Mavericks and up?
This form of timer coalescing works on Mavericks and up although I haven't checked on Yosemite. For Windows, it works on 8 or later and its been checked on 8.1 and 7 where it falls back to non-coalescing.
Interesting, didn't know Windows supports timer coalescing.
Post by Neil Hodgson
Post by Mike Lischke
Btw, do you use real tabs in your code? The patch looks a bit messed up. It starts with nice indentation:\
Yes, all the files I originated use tabs which is how I have Xcode set up. Then I edit one of the files in the Cocoa directory which uses spaces (and is indented all wrong) so it gets messed up.
The problem with using tabs is that it shows fine only if any viewer of your code uses the same setting as you. Often however we don't want that or we can't even change them (e.g. in OSX quick view, in diff tools, CMS tools etc.). I certainly don't want to change my tab/space settings every I work with a different project (even if I could).
Post by Neil Hodgson
Post by Mike Lischke
Should it send dwell events also if it doesn't have focus? That would mean you get, e.g. tooltips while a different window is the active one. Sounds not right to me. IMO all mouse interaction should stop if scintilla lost focus.
One of the main purposes of dwell events was value tips in debuggers where you move the cursor over a variable and leave it there a little and the value appears in a small window. You may have the focus in a different pane where you are changing a setting or using cursor keys to expand and look inside other variables.
That's a very good point, however applies only to the same app. If you switch to a different app then there should be no action on mouse hovering over the inactive app.

Mike
--
www.soft-gems.net
--
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.
Neil Hodgson
2014-07-12 23:43:34 UTC
Permalink
Post by Mike Lischke
Interesting, didn't know Windows supports timer coalescing.
Its not clear but it looks to me as though Intel has been driving this to try to get their power use down to ARM levels before ARM gets their speed up to near-Intel levels.

This is a good example of how Apple gets developers to follow its program: first a mention in a keynote and some more detailed conference sessions and papers, then a page in the debugger making the issue visible in a way that is easy to understand and change. There may be something similar in Visual Studio or a related download but I'm not aware of it and I use Visual Studio much more often than Xcode.

For Linux, the only tool I'm aware of is PowerTOP which shows about 12 events per second when SciTE is foreground with no user activity.
Post by Mike Lischke
The problem with using tabs is that it shows fine only if any viewer of your code uses the same setting as you.
The tab versus space war has been going on for many years and I'm not expecting to declare victory any time soon.
Post by Mike Lischke
That's a very good point, however applies only to the same app. If you switch to a different app then there should be no action on mouse hovering over the inactive app.
Yes, its the multiple controls/panes in a single application situation that warrants the change. Multiple application scenarios could go either way - I could see debugging situations where you want to examine values without switching focus to the debugger.

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.
Neil Hodgson
2014-07-13 13:13:25 UTC
Permalink
There are now simple, non-coalescing implementations for GTK+ and Qt. Attached is an updated patch for all 4 standard platforms.

The GTK+ and Qt code includes some commented out tracing: uncomment the prntimers calls to see tracing to stderr with "C S W D" showing that the Caret, Scroll, Widen, or Dwell timer is running with '_' when each is off. This can be useful to check that the timers appear and disappear when required.

Unless someone tells me there is a problem with this approach it will be committed in about a day. The support for the old shared timer will be removed from each platform before committal although the Editor class will still work with other platform layers that use a shared timer.

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.
Neil Hodgson
2014-07-15 02:36:40 UTC
Permalink
This feature has been committed as
https://sourceforge.net/p/scintilla/code/ci/62e0d5bac1dd4954d4c633f6e424f09bb8ce65a1/

While platform layers distributed separately from Scintilla can continue working with a global 100 millisecond timer, there are strong benefits from implementing separate timers. Its not much work, and there are 4 examples in that change set.

Since this change turns timers on and off in several places, there could be bugs in both directions. Features may be inactive when their timer is not turned on (which is easy to spot) or extra power may be used when a timer is running without need. One problem that occurred during testing was for dragging text into Scintilla from another application, which showed the caret and turned the caret timer on, then pressing Esc to stop the drag. Scintilla didn't turn the caret timer off so continued to have too many wake ups even though it didn't have focus.

The change using a tracking area instead of a tracking rectangle on Cocoa for dwell events without focus is independent so was committed as
https://sourceforge.net/p/scintilla/code/ci/6deaf5b9c8d98725caf35710861711f3a69bc821/

Available from the Mercurial repositories:
hg clone http://hg.code.sf.net/p/scintilla/code scintilla
hg clone http://hg.code.sf.net/p/scintilla/scite
and from
http://www.scintilla.org/scite.zip Source
http://www.scintilla.org/wscite.zip Windows executable

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.
Philippe Lhoste
2014-07-15 09:24:37 UTC
Permalink
Post by Mike Lischke
Better don't use tabs at all.
The problem is more with the tools not handling tabs correctly (or with not using the
right tools) rather than with the tabs themselves...

Not to start (again) a tabs vs. spaces war, but stating that a coding choice should be
changed because your tools doesn't handle correctly something that exists almost since
computing exists is a bit rude. :-)
--
Philippe Lhoste
-- (near) Paris -- France
-- http://Phi.Lho.free.fr
-- -- -- -- -- -- -- -- -- -- -- -- -- --
--
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.
Mike Lischke
2014-07-15 09:32:52 UTC
Permalink
Post by Mike Lischke
Better don't use tabs at all.
The problem is more with the tools not handling tabs correctly (or with not using the right tools) rather than with the tabs themselves...
Not to start (again) a tabs vs. spaces war, but stating that a coding choice should be changed because your tools doesn't handle correctly something that exists almost since computing exists is a bit rude. :-)
I'm sorry if you (or anybody) feels like that for such a trivial suggestion or tip/wish (you name it). Believe me, it's not only about me or my tools. I'm only a bit surprised we need to discuss this yet in 2014 as the disadvantage of tabs have been proven many times. But anyway, feel free to ignore my throw-in. It was just meant to signal that not everybody is happy with the current state.

Mike
--
www.soft-gems.net
--
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.
Nicholai Benalal
2014-07-15 12:17:32 UTC
Permalink
Post by Mike Lischke
'm only a bit surprised we need to discuss this yet in 2014 as the disadvantage of tabs have been proven many times.
The advantages are also easy to see and that's why many people prefer to use tabs in one form or another. There is definitely no consensus on tabs vs spaces so I find it quite surprising that someone finds it appropriate to start up such a discussion here.
--
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.
Colomban Wendling
2014-07-12 12:31:00 UTC
Permalink
[...] 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.
GTK+ has g_timeout_add() and g_timeout_add_seconds() [1], the second
having a granularity to the second. This may not be interesting enough
though, as a whole second is probably too long for Scintilla's uses.

[1]
https://developer.gnome.org/glib/unstable/glib-The-Main-Event-Loop.html#g-timeout-add-seconds-full
--
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.
Matthew Brush
2014-07-12 20:29:05 UTC
Permalink
Post by Colomban Wendling
[...] 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.
GTK+ has g_timeout_add() and g_timeout_add_seconds() [1], the second
having a granularity to the second. This may not be interesting enough
though, as a whole second is probably too long for Scintilla's uses.
[1]
https://developer.gnome.org/glib/unstable/glib-The-Main-Event-Loop.html#g-timeout-add-seconds-full
Also if motivated enough, I think you could use Linux's timerfd[1]
together with GLib's GSource[2]/IO Channels[3] mechanism for mainloop
integration.

Cheers,
Matthew Brush

[1]: http://man7.org/linux/man-pages/man2/timerfd_create.2.html
[2]:
https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#GSource
[3]: https://developer.gnome.org/glib/stable/glib-IO-Channels.html
--
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.
Neil Hodgson
2014-07-12 23:42:18 UTC
Permalink
Also if motivated enough, I think you could use Linux's timerfd[1] together with GLib's GSource[2]/IO Channels[3] mechanism for mainloop integration.
I will write a basic implementation without coalescing for GTK+ if no one else gets there first.

Its likely that glib will gain coalescing timers as various parts of the Linux community are working on tablets and laptops and want to be competitive with OS X and Windows.

If/when glib has simple coalescing timers I'll implement them but otherwise I'll leave it to a 'sufficiently motivated' person to look into timerfd.

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.
Loading...