dummzeuch 1505 Posted February 12, 2020 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
Alexander Elagin 143 Posted February 12, 2020 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
Alexander Elagin 143 Posted February 12, 2020 Ok, I knew somebody must have implemented it already: https://blog.grijjy.com/2017/04/20/cross-platform-timer-queues-for-windows-and-linux/ Share this post Link to post
Uwe Raabe 2058 Posted February 12, 2020 (edited) 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 February 12, 2020 by Uwe Raabe 1 1 Share this post Link to post
dummzeuch 1505 Posted February 12, 2020 (edited) 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 February 12, 2020 by dummzeuch Share this post Link to post
FredS 138 Posted February 12, 2020 2 hours ago, dummzeuch said: What would be the alternative Calculating accurate 'Now' or maybe System.Diagnostics.TStopWatch Share this post Link to post
David Heffernan 2345 Posted February 12, 2020 32 minutes ago, FredS said: Calculating accurate 'Now' or maybe System.Diagnostics.TStopWatch Timers are event driven. You are suggesting polling. That's no good. Share this post Link to post
limelect 48 Posted February 13, 2020 @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
limelect 48 Posted February 13, 2020 (edited) @dummzeuchFound on my backup sending you by mail sent acknowledge receipt Edited February 13, 2020 by limelect Share this post Link to post
dummzeuch 1505 Posted February 13, 2020 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. 1 Share this post Link to post
stijnsanders 35 Posted February 16, 2020 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
dummzeuch 1505 Posted February 17, 2020 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
Lars Fosdal 1792 Posted February 17, 2020 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
Fr0sT.Brutal 900 Posted February 17, 2020 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
David Heffernan 2345 Posted February 18, 2020 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
Lars Fosdal 1792 Posted February 18, 2020 I am curious - when would you need such minuscule intervals? Share this post Link to post
Lars Fosdal 1792 Posted February 18, 2020 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 Posted February 18, 2020 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
Lars Fosdal 1792 Posted February 18, 2020 @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 Posted February 18, 2020 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
David Heffernan 2345 Posted February 18, 2020 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
Lars Fosdal 1792 Posted February 18, 2020 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 Posted February 18, 2020 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. Share this post Link to post
Attila Kovacs 629 Posted February 18, 2020 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