Recent

Author Topic: GetTickCount64 duplicate  (Read 1600 times)

valter.home

  • Jr. Member
  • **
  • Posts: 75
GetTickCount64 duplicate
« on: May 26, 2021, 10:53:08 am »
Hello everybody.
I have a problem with GetTickCount64 that never occurred.
I use it to assign a unique name to panels created at runtime, eg MyPanel + [GetTickCount.ToString].
I don't go into the details of my application because I don't think it's necessary but in general:
I have some figures on the screen and each of them is associated with some panels contained in a TScrollBox (which shows only the panels associated with the selected figure).
When I double click on a figure, I delete the contents of the TScrollBox and recreate the panels associated with that figure (whose data is saved on a text file).
I load the contents of the file into a TStringList and use a for loop to recreate the panels.
What happens is that GetTickCount always returns me the same value and therefore I am raised an exception in creating the second panel (duplicate name).
But if I write something like this:

Code: Pascal  [Select][+][-]
  1. n:=(GetTickCount64-random(1000)).ToString;
  2. MyPanel.Name:='Panel'+n;

the problem seems to be solved.
So it would appear that GetTickCount64 doesn't change value as opposed to random (1000) which returns a different number.

Do you have any ideas? Is there any way to somehow reset GetTickCount64?

[edit]
I think the only explanation is that less than a millisecond passes between each pass of the loop.

« Last Edit: May 26, 2021, 12:13:21 pm by valter.home »

engkin

  • Hero Member
  • *****
  • Posts: 2931
Re: GetTickCount64 duplicate
« Reply #1 on: May 26, 2021, 12:41:54 pm »
If you don't mind being limited to Intel CPU assembly, use "CPUClocks"

PascalDragon

  • Hero Member
  • *****
  • Posts: 3339
  • Compiler Developer
Re: GetTickCount64 duplicate
« Reply #2 on: May 26, 2021, 01:16:28 pm »
I think the only explanation is that less than a millisecond passes between each pass of the loop.

Correct, that is the likely cause.

josh

  • Hero Member
  • *****
  • Posts: 819
Re: GetTickCount64 duplicate
« Reply #3 on: May 26, 2021, 01:35:20 pm »
Maybe something similar to below a global var and a funtion using it to make sure its unique.

Code: Pascal  [Select][+][-]
  1. //global vars
  2. var LastTick64:qword;
  3.  
  4. function UniqueTick64:string;
  5. begin
  6.   while LastTick64=GetTickCount64 do sleep(1);
  7.   LastTick64:=GetTickCount64;
  8.   Result:=inttostr(LastTick64);
  9. end;
  10.  
  11. .....
  12.  
  13.     n:=UniqueTick64;
  14.     MyPanel.Name:='Panel'+n;
  15.  

Development Installation Lazarus 1.3, FPC 2.7.1,Windows 7/8 32/64, OSX, *nix

Test Environment Lazarus & FPC Trunk on Windows and OSX (Cocoa Mainly on OSX). Testing also Crosscompile windows to OSX.. 
Any posts made from 2015 will be based on Lazarus Trunk.

ccrause

  • Sr. Member
  • ****
  • Posts: 435
Re: GetTickCount64 duplicate
« Reply #4 on: May 26, 2021, 01:38:32 pm »
I think the only explanation is that less than a millisecond passes between each pass of the loop.

Correct, that is the likely cause.

Indeed, the resolution of GetTickCount64 is 10 to 16 milliseconds.

creaothceann

  • Full Member
  • ***
  • Posts: 110
Re: GetTickCount64 duplicate
« Reply #5 on: May 26, 2021, 04:05:16 pm »
Note that a time value does not guarantee unique IDs. Why not use a counter instead?

---

If you don't mind being limited to Intel CPU assembly, use "CPUClocks"

"We strongly discourage using the RDTSC or RDTSCP processor instruction to directly query the TSC because you won't get reliable results on some versions of Windows, across live migrations of virtual machines, and on hardware systems without invariant or tightly synchronized TSCs."
- https://docs.microsoft.com/en-us/windows/win32/sysinfo/acquiring-high-resolution-time-stamps

Here's a wrapper:

Code: [Select]
unit U_HRT;

{
High-Resolution Timer
=====================

Windows: "[...] a high resolution (<1us) time stamp that can be used for time-interval measurements."


Notes:

InitialTick may be of limited value for timekeeping over longer durations (e.g. across host computer hibernations).
}

interface
uses
SysUtils;


type
HRT = class
private
class var
_InitialTick    : Int64;
_InitialTime    : TDateTime;
_TicksPerSecond : Int64;

class function  _Get_CurrentValue : Int64;  static;
class procedure _Init;                      static;

// API
public
class function TicksToSeconds(const Value : Int64) : Double;  static;

class property CurrentValue   : Int64      read _Get_CurrentValue;
class property InitialTick    : Int64      read _InitialTick;
class property InitialTime    : TDateTime  read _InitialTime;
class property TicksPerSecond : Int64      read _TicksPerSecond;
end;


function Seconds_to_TDateTime(const f : Double) : TDateTime;


implementation


function Seconds_to_TDateTime(const f : Double) : TDateTime;  inline;
begin
Result := f * 1000 / MSecsPerDay;  // freepascal.org/~michael/articles/datetime/datetime.pdf
end;


{$ifdef Windows}

function QueryPerformanceCounter  (out lpPerformanceCount : Int64) : LongBool;  external 'kernel32' name 'QueryPerformanceCounter';
function QueryPerformanceFrequency(out lpFrequency        : Int64) : LongBool;  external 'kernel32' name 'QueryPerformanceFrequency';


class function HRT._Get_CurrentValue : Int64;
begin
QueryPerformanceCounter(Result);
end;

{$endif}


class procedure HRT._Init;  inline;
begin
{$ifdef Windows}
QueryPerformanceFrequency(HRT._TicksPerSecond);
{$else}
//...
{$endif}
_InitialTick := CurrentValue;
_InitialTime := Now;
end;


class function HRT.TicksToSeconds(const Value : Int64) : Double;  inline;
begin
Result := Value / TicksPerSecond;
end;


initialization
HRT._Init;


end.
« Last Edit: May 26, 2021, 04:06:47 pm by creaothceann »

valter.home

  • Jr. Member
  • **
  • Posts: 75
Re: GetTickCount64 duplicate
« Reply #6 on: May 26, 2021, 05:01:34 pm »
Thank you guys,
a counter might perhaps be the safest way.
But I'm asking myself a question: is it mandatory to name components for components created at runtime? Because I don't really use the component name under any circumstances. Unlike the ide that assigns a sequential name to the component, at runtime the component name, if not assigned, is an empty string.
Could this cause random problems in running the application?

howardpc

  • Hero Member
  • *****
  • Posts: 3760
Re: GetTickCount64 duplicate
« Reply #7 on: May 26, 2021, 06:04:32 pm »
Leaving a dynamically created component unnamed is not a problem (unless, of course, your app depends in some way on your components having unique names, as, for instance,  the Lazarus IDE expects).

In a dynamic situation naming of components is mainly useful for debugging purposes, it is not mandatory at all.
The only thing that is mandatory is if you *do* name a dynamic component it must of course be a unique name. But if it isn't unique you get an immediate exception anyway, so it is never a hidden bug waiting to bite you.
« Last Edit: May 26, 2021, 07:49:54 pm by howardpc »

valter.home

  • Jr. Member
  • **
  • Posts: 75
Re: GetTickCount64 duplicate
« Reply #8 on: May 26, 2021, 06:19:59 pm »
Thanks howardpc,
your confirmation is welcome!
Less unnecessary code  :)

 

TinyPortal © 2005-2018