Jump to content
Sign in to follow this  
dummzeuch

TTimer equivalent with smaller interval

Recommended Posts

The TTimer component has a minimum interval of 50ms. I understand that this is a limitation of the Windows timer which uses messages.

 

What would be the alternative if I need smaller intervals, e.g. down to 10ms?

 

The code is still supposed to be run in the main VCL thread. It doesn't matter if some events get lost because executing the code takes longer than the timer interval because the computer is busy. I just want to be able to get a smaller interval if the computer can support it.

Share this post


Link to post

Look at CreateTimerQueue /  CreateTimerQueueTimer. Nothing too difficult but needs a callback and probably an event and thread to wait on it.

Share this post


Link to post
27 minutes ago, dummzeuch said:

The TTimer component has a minimum interval of 50ms.

AFAIK, that has been true for Windows 95. According to the WinApi SetTimer function, which is internally used by a VCL TTimer, the minimum value for Interval is 10 ms: 

Quote

If uElapse is less than USER_TIMER_MINIMUM (0x0000000A), the timeout is set to USER_TIMER_MINIMUM.

 

Edited by Uwe Raabe
  • Like 1
  • Thanks 1

Share this post


Link to post
4 minutes ago, Uwe Raabe said:

According to the WinApi SetTimer function, which is internally used by a VCL TTimer, the minimum value for Interval is 10 ms: 

Quote

If uElapse is less than USER_TIMER_MINIMUM (0x0000000A), the timeout is set to USER_TIMER_MINIMUM.

 

Yes, I just found that too and was suprised. Apparently my "knowledge" about this minimum interval goes back to Windows 95 times.

 

This also matches the logs that I am currently looking at: The next timer event starts in the same millisecond that the last one ended. So apparently it's not the interval that's the limiting factor here but the code executed in the event.

 

Thanks everybody. That's the answer.

Edited by dummzeuch

Share this post


Link to post

@dummzeuch A long long time ago I recall a program/component, I don't remember which,

had a much lower time that ttimer.  

With all the information on Delphi that i have, it is some ware on my old old old computer.

@dummzeuch  Try searching for it may come up.

Share this post


Link to post
18 minutes ago, limelect said:

@dummzeuchFound on my backup sending you by mail

Some interesting implementations, thanks. Not sure that I can use any of them though.

  • Like 1

Share this post


Link to post

Have you considered the OnIdle event on tApplication? (optionally with the ApplicationEvents component)?

In other words, instead of using a kind of timer, you can have the message pump itself run something between each message! I've had a scenario once that would make the process take 100% of one CPU, but I've recently discovered Windows' own SwitchToThread to have a kind-of timer using Windows' own task switching 'cadence'. If you need finer grained timing, I would suggest QueryPerformanceTimer

Share this post


Link to post
8 hours ago, stijnsanders said:

Have you considered the OnIdle event on tApplication?

(Plus some kind of time interval checking.)

 

No, but it's an interesting idea. Unfortunately not helpful in my particular case as I have now determined that it is not the timer interval but the code executed in the event that causes my slow down effect. I have tried to optimize it but so far failed. There are too many complex dependencies on multithreaded code to easily find the culprit.

Share this post


Link to post

My first thought was - why not use a thread with sleep if you need that fast a timer - but - again, multithreading raises its own issues.

 

 

Share this post


Link to post
49 minutes ago, Lars Fosdal said:

My first thought was - why not use a thread with sleep if you need that fast a timer - but - again, multithreading raises its own issues.

I'm not sure WaitFor* functions have lesser granularity

Share this post


Link to post
22 hours ago, Lars Fosdal said:

My first thought was - why not use a thread with sleep if you need that fast a timer - but - again, multithreading raises its own issues.

 

 

Try timing Sleep(1) with TStopwatch. 

Share this post


Link to post

Anyways - under Windows, we have the so-called multimedia timer, 

https://docs.microsoft.com/en-us/windows/win32/multimedia/about-multimedia-timers

but a caveat is that actual minimum resolution varies with platform and device

https://docs.microsoft.com/en-us/windows/win32/multimedia/timer-resolution

 

var
  TCaps: TTimeCaps; // WinAPI.MMSystem;
  rc: MMResult;
begin
  rc := timeGetDevCaps(@TCaps, SizeOf(TCaps)); // WinAPI.MMSystem;
  if rc = 0
   then Writeln(Format('Min %d / Max %d', [TCaps.wPeriodMin, TCaps.wPeriodMax]))
    else Writeln(Format('timeGetDevCaps returned %d', [rc]));
end;

outputs
Min 1 / Max 1000000
on my computer.

 

Oddly enough, the resolution is 1ms - so, in theory it is impossible to use a timer to get a better resolution than 1 ms.

 

Still - the WaitableTimer has 100ns resolution, so that should work, right?

https://docs.microsoft.com/en-gb/windows/win32/api/synchapi/nf-synchapi-setwaitabletimer

 

function NanoSleep(const NanoSec: Int64):Boolean;
var
  Timer: THandle;
  Constraint: _Large_Integer;
begin
  Result := False;
  Timer := CreateWaitableTimer(nil, True, nil);
  if timer <> 0
  then try
    Constraint.QuadPart := -NanoSec;
    if SetWaitableTimer(Timer, Constraint.QuadPart, 0, nil, nil, False)
    then begin
      WaitForSingleObject(Timer, INFINITE);
      Result := True;
    end;
  finally
    CloseHandle(Timer);
  end;
end;

but even that is incredibly erratic.

 

const
  ns: Int64 = 10000;
var
  st: TStopWatch;
  ix: Integer;
begin
  st := TStopWatch.StartNew;
  for ix := 1 to 10
   do NanoSleep(ns);
  st.Stop;
  Writeln(st.ElapsedMilliseconds);
end;

and does not seem to work at low intervals - unless I screwed something up?

Windows is not a real time OS - so it seems milliscond timing will be iffy - unless you use a power consuming loop of instructions - and that is not desirable.

Share this post


Link to post
Guest

Sleep(1) will not do it, as the system wide setting that be configured by timeBeginPeriod ( https://docs.microsoft.com/en-us/windows/win32/api/timeapi/nf-timeapi-timebeginperiod ) will affect the accuracy of Sleep.

Be careful when use Sleep(1) in Delphi, because Delphi IDE is altering that system wide setting and set it to 1 when it is running and try to return it to 16 or 15 when exit, so if you are testing stuff with Sleep(1) with Delphi IDE is running you will find the result is far from the result when the IDE is not running in the background.

 

@Lars Fosdal That NanoSleep is something, but .... it does suffer from the same system accuracy like Sleep(1) and without the IDE or adjusting timeBeginPeriod the interval will be mostly 15 when the thread priority THREAD_PRIORITY_TIME_CRITICAL and that is very optimistic prediction.

 

@Lars Fosdal I am using Chrome, i copied your NanoSleep function and pasted it on two different IDE's and both complained about hidden character before your open bracket "(", you might want to investigate that, or it is forum problem,

to be exact to point the problem :

You have an invisible character before "(" in few places, to be exact it is $FEFF aka "zero width no-break space", and you might be interested in reading this https://www.freecodecamp.org/news/a-quick-tale-about-feff-the-invisible-character-cd25cd4630e7/ but if it is from you side not the forum.

Share this post


Link to post

@Kas Ob. It was a direct cut/paste from BDS to the forum editor in Chrome - so hard to say where the $FEFF was introduced. I can't replicate that error using BDS or VSCode.

 

A proper realtime OS with a functional nanosleep is a better choice than windows for high resolution timing, I suppose.

Share this post


Link to post
Guest
4 minutes ago, Lars Fosdal said:

It was a direct cut/paste from BDS to the forum editor in Chrome - so hard to say where the $FEFF was introduced. I can't replicate that error using BDS or VSCode.

Can you confirm the hidden character first, if you copied form this page and pasted in the IDE ? was it your browser ? or is it my problem ? 

Now i will not sleep before knowing !

 

On side note : i suggest to have this nice and great thing in your toolbox https://windowsclipboard.com/ 

Share this post


Link to post
2 hours ago, Lars Fosdal said:

I am curious - when would you need such minuscule intervals?

The question literally asks about intervals less than that which you obtakn with a timer. You'll find that Sleep has the same performance as a timer. 

Share this post


Link to post
50 minutes ago, Kas Ob. said:

Can you confirm the hidden character first, if you copied form this page and pasted in the IDE ? was it your browser ? or is it my problem ? 

Now i will not sleep before knowing !

 

On side note : i suggest to have this nice and great thing in your toolbox https://windowsclipboard.com/ 

I opened the file as a binary file in a hex viewer and there were no FF or FE bytes.
 

Share this post


Link to post
Guest
7 minutes ago, Lars Fosdal said:

I opened the file as a binary file in a hex viewer and there were no FF or FE bytes.

The is not in the file because if it was there then the IDE would complained, but between coping and pasting the clipboard , now i tried to repeat it, it doesn't appeared before the bracket but in different place, so the problem is found the forum is adding that invisible character randomly, i closed my browser between then and now and the place of this $FEFF is changed.

 

I remember read some one complaining about editing and writing posts here and my self too saw some random artifacts like you can't move the cursor using the keyboard arrows at times, so i would recommend for some one to look at the forum configuration and remove any UTF8 BOM support.

 

image.thumb.png.20787e230662884a9a980396812502e0.png

Share this post


Link to post
1 hour ago, Kas Ob. said:

You have an invisible character before "("

Can't reproduce in Chrome.

@Kas Ob. Wat is your default os encoding and which parentheses was it?

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×