Jump to content

TimerDiff returns negative values


Recommended Posts

I know TimerInit / TimerDiff works for many people over many years without problems, but

I have a case where these functions fail.
I know also to handle the return value of TimerInit as a handle and not directly to work
on it (except with TimerDiff). But this value is nothing else than the return value
of Win32-Api call to QueryPerformanceCounter(...). 
It seems the Timer functions assume the internal counter as 64Bit. But in
my case the value will wrap around after reaching the maximum of an unsigned 32Bit value.
This may lead to negative TimerDiff return values. 
e.g.: take TimerInit short time before the overflow and do TimerDiff after the overflow, then TimerDiff returns
negative values. This happens on a Windows XP 32Bit SP3 running on a Hyper-V machine (based on a AMD-Phenom 
processor).
The question is: Why do I get this negative values? I wrote my own TimerInit/TimerDiff function in C++
using the windows API functions. I also see the 32bit overflow ( in my case every 20min) and
the calculation is based on integer math only. This compensates the overflow.
With my integer only implementation I always get the correct difference (where AutoIt will fail).
 
I guess it has something to do with the internal implementation, because the AutoIT functions seems to
work with double values, so maybe the internal functions casts the counter values to double
and the calculation is based on double operations?

My test code should show the details. There is also a try to solve the problem with AutoIT code using the API function directly.
I know this would only work for 32bit values, but in case of 64bit values it take a very long time to get wrong...
And yes, it may not happen on every machine, maybe only on Hyper-V hosted XPs.... 
 
 
$fp = FileOpen("timer_test.txt",1)
$F = DllCall("Kernel32.dll", "Int", "QueryPerformanceFrequency", "int64*", "")
$maxint = 4294967296
Do
  Local $TimeNow = TimerInit()
  $S = DllCall("Kernel32.dll", "Int", "QueryPerformanceCounter", "int64*", "")
  Sleep(1000)
  Local $TimeDiff = TimerDiff($TimeNow)
  $E = DllCall("Kernel32.dll", "Int", "QueryPerformanceCounter", "int64*", "")
  Local $diff = $E[1]-$S[1]
  ; Correct overflow
  If $E[1] < $S[1] Then $diff += $maxint   ; Because there is no real integer operation in AutoIT, add the 32bit max int to correct value!
  FileWriteLine( $fp, @CRLF & "Time diff using QPC:" & @CRLF & "Start: " & $S[1] & " End: " & $E[1] & " " & " Diff: " & $diff & " " & "Freq.: " & $F[1] & @CRLF & "(E-S)/F= " & $diff/$F[1] & " sec" & @CRLF)
  FileWriteLine( $fp, "Using AutoIT - Init: " & $TimeNow & "  Diff (ms): " & $TimeDiff )
Until $TimeDiff < 0 ; may not stop if your system is using 64bit timer values....
My output looks like that:
 
     :
     :
Time diff using QPC:
Start: 4284216198 End: 4287790942 Diff: 3574744 Freq.: 3579545
(E-S)/F= 0.998658768083653 sec
Using AutoIT - Init: 4284216041 Diff (ms): 998.626082365217

Time diff using QPC:
Start: 4287795275 End: 4291474056 Diff: 3678781 Freq.: 3579545
(E-S)/F= 1.02772307653626 sec
Using AutoIT - Init: 4287795136 Diff (ms): 1027.56132413477

Time diff using QPC:
Start: 4291479430 End: 82755 Diff: 3570621 Freq.: 3579545
(E-S)/F= 0.997506945715168 sec
Using AutoIT - Init: 4291479108 Diff (ms): -1198866.52297988
 
 
THX in advance!
 
Edited by chessi
Link to comment
Share on other sites

There is already a function that does what your code does, _Timer_Init and _Timer_Diff, it's in the Timers.au3 UDF.

If I posted any code, assume that code was written using the latest release version unless stated otherwise. Also, if it doesn't work on XP I can't help with that because I don't have access to XP, and I'm not going to.
Give a programmer the correct code and he can do his work for a day. Teach a programmer to debug and he can do his work for a lifetime - by Chirag Gude
How to ask questions the smart way!

I hereby grant any person the right to use any code I post, that I am the original author of, on the autoitscript.com forums, unless I've specifically stated otherwise in the code or the thread post. If you do use my code all I ask, as a courtesy, is to make note of where you got it from.

Back up and restore Windows user files _Array.au3 - Modified array functions that include support for 2D arrays.  -  ColorChooser - An add-on for SciTE that pops up a color dialog so you can select and paste a color code into a script.  -  Customizable Splashscreen GUI w/Progress Bar - Create a custom "splash screen" GUI with a progress bar and custom label.  -  _FileGetProperty - Retrieve the properties of a file  -  SciTE Toolbar - A toolbar demo for use with the SciTE editor  -  GUIRegisterMsg demo - Demo script to show how to use the Windows messages to interact with controls and your GUI.  -   Latin Square password generator

Link to comment
Share on other sites

BrewManNH, thanks for your answer, but it doesn't help. The implementation and the behavior is same like the
original AutoIt functions TimerInit and TimerDiff.
 
What I need is a raw 32Bit operation, which is not possible with AutoIT because it is using variants.
Otherwise I have to use the code which I have attached. (This line is important: $E[1] < $S[1] Then $diff += $maxint)
 
O.k. maybe my root problem is why I get such 32bit instead 64bit counter values. I could imagine that there other
people out there, who have the same problem but they don't have it recognized yet. I guess also that this will
happen only on virtual machines, but virtual machines are getting more and more popular....
Link to comment
Share on other sites

So is it an AutoIt issue, or a Hyper-V issue? It appears to be a Hyper-V issue from reading the links you posted, and there's a simple fix to workaround it.

If I posted any code, assume that code was written using the latest release version unless stated otherwise. Also, if it doesn't work on XP I can't help with that because I don't have access to XP, and I'm not going to.
Give a programmer the correct code and he can do his work for a day. Teach a programmer to debug and he can do his work for a lifetime - by Chirag Gude
How to ask questions the smart way!

I hereby grant any person the right to use any code I post, that I am the original author of, on the autoitscript.com forums, unless I've specifically stated otherwise in the code or the thread post. If you do use my code all I ask, as a courtesy, is to make note of where you got it from.

Back up and restore Windows user files _Array.au3 - Modified array functions that include support for 2D arrays.  -  ColorChooser - An add-on for SciTE that pops up a color dialog so you can select and paste a color code into a script.  -  Customizable Splashscreen GUI w/Progress Bar - Create a custom "splash screen" GUI with a progress bar and custom label.  -  _FileGetProperty - Retrieve the properties of a file  -  SciTE Toolbar - A toolbar demo for use with the SciTE editor  -  GUIRegisterMsg demo - Demo script to show how to use the Windows messages to interact with controls and your GUI.  -   Latin Square password generator

Link to comment
Share on other sites

Both links suggest to add usepmtimer to the boot.ini. I tried this and in my case it doesn't help again.
 

Would be interesting to know if other people have the same issue. It's easy to test. My example code stops working after 20min. in case of that problem (otherwise it runs many years...).

Reading out the QueryPerformanceCounter and checking if it is less than a max 32Bit value is also a good indicator (assumes machine has been running for some time).

And I don't think this is a real AutoIT issue. But it is good to know that this behavior could happen. Is used TimerInit/TimerDiff to calculate timeouts. In case of that negative diff values my timeout never reached the end, so I got script runs which never stops....( only on a few machines, so it take some time to figure out what the reason was).

Link to comment
Share on other sites

Of course it's an AutoIt issue. You as user shouldn't care about internal workings of AutoIt, therefore if the documentation says that TimerDiff() returns difference in miliseconds without making any remarks, then in any other case it's an issue.

♡♡♡

.

eMyvnE

Link to comment
Share on other sites

Would be interesting to know if other people have the same issue. It's easy to test. My example code stops working after 20min. in case of that problem (otherwise it runs many years...).

Tested for more than one hour without any problem (Win7 64bits - script executed in 32bits).

Link to comment
Share on other sites

  • 9 months later...
  • 1 year later...

Well, I have the same problem now. Is there maybe now a solution or workaround or anything?

My timer works just fine but when I try using the ImageSearch UDF my timer breaks.

I can provide my script as an example, although it's gotten kind of big and messy.

Btw, sorry for necroing. Thought it would still be better than to make a new topic.

Edited by Kira16651
Link to comment
Share on other sites

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
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...