Running out of Windows timers

Hi all,

I am facing a weird one. Everything has been working well. Complex UI, lots of controls,…

The number of controls being displayed at any one time increases with the amount of data being handled.

On Mac no issues. On Windows, everything works well up to a certain size of data set. Above a certain size, things go wrong.

Essentially, all Timer controls stop working.

Plus, in the debugger, I also get weird ‘Ignore’/‘Report’ dialog. When these occur the code is always pointing at an issue with a Timer control: the IDE stops on a line that typically will say ‘someTimer.Mode = something’.

After a bit of research I found that on Windows system timers are a limited resource, and my suspicion was that I was a bit too liberal and used too many of them, as Xojo timers probably map onto Windows system timers.

I had originally attached a timer for debouncing to each a whole range of composite controls, and I was using 100s if not 1000s of timers like there was no tomorrow.

As I don’t need accurate timing (it’s mostly debouncing stuff), I cleaned things up, and reduced my ‘timer footprint’ to just one single Xojo Timer.

It gets created on startup, starts ticking and replaces the 1000s of timers. I have this timer on ModeMultiple, and have it fire regularly, and I do all my debouncing with just the one timer.

The strange thing is: the issue did not disappear. I am still getting ‘Ignore’/‘Report’ dialogs when I use statements like ‘myOnlyTimer.Mode = 2’.

The things I do know:

  • It is Windows-only
  • It’s related to the size of the task. Beyond a certain size things start breaking
  • It is related to timers

at a certain point, any and all timers stop working. In my latest test, my one and only timer stops working.

So, my theory is that something else, hidden inside, might be leaking timers.

Anyone experience something like that?

I haven’t seen this - and wouldn’t have. Have you tried a 64bit version?

Whats a task?

And does any code in the timer event cause a new timer/thread to start?
Is the code recursive, essentially?

Such things as long tasks monopolizing an event do indeed stop timers. Too many timers with in each too much stuff can also do it. Timers essentially fire when they can, and cannot fire while an event code is executing.

Tight loops are a poison for timers.

Apart from that, there is not enough info to suggest more.

Did you quit Xojo, clear its cache and re-run Xojo ?

True. Make sure the code is the action-event of the timer is just short and quick. For longer processes to be initiated by a timer, I would add it to a queue, and create a sort of taskmanager to run the code.
A while ago I did some testing with a lot of dynamic created timers, just to show what’s happening when you have too many.

Timers on windows where the action event ends up being longer than the period causes the event scheduler to stop working. Mac is all ok. I haven’t tried 64 bit builds on Windows though. It’s been like this for a few years.

One way is to refactor the timer into a thread. Something like this:
Thread.run Event

dim start as new  date
dim now as new date
dim schedule as double = 10 // 10 seconds
while not me.cancelled
  if now.totalseconds>me.nextrun then
     RUNLONGCODEMETHOD
     now = new date
     me.nextrun=now.TotalSeconds+schedule
  end if
  me.sleep(100)
wend

You could move the now=new date to before the RUNLONGCODEMETHOD if you wanted the schedule to be as close to 10 seconds as possible. The current code runs 10 seconds after the last time it finished.

Another way is in the Timer.Action Event

me.mode=0 RUNLONGCODEMETHOD me.mode=2

In GUI apps I’ve mostly used the second method, console/web apps the first.

Feedback case from 2014…
<https://xojo.com/issue/32275>

Lee

Indeed, the Action event of a timer blocks other timers just the same as any other event. So any task that takes a long time should be moved to a thread, and the timer simply starts the thread.

Also, one has to remember that the timer Action event itself blocks other timers from firing. So pass a certain number of timers, each with a relatively long task, they will not be able to fire.

Joost idea of queing tasks is probably the best one to minimize the number of timers.

[quote=297926:@Lee Badham]Another way is in the Timer.Action Event

me.mode=0 RUNLONGCODEMETHOD me.mode=2

In GUI apps I’ve mostly used the second method, console/web apps the first.[/quote]
I also use this mechanism on Linux tools. It has solved a lot of explainable hangs when a lot of timers are firing.

It looks like feedback case 32275 was closed because it was not reproducible.

Could I ask someone to make a simple example that is reproducible (where it fails on Windows and works on OSX), and post it here for others to try?

If we are able to replicate this issue, then a new feedback case should be opened or 32275 reopened.

Most important is to warn against using timers like confetti at a bridal party.

I filed bug report 45829 with a repeatable sample that can be run from the IDE.

It is related to the number of controls in the window.

The sample has one single Timer control which is initially not touched.

There is a ‘set up’ phase during which I create heaps of controls, but no Timer is used or touched. Then there is a ‘demonstrate the bug’ phase, where clicking a button tries to arm that single timer control.

Below a certain limit all works as expected: a few 100s of controls are created during setup. Then I click the button, which arms the timer, that works, then the timer fires, all is well.

Above a certain limit, things suddenly go wrong: creating a few more controls than before during setup (no use is made of any Timer controls).

When I click the button, instead of arming the Timer the app crashes with a ‘Report/Ignore’ Xojo crash dialog when I try to ‘touch’ the Timer, taking me to the Feedback app.

My suspicion is that something ‘inside’ Xojo is consuming Windows system timers. After creating 100s of controls, they’re all consumed by the purple timer eater. When I then try to arm my single Timer control, the whole kaboodle crashes because there are no Windows system timers left.

When the limit is reached, the IDE also becomes wonky - I suspect it also uses the same pool of timers when running a program from the IDE.

You did not attach any test project to the bug report. It would have been the only way for Xojo to see what is going on.

At first glance “hundreds of controls” (500, 1000 ?) is probably gobbling memory…

Timer is just one among a crowd, and if all memory is gone, it can do little else but crash. Not sure this specific to timers.

I did attach the test project, but only for Xojo to see. It’s a stripped down version of a confidential project, so I cannot make it available to the world.

It’s not a memory issue, pretty sure of that; plenty of memory available.

In the Feedback report being auto-generated when things crash, it shows it is an internal assert that fires inside Xojo about not being able to set the timer.

Also, the Xojo docs say that Timer controls on Windows are based on Windows System Timers, which are limited in number.

The app runs without a hitch on Mac.

The solution might be to create less controls (which I can do, but not quickly: some stuff has to be refactored), so I want to first find out what the story is - whether it is a timer leak, or something else, or instead a hard limitation in Windows.

I don’t think Xojo controls ought to consume (many) timers. It is perfectly possible to use a very limited amount of system timers and share it for many controls, so if it really is a Timer issue (I suspect there is a certain type of controls that grabs an ‘internal’ system timer, one per control), that should be fairly easy to fix by refactoring and having a single Timer control service all controls of a certain type. But I am only guessing. Might be totally different.

On the application side, it is certainly feasible to use one timer as scheduler, and a queue or methods to trigger. That would certainly alleviate a good number of issues with too many separate timers.

Yup. That’s what I did initially when I thought I was consuming too many timers: I reduced my footprint to a single scheduling timer with variable period (it calculates the time up to the next time something needs to fire) and I replaced all my timers with a ‘SharedTimer’ object that looks and feels like a Xojo Timer, so it is a drop-in replacement, but SharedTimer is not associated with a Xojo Timer; it just an object maintained by a global timer manager object that only consumes a single Xojo Timer. The SharedTimer are kept in an ordered list by when they need to fire, so it is easy to calculate when to fire the single Xojo timer next.

Then I found that that did not fix my problem, and something else was apparently consuming timers.

You might also try this to see if you’re hitting a Windows limit
From https://social.msdn.microsoft.com/Forums/windows/en-US/73aaa1f3-30a7-4593-b299-7ec1fd582b27/the-current-process-has-used-all-of-its-system-allowance-of-handles-for-window-manager-objects?forum=winforms

You can use Task Manager’s View menu, Select Columns. Turn on “USER Objects”. (Here, USER means “user interface”, as in user32.dll, the main GUI library in Windows.) Go to the Processes tab. Monitor and make sure your process is a team player and does not use too many more objects than other major applications like MS Word, Internet Explorer, etc. IIRC, the limit is 10000 USER objects per process but you should avoid getting anywhere near it as there is also a session-wide limit that is too close for comfort to the per process limit.