AutoHotkey Community

It is currently May 26th, 2012, 12:40 pm

All times are UTC [ DST ]




Post new topic Reply to topic  [ 17 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: Timers don't work
PostPosted: December 19th, 2008, 5:00 am 
Here's the test code I used:

Code:
cycles = 0

SetTimer, TestTimer, 10

TestTimer:
   cycles++
   Tooltip, %time%


With an interval of 10 milliseconds for each run, it should run the loop 100 times per second. I ran the loop for approximately 60 seconds (give or take one or two seconds), so the number I should have gotten should have been within the range of 5,900-6,100. However, I only got about 3,700 after one minute. Instead of getting 100 iterations per second, I got about 61.6 iterations per second. 1,000 milliseconds / 61.6 cycles = 16.23 milliseconds per cycle. So, instead of getting one cycle every 10 seconds, I'm getting one cycle every 16.23 seconds.

Does anyone else have the same problem?


Report this post
Top
  
Reply with quote  
 Post subject:
PostPosted: December 19th, 2008, 5:18 am 
Also, I tried changing from 10 milliseconds to 20, so that I would get 50 cycles per second. I should have gotten around 3,000 cycles after a minute. I only got 1,900. I tried changing from 20 to 50, so that I would get 20 cycles per second. I should have gotten 1,200 cycles after a minute, but I got 960. I changed it to 100 milliseconds per cycle, so that I would get 600 cycles after a minute. I got 540 cycles. It's consistently slower than it should be.

Also, I'm running XP with Service Pack 3, if it matters.


Report this post
Top
  
Reply with quote  
 Post subject:
PostPosted: December 19th, 2008, 5:18 am 
Offline

Joined: January 12th, 2008, 7:45 pm
Posts: 131
Hey, are you running the script with "SetBatchLines, -1" without that the script won't run as fast as it could...

Another note worth mentioning is that timers aren't that precise... as I recall it wouldn't count more precise than aprox 16ms (depending on hardware/state of the pc etc), but it's just a rough note that I don't remember really well...

Basically there is not much you can do about timers, they will not be precise... I've gone through this before...

PS it's not a bug...

_________________
Image


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: December 19th, 2008, 5:23 am 
Moderator: This should be in Ask for Help. Just because Debuggerizer does not undertand the limits of timers, is not a good reason to post (or leave it here as) a bug report. IMO

Help wrote:
Currently, timers cannot run much more often than every 10ms on Windows XP/2000/NT and about 55ms on Windows 9x. Specifying a Period less than this will usually result in an actual interval of 10 or 55 (but this policy could change in future versions so shouldn't be relied upon).

A timer might not be able to run as often as specified under the following conditions:
Other applications are putting a heavy load on the CPU.
The timer subroutine itself takes longer than its own period to run, or there are too many other competing timers (altering SetBatchLines may help).
The timer has been interrupted by another thread, namely another timed subroutine, hotkey subroutine, or custom menu item (this can be avoided via Critical). If this happens and the interrupting thread takes a long time to finish, the interrupted timer will be effectively disabled for the duration. However, any other timers will continue to run by interrupting the thread that interrupted the first timer.
The script is uninterruptible as a result of Critical or Thread Interrupt/Priority. During such times, timers will not run. Later, when the script becomes interruptible again, any overdue timer will run once as soon as possible and then resume its normal schedule.


Report this post
Top
  
Reply with quote  
 Post subject:
PostPosted: December 19th, 2008, 6:24 am 
I'm using Windows XP, so, according to the information about SetTimer, 10ms should work. Furthermore, the other settings that I used (20, 50, 100) should have worked. My normal CPU usage is around 1-5% and I've got a dual core 2.81 Ghz Intel CPU. There shouldn't be any problems because of an excessive load. It should be clear that the timer subroutine I used takes no longer than 16 milliseconds, as I demonstrated in the first example. So, when I gave it 20 milliseconds to complete the task, it should have finished in exactly 20 milliseconds. I wasn't running any other ahk scripts at the time, there should be no interference from that.

Basically, I ran this test under ideal conditions, and I didn't get what was claimed:

Quote:
Period: Creates or updates a timer using this parameter as the number of milliseconds that must pass since the last time the Label subroutine was started. When this amount of time has passed, Label will be run again (unless it is still running from the last time).


My test at 100 milliseconds per cycle should have worked. There should definitely have been enough time to complete the subroutine, and then start it again right on time. However, the timer seems to add anywhere from 6-12 ms to the original time.

Original setting - Real setting
10 ms spacespa- 16.23 ms
20 ms spacespa- 31.58 ms
50 ms spacespa- 62.5 ms
100 ms spacesp- 111.11 ms

There's no mention in the description of the timer that it will add 6-12 ms to the actual time that you set.


Report this post
Top
  
Reply with quote  
 Post subject:
PostPosted: December 19th, 2008, 6:38 am 
Offline

Joined: May 28th, 2008, 2:11 am
Posts: 739
Location: Minnesota, USA
Try posting the exact code you used... the one you did post won't do anything...

_________________
Unless otherwise stated, all code is untested

(\__/) This is Bunny.
(='.'=) Cut, copy, and paste bunny onto your sig.
(")_(") Help Bunny gain World Domination.


Last edited by Slanter on December 19th, 2008, 6:56 am, edited 2 times in total.

Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: December 19th, 2008, 6:42 am 
Ah, sorry, my mistake.

Code:
cycles = 0

SetTimer, TestTimer, 10

TestTimer:
   cycles++
   Tooltip, %cycles%


Report this post
Top
  
Reply with quote  
 Post subject:
PostPosted: December 19th, 2008, 6:43 am 
Offline

Joined: January 12th, 2008, 7:45 pm
Posts: 131
As I've understood, the weird delay i is not a set value, the value is variable, and as I recall that value is not the same on all PCs... you shouldn't rely on settimer for exact calculation, as it is not predictable... it rounds up just like A_Tickcount, I believe..

Code:
#Persistent
;SetBatchLines, -1         ; this shouldn't be commented, but w/e...
cycles = 0

SetTimer, TestTimer, 10

TestTimer:
   cycles++
   Tooltip, %cycles%

Fix'd (as in the script running, but the problem still exists)

_________________
Image


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: December 19th, 2008, 6:57 am 
Offline

Joined: May 28th, 2008, 2:11 am
Posts: 739
Location: Minnesota, USA
Just tested this using the following script. Did tests over 60 seconds (exactly 60 seconds...). Took ~0.4% longer than expected on 10ms, ~0.2% longer than expected on 100ms, ~0.1% longer than expected on 1000ms. I am running Win2k Pro on a PoS computer from the 90's, while running firefox, windows media player, and several other programs.

I see no problem here

Code:
#Persistent
Projected = 0
Time := 1000

SetBatchLines, -1
SetTimer, Stop, 60000
Start := A_TickCount
SetTimer, TestTimer, %Time%
Return

TestTimer:
   Projected+=Time
   Tooltip, % ((A_TickCount - Start) / Projected) " times longer than expected"
Return

Stop:
   SetTimer, TestTimer, Off
Return

_________________
Unless otherwise stated, all code is untested

(\__/) This is Bunny.
(='.'=) Cut, copy, and paste bunny onto your sig.
(")_(") Help Bunny gain World Domination.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: December 19th, 2008, 10:21 am 
Offline

Joined: November 23rd, 2007, 10:23 am
Posts: 841
Location: ~/.
here we have a hi res benchmark script build with my benchmarking framework ...
(abs framework from http://www.autohotkey.com/forum/viewtopic.php?t=35354)

ABS 1.0 wrote:
---------------------------
Benchmark Results 5 Runs with 10 Rounds
---------------------------

SetBatchLines, 20
Critical, Off / Process Priority Normal

0.100033 sec (Standard SetTimer,Label,-10)


SetBatchLines, -1
Critical, Off / Process Priority Normal
0.175800 sec (Standard SetTimer,Label,-10)

SetBatchLines, -1
Critical,Off / Process Priority High
0.183413 sec (Standard SetTimer,Label,-10)

---------------------------
OK
---------------------------


this is the abs code used (code to benchmark is red):
Code:
; QueryPerfomanceCounter - Benchmark Skript
; Part of Official PlayAHK.com xFast-Exec Benchmark Skript
; Version 1.0 (w) 2008 by DerRaphael / zLib License Style Release

DllCall("QueryPerformanceFrequency", "Int64*", BenchMark[F])
; BENCHMARK START
; Äußere Runden / Outer Rounds
@OR := 5
; Innere Läufe / Inner Runs
@IR := 10

; Start Benchmark
Loop,3
{
   Setting := A_Index
   SetBatchLines, 20
   Critical, Off
   Process, Priority,, Normal
   if (A_Index = 1) {
      CurrentSettings := "SetBatchLines, 20`nCritical, Off / Process Priority Normal"
   } else if (A_Index = 2) {
      CurrentSettings := "SetBatchLines, -1`nCritical, Off / Process Priority Normal"
      SetBatchLines, -1
      Process, Priority,, Normal
   } else if (A_Index = 3) {
      CurrentSettings := "SetBatchLines, -1`nCritical,Off / Process Priority High"
      SetBatchLines, -1
      Process, Priority,, H
   }
   OfficialResult .= "`n" CurrentSettings "`n"
   tooltip,% currentsettings, 10, 10
   
   Loop, % @OR
   {
      A_Run := A_Index
      Loop, % @IR
      {
         ; Zähler der auszuführenden Tests / Count of Tests to accomplish
         A_Test := 0
         
         ; SOBM***********************************************************************************
         A_Test+=1
         
         if !StrLen(Desc[%A_Test%])
            Desc[%A_Test%] := "Standard SetTimer,Label,-10"
           
         DllCall("QueryPerformanceCounter", "Int64 *", BenchMark[SC]) ; StartCounter
         
         ; Hier komme hinein, was getestet wird / Insert what needs to be tested
      counter := 0
      Loop,
         if (counter=10) ; expected ideal time is 100 ms
            break
         Else {
            SetTimer,tst_iteration,-10
         }

         ; Hier ist zuende, was getestet wurde / End of whatever has been tested
         
         DllCall("QueryPerformanceCounter", "Int64 *", BenchMark[EC]) ; EndCounter
         
         Result[%A_Test%][%A_Run%][%A_Index%] := (BenchMark[EC] - BenchMark[SC]) / BenchMark[F]
         ; ***********************************************************************************EOBM

      }
      ; Zeiten mitteln / Average Timings
      Loop, % A_Test
      {
         A_Test := A_Index
         Result[%A_Test%][%A_Run%] := 0
         Loop, % @IR
            Result[%A_Test%][%A_Run%] += Result[%A_Test%][%A_Run%][%A_Index%]
         Result[%A_Test%][%A_Run%] /= @IR
      }
   }
   ; BENCHMARK END
   ; Resultate ermitteln / Calculate Results
   Loop, % A_Test
   {
      A_Test := A_Index
      Result[%A_Test%] := 0
      Loop, % A_Run
         Result[%A_Test%] += Result[%A_Test%][%A_Index%]
      Result[%A_Test%] /= @OR
      OfficialResult .= Result[%A_Test%] " sec`t(" Desc[%A_Test%] ")`n"
   }
}
SetBatchLines, 20
Critical, Off
Process, Priority,, Normal

MsgBox,64,Benchmark Results %@OR% Runs with %@IR% Rounds, %OfficialResult%
ExitApp

tst_iteration:
   counter += 1
return


i might be wrong, but to me it looks as if the timer works perfectly well under standard circumstances. maybe someone else can also benchmark this one and post result msgbox (1ghz / win2k sp4 / ahk 1.0.48 beta)

try rerunning the script multiple times as windows caches the binary (later runs result in more acurate timings)

greets
dR

_________________
Image
    All scripts, unless otherwise noted, are hereby released under CC-BY


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: December 31st, 2008, 6:11 am 
Offline

Joined: March 2nd, 2004, 3:36 pm
Posts: 10720
I've clarified the SetTimer documentation to indicate that 15ms is the minimum interval on some PCs. In the future it could probably use some more clarification -- perhaps even a mention of the timeBeginPeriod technique mentioned in other topics.

Thanks.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: December 31st, 2008, 4:36 pm 
Offline

Joined: February 14th, 2005, 4:05 pm
Posts: 4710
Location: Boulder, CO
It was discussed more than 3 years ago, too. Most modern PC’s (chipsets?) seem to have a HW tick period of 15.6ms, and accordingly, the timer period is not what you request, but the closest multiple of 15.6ms (at least 15.6ms for larger than 0 periods). If you need better resolution, you can always use the multimedia (performance) timers, although I experienced bad crashes with them in complex scripts.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: January 3rd, 2009, 5:04 pm 
Offline

Joined: March 2nd, 2004, 3:36 pm
Posts: 10720
Thanks for that info, which I've applied to the Sleep and SetTimer pages. I also added the following wording:
Quote:
Due to the granularity of the OS's time-keeping system, Delay is typically rounded up to the nearest multiple of 10 or 15.6 milliseconds (depending on the type of hardware and drivers installed). For example, a delay between 1 and 10 (inclusive) is equivalent to 10 or 15.6 on most Windows NT/2000/XP systems. To achieve a shorter delay [see the following example]:
...
Code:
; The following is a working example that demonstrates how to sleep for less time than the
; normal 10 or 15.6 milliseconds.
; NOTE: While a script like this is running, the entire operating system and all applications are
; affected by timeBeginPeriod below.

SetBatchLines -1  ; Ensures maximum effectiveness of this method.

SleepDuration = 1  ; This can sometimes be finely adjusted (e.g. 2 is different than 3) depending on the value below.
TimePeriod = 3 ; Try 7 or 3.  See comment below.
; On a PC whose sleep duration normally rounds up to 15.6 ms, try TimePeriod=7 to allow
; somewhat shorter sleeps, and try TimePeriod=3 or less to allow the shortest possible sleeps.

DllCall("Winmm\timeBeginPeriod", uint, TimePeriod)  ; Affects all applications, not just this script's DllCall("Sleep"...), but does not affect SetTimer.
Iterations = 50
StartTime := A_TickCount

Loop %Iterations%
    DllCall("Sleep", UInt, SleepDuration)  ; Must use DllCall instead of the Sleep command.

DllCall("Winmm\timeEndPeriod", UInt, TimePeriod)  ; Should be called to restore system to normal.
MsgBox % "Sleep duration = " . (A_TickCount - StartTime) / Iterations

Things like the above probably have been discovered and explored in other topics; so improvements are welcome.

Edit: Optimized the code.


Last edited by Chris on January 3rd, 2009, 6:28 pm, edited 1 time in total.

Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: January 3rd, 2009, 5:48 pm 
Offline

Joined: February 14th, 2005, 4:05 pm
Posts: 4710
Location: Boulder, CO
I have been using a much simpler method:
Code:
SoundBeep 1, ms
It sleep ms milliseconds, by playing an inaudible sound (1Hz). At least in my Vista PC there is no large CPU load, but older PC's could actually use the CPU to generate the sound, so I am not sure, if it is a good substitute in every situation.

The script above gives the same result if I remove the timeBeginPeriod and timeEndPeriod dll calls, in my Vista 32 PC. It looks like the Sleep dll call uses finer timer resolution than the Sleep AHK command. Or, it uses some averaging process. MSDN does not say.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: January 3rd, 2009, 6:24 pm 
Offline

Joined: March 2nd, 2004, 3:36 pm
Posts: 10720
Laszlo wrote:
I have been using a much simpler method:
Code:
SoundBeep 1, ms
It sleep ms milliseconds, by playing an inaudible sound (1Hz).
Creative technique. For some reason on my PC, it doesn't seem to sleep at all (or inconsistently) if the frequency is below 40 or so. The following displays 0.000000 unless I raise the frequency:

Code:
SetBatchLines -1  ; Ensures maximum effectiveness of this method.
Iterations = 50
StartTime := A_TickCount
Loop %Iterations%
    SoundBeep 30, 10
MsgBox % "Sleep duration = " . (A_TickCount - StartTime) / Iterations

Laszlo wrote:
The script above gives the same result if I remove the timeBeginPeriod and timeEndPeriod dll calls, in my Vista 32 PC. It looks like the Sleep dll call uses finer timer resolution than the Sleep AHK command. Or, it uses some averaging process. MSDN does not say.
Interesting. I believe AutoHotkey uses SetTimer() to implement the Sleep command except for Sleep 0 (and except for short sleeps on Windows 9x). Perhaps a future version of AutoHotkey should use Sleep() instead of SetTimer() when the specified duration is very short, perhaps under 10ms (at least if the OS is Vista or later). On the other hand, that seems likely to alter the behavior of a lot of existing scripts, so it might be best to defer it to AutoHotkey v2.

In the meantime, a new parameter could be added to Sleep, maybe TimePeriod:
If new parameter missing (or zero?), use existing/old behavior.
If present, use timeBeginPeriod + Sleep + timeEndPeriod.

However, that mode could have side effects because it would affect the entire OS and all applications during the duration of the Sleep.


Report this post
Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 17 posts ]  Go to page 1, 2  Next

All times are UTC [ DST ]


Who is online

Users browsing this forum: No registered users and 21 guests


You can post new topics in this forum
You can reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Powered by phpBB® Forum Software © phpBB Group