Page 1 of 2

A_TickCount to use GetTickCount64 instead of GetTickCount

Posted: 24 Sep 2014, 04:34
by Raccoon
NT

Re: A_TickCount to use GetTickCount64 instead of GetTickCoun

Posted: 24 Sep 2014, 05:26
by jNizM
just use tc := DllCall("Kernel32.dll\GetTickCount64", "UInt64")

Re: A_TickCount to use GetTickCount64 instead of GetTickCoun

Posted: 24 Sep 2014, 05:35
by Raccoon
Thank you jNizM. This is a WishList request for the betterment of AutoHotkey's development.

GetTickCount is deprecated and should be replaced with GetTickCount64 for modern builds of AHK_L where applicable.

GetTickCount on MSDN

GetTickCount64 on MSDN

Re: A_TickCount to use GetTickCount64 instead of GetTickCoun

Posted: 24 Sep 2014, 05:39
by jNizM
See the Minimum Support

GetTickCount function
Retrieves the number of milliseconds that have elapsed since the system was started, up to 49.7 days.
Minimum supported client: Windows 2000 Professional
Minimum supported server: Windows 2000 Server

GetTickCount64 function
Retrieves the number of milliseconds that have elapsed since the system was started.
Minimum supported client: Windows Vista
Minimum supported server: Windows Server 2008

timeGetTime function
The timeGetTime function retrieves the system time, in milliseconds. The system time is the time elapsed since Windows was started.
Minimum supported client: Windows 2000 Professional
Minimum supported server: Windows 2000 Server

=========================================================

Test Script

Code: Select all

WinAPI_timeBeginPeriod(1)
sleep 1000
buf := "-------------------`n"
loop 30
{
	tc := WinAPI_GetTickCount()
	loop
	{
		dt := WinAPI_GetTickCount() - tc
		if (dt >= 1)
		{
			buf .= A_Index . "  " . dt . "`n"
			break
		}
	}
}
buf .= "-------------------`n"
sleep 1000
loop 30
{
	tc := WinAPI_timeGetTime()
	loop
	{
		dt := WinAPI_timeGetTime() - tc
		if (dt >= 1)
		{
			buf .= A_Index . "  " . dt . "`n"
			break
		}
	}
}
WinAPI_timeEndPeriod(1)
MsgBox % buf
ExitApp


WinAPI_GetTickCount()    ; http://msdn.microsoft.com/en-us/library/ms724408.aspx
{
    return DllCall("kernel32.dll\GetTickCount", "UInt")
}

WinAPI_timeGetTime()    ; http://msdn.microsoft.com/en-us/library/dd757629.aspx
{
    return DllCall("Winmm.dll\timeGetTime", "UInt")
}

WinAPI_timeBeginPeriod(uPeriod)    ; http://msdn.microsoft.com/en-us/library/dd757624.aspx
{
    return DllCall("Winmm.dll\timeBeginPeriod", "UInt", uPeriod, "UInt")
}

WinAPI_timeEndPeriod(uPeriod)    ; http://msdn.microsoft.com/en-us/library/dd757626.aspx
{
    return DllCall("Winmm.dll\timeEndPeriod", "UInt", uPeriod, "UInt")
}
=========================================================

Interesting Links about GetTickCount & timeGetTime
- What’s the difference between GetTickCount and timeGetTime?
- Bug in waitable timers?

Image

Re: A_TickCount to use GetTickCount64 instead of GetTickCoun

Posted: 24 Sep 2014, 06:16
by Raccoon
Aye, I'm familiar with all of these.

AHK_L can check internally which is more appropriate to use for minimum support.

You seem to gloss over the fact that GetTimeCount is flawed in its 49.7 day limitation. (timeEndPeriod as well)

This scripting engine should strive to use the best available features at its disposal, without requiring lay users to learn "fancy DllCalls".

Re: A_TickCount to use GetTickCount64 instead of GetTickCoun

Posted: 24 Sep 2014, 06:41
by Raccoon
Swaying off topic:

It doesn't appear that timeBeginPeriod()/timeEndPeriod() are necessary nor effect the resolution of either GetTickCount() or timeGetTime(). Changing the resolution from 1 to 100 or 1000 yields the same results.

Yes, GetTickCount() is based off the minimum resolution of the system clock, and timeGetTime() is based on the processor's timing. While timeGetTime has a lower resolution, it also sways a little bit +/- from real time as it's not based on a quartz crystal like GetTickCount is. Of course, the sway is negligible and impractical to worry about.

Here's a fun comparison script of the two functions.

Code: Select all

s:=""
Loop, 50
{
  gtc:=DllCall("GetTickCount"), tgt:=DllCall("Winmm\timeGetTime")
  s.=gtc " `t " tgt " `t " gtc-tgt "`n" 
  sleep 1
}
msgbox % s
ExitApp

Re: A_TickCount to use GetTickCount64 instead of GetTickCoun

Posted: 24 Sep 2014, 07:10
by jNizM
Raccoon wrote:This scripting engine should strive to use the best available features at its disposal [...]
Thats true =)

OT
just fyi
Timers, Timer Resolution, and Development of Efficient Code

Re: A_TickCount to use GetTickCount64 instead of GetTickCoun

Posted: 24 Sep 2014, 12:37
by Raccoon
Re:OT: One glaring typo in there seems to be "The default timer resolution on Windows 7 is 15.6 milliseconds (ms)." ... that's only true if your system clock is running at 64Hz, but some cheaper system clocks are wired at somewhere between 99Hz and 100Hz which is where Get/SetSystemTimeAdjust() comes in handy to both look up this resolution and tweak it if your system clock drifts too much from real time. A side effect of having a 100Hz system clock is your application timers [WM_TIMER] fire more rapidly (even in Windows 7).

Re: A_TickCount to use GetTickCount64 instead of GetTickCoun

Posted: 25 Sep 2014, 01:22
by nnnik
You do need to learn DllCall if you want extended functionality.

Re: A_TickCount to use GetTickCount64 instead of GetTickCoun

Posted: 02 Oct 2014, 20:22
by Raccoon
nnnik wrote:You do need to learn DllCall if you want extended functionality.
Which is why A_TickCount must be updated, since the average user doesn't learn DllCall... nor should they need to.

MSDN says that GetTickCount() is deprecated and should no longer be used. AHK should only use it for conditional backwards compatibility in builds that still support XP (if any).

Re: A_TickCount to use GetTickCount64 instead of GetTickCoun

Posted: 03 Oct 2014, 00:14
by nnnik
Most users like that will not care whether they use GetTickCount64 instead of GetTickCount.
Also it would break some old scripts so can only be applied to AHKv2 and would then break scripts between XP and newer Windows versions.

Re: A_TickCount to use GetTickCount64 instead of GetTickCoun

Posted: 04 Oct 2014, 16:09
by Raccoon
Challenging that a bug fix (the 49.7 day limitation) will break old scripts (that work around this bug) is a logical fallacy in software development.

Those old scripts will be updated accordingly, should any exist.

Re: A_TickCount to use GetTickCount64 instead of GetTickCoun

Posted: 08 Dec 2014, 10:10
by Bruttosozialprodukt
I'm on Raccoons side here, the fact that scripts running for 50 days would break is kind of alarming imo.
I for example put my PC into hibernate instead of shutting down most of the time.

Re: A_TickCount to use GetTickCount64 instead of GetTickCoun

Posted: 09 Dec 2014, 03:25
by lexikos
If someone who actually cares (i.e. not me) were to make the change and do proper testing and benchmarking, I would consider integrating it.

AutoHotkey uses GetTickCount in quite a number of places internally, so some features other than A_TickCount might also be affected by the (exceedingly rare) limitation. Using GetTickCount64 while also supporting XP would require dynamic binding, which may increase code size and decrease performance (if all instances of GetTickCount were replaced; it is called very often).

Whether a script would break would depend on how the tick count was used. I suppose it would have to be used before and after the 49.7 day overflow occurred, so that end - start produces a negative number (or internally, a very large unsigned number). How severe the consequence of this breakage would be would obviously also depend on the script/usage.

I find it hard to believe there is any script which relies on the overflow occurring. The only practical use for detecting the overflow - that I can think of - would be to work around it.

Re: A_TickCount to use GetTickCount64 instead of GetTickCoun

Posted: 09 Dec 2014, 09:08
by joedf
IMO, it's not worth it. If you're going to a run a script for 50 days, get the system time (sync with the PC) or use DLLCall.

Re: A_TickCount to use GetTickCount64 instead of GetTickCoun

Posted: 09 Dec 2014, 09:28
by Bruttosozialprodukt
One simple check in the very beginning like f = (A_Is64Bit ? GetTickCount64 : GetTickCount); would probably do he job.
I don't think it would affect the performance in a noticeable way.
But I agree it's too much work to implement, as no one has been complaining about issues with this before.

The limitation should be mentioned in the documentation though.

Re: A_TickCount to use GetTickCount64 instead of GetTickCoun

Posted: 09 Dec 2014, 11:28
by joedf
Maybe a notice in the docs is not such a bad idea.

Re: A_TickCount to use GetTickCount64 instead of GetTickCoun

Posted: 10 Dec 2014, 01:47
by jNizM
dont forget the right end-type in ahk

Tick := ((A_Is64bitOS) ? DllCall("Kernel32.dll\GetTickCount64", "UInt64") : DllCall("Kernel32.dll\GetTickCount", "UInt"))

Code: Select all

var1 := A_TickCount
var2 := DllCall("kernel32.dll\GetTickCount", "UInt")
var3 := DllCall("kernel32.dll\GetTickCount64", "UInt64")
var4 := DllCall("winmm.dll\timeGetTime", "UInt")

MsgBox, % var1 "`n" var2 "`n" var3 "`n" var4 "`n"

Re: A_TickCount to use GetTickCount64 instead of GetTickCoun

Posted: 10 Dec 2014, 09:29
by Bruttosozialprodukt
My idea was c++ code and assumed that A_Is64bitOS was supposed to store an exact copy of one function in f.
In theory it could be used like this:

Code: Select all

#include <windows.h>
f = (A_Is64bitOS ? GetTickCount64 : GetTickCount);

f(); //is the same as GetTickCount64() on a x64 OS and GetTickCount() on a x86 OS

Re: A_TickCount to use GetTickCount64 instead of GetTickCoun

Posted: 10 Dec 2014, 09:46
by nnnik
jNizM wrote:dont forget the right end-type in ahk

Tick := ((A_Is64bitOS) ? DllCall("Kernel32.dll\GetTickCount64", "UInt64") : DllCall("Kernel32.dll\GetTickCount", "UInt"))

Code: Select all

var1 := A_TickCount
var2 := DllCall("kernel32.dll\GetTickCount", "UInt")
var3 := DllCall("kernel32.dll\GetTickCount64", "UInt64")
var4 := DllCall("winmm.dll\timeGetTime", "UInt")

MsgBox, % var1 "`n" var2 "`n" var3 "`n" var4 "`n"
I agree that this is a necessity in the second example.
However it is not necessity in the first example since you could just use the default type which is pointer and 64 bits on a 64 bit OS and 32 bits on a 32 bit OS.