Jump to content
Kas Ob.

Help needed in testing emulated GetTickCount32/64

Recommended Posts

Hi,

 

This version of GetTickCount works in both flavors (32Bit and 64Bit) on all 64Bit Windows versions, the result is identical to both APIs, also the 32Bit version of it will work on all 32bit Windows versions, the problem is i don't have access to to 32Bit Windows that is running for more than 49.7 days to test the 64Bit result version, 

 

And here comes the question for the help, if anyone have access to such OS, like Windows XP or Server 2003 that is running for that long time, it will be great help to test the result from the 64Bit result form this emulated API, and confirm it does return true value with value above the 32Bit.

function GetTickCount64Emu: UInt64;
const
  KUSER_BASE_ADDRESS = $7FFE0000;
  //KUSER_BASE_ADDRESS_KERNEL_MODE =$FFFFF78000000000; //in case it is needed
begin
  Result := (PUInt64(KUSER_BASE_ADDRESS + $320)^ * PCardinal(KUSER_BASE_ADDRESS + $4)^) shr 24;
end;

Rename as you wish, and adjust as you see fit, like make the result Cardinal to replace GetTickCount or keep it as UInt64, it doesn't matter.

 

and keep in mind it does exactly what GetTickCount and GetTickCount64 do, as this snippet i decompiled form the OS, also this address is fixed across Windows versions, and belongs to a readonly page protected, also in the past, well, far past Microsoft documentation for DDK, was suggesting using the same algorithm for games engines to ditch calling API for timing, to squeeze few extra cycles, so even if this approach is not documented now, it was and will stay accessible.

The operation of multiplication and shifting is as it seems a simple division, but with fixed point, hence the bit shifting, per Microsoft documentation the Windows OS kernel is prohibited from using float point operation, and only fixed point are allowed, those has the point at 24th bit.

 

If someone has insight about this, then please share, and if someone can confirm a result over 32bit on an old or new 32Bit system that was and is running for over 49.7 days, then it will be great to share the result.

Share this post


Link to post
Posted (edited)
2 hours ago, Kas Ob. said:

also this address is fixed across Windows versions, and belongs to a readonly page protected, also in the past, well, far past Microsoft documentation for DDK, was suggesting using the same algorithm for games engines to ditch calling API for timing, to squeeze few extra cycles, so even if this approach is not documented now, it was and will stay accessible.

You are accessing a 64bit tick counter that is located at fixed address (0x7FFE0000+800), but according to this discussion: https://groups.google.com/g/comp.lang.asm.x86/c/zA0WcO6_5AU, in XP SP1 and earlier at least, the tick counter was a 32bit integer located at address (0x7FFE0000) instead.  According to the history outlined here: https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/ntexapi_x/kuser_shared_data/index.htm, Windows deprecated the 32bit counter and switched over to the 64bit counter in v5.2 (ie, XP Pro 64bit) onward.

Edited by Remy Lebeau

Share this post


Link to post
1 hour ago, Remy Lebeau said:

You are accessing a 64bit tick counter that is located at fixed address (0x7FFE0000+800), but according to this discussion: https://groups.google.com/g/comp.lang.asm.x86/c/zA0WcO6_5AU, in XP SP1 and earlier at least, the tick counter was a 32bit integer located at address (0x7FFE0000) instead.

Right, i should have mentioned that may be as i read that second source you linked.

 

1 hour ago, Remy Lebeau said:

According to the history outlined here: https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/ntexapi_x/kuser_shared_data/index.htm, Windows deprecated the 32bit counter and switched over to the 64bit counter in v5.2 (ie, XP Pro 64bit) onward.

According to this i have the it should (might) work for all starting from Windows XP SP2/SP3 and Server 2003 SP1, and that include 32Bit and 64Bit , as shown per declaration with 64bit size in that link,

image.thumb.png.2108f42c49cb74dae3aba7f1486935dd.png

It is the same declared in DDK headers

https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/ns-ntddk-kuser_shared_data

 

also here explain the size of KSYSTEM_TIME

https://osm.hpi.de/wrk/2007/08/getting-os-information-the-kuser_shared_data-structure/

 

And there a confession to make there is a condition i omitted in the code because i don't see it as big relevant, in 64bit there is a loop to establish that High2Time and High3Time are identical, this happen if updating one was happening at this very exact moment, i tried to slow my CPU by overloading up to 100%, and couldn't make this trigger, then tried to downclock and overclock CPU, as mine is Intel unlocked (model with "k"), yet even over more than an hour and in both cases could capture such case not even once, and i am not saying it is right to capture it, but i am saying statistically i satisfied, also even when they are not identical, meaning the result will be as much as it was like 100ns before, so no harm there, this can affect and important for kernel drivers, but can not be critical for any software in user mode.

Share this post


Link to post

What is the goal here? GetTickCount64() is available in Vista (6.0) onward.  The page you quoted says the 64bit tick counter existed in 5.1, but wasn't actually in use until 5.2.  So 5.2->6.0 is a pretty small window if you are just looking to emulate GetTickCount64() on pre-Vista systems.

  • Like 1

Share this post


Link to post

Give me a couple of days:

 

image.thumb.png.96926a5bf89f2b76b86e1668694bff6b.png

 

I'll let the admin know NOT to touch either this one or the host 🙂

  • Like 1

Share this post


Link to post
12 hours ago, aehimself said:

Give me a couple of days:

 

image.thumb.png.96926a5bf89f2b76b86e1668694bff6b.png

 

I'll let the admin know NOT to touch either this one or the host 🙂

Great and perfect and Thank you !

Share this post


Link to post
12 hours ago, Remy Lebeau said:

What is the goal here? GetTickCount64() is available in Vista (6.0) onward.  The page you quoted says the 64bit tick counter existed in 5.1, but wasn't actually in use until 5.2.  So 5.2->6.0 is a pretty small window if you are just looking to emulate GetTickCount64() on pre-Vista systems.

I want to know and solve this, away from Windows Server 2003 and Windows XP rare existence, it is nice to have unified version to support them all, this single API stopped a punch of great and old software and split many repository.

 

I don't see this as stupid or waste of time, if a time spent lead to a result in testing something, success or failure, for me this is well spent time.

Share this post


Link to post

@Kas Ob. The VM is now at 61 days of uptime. I'm having a bit of trouble compiling an EXE which actually executes on Windows 2003... I remember having to change something somewhere in the IDE / project options.

If you know the solution let me know - it might be quicker than me attempting to research.

Share this post


Link to post

Found it!

The code I used could not be more simple...

program Project1;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils;

function GetTickCount64Emu: UInt64;
const
  KUSER_BASE_ADDRESS = $7FFE0000;
  //KUSER_BASE_ADDRESS_KERNEL_MODE =$FFFFF78000000000; //in case it is needed
begin
  Result := (PUInt64(KUSER_BASE_ADDRESS + $320)^ * PCardinal(KUSER_BASE_ADDRESS + $4)^) shr 24;
end;

begin
  try
    WriteLn(GetTickCount64Emu);

    ReadLn;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.

And it resulted 5283539281 with 61 days, 3.5 hours of uptime on a 32-bit Windows Server 2003 R2:

 

image.thumb.png.582a9b0cdf91afed53d90ba1d5c2356c.png

 

  • Like 1

Share this post


Link to post
15 hours ago, aehimself said:

And it resulted 5283539281 with 61 days, 3.5 hours of uptime on a 32-bit Windows Server 2003 R2:

Brilliant, thank you very very much !

 

This test is very hard to wait for and make, and you did it, really appreciated your sharing.

Share this post


Link to post

To make it clearer, your result is 5283539281 in decimal which is 13AEC6951 in hex, meaning it did not wrapped (overflow) and performed exactly what GetTickCount64 should/have returned.

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

×