Guest Posted September 16, 2021 Found this solution in VCP, he also emulated it and used simple locking mechanism https://github.com/lakeofsoft/vcp/blob/87509e9ecc5ba1f09dcc5e1eba45b245c503edad/common/unaUtils.pas#L8518 Share this post Link to post
Guest Posted September 16, 2021 Well this still lingering in my head, i did this test and it looks working fine var PerformanceCounterFreq: Int64; function GetTickCountFromPerformanceCounter: UInt64; begin QueryPerformanceCounter(Int64(Result)); Result := Result div PerformanceCounterFreq; end; procedure TForm6.FormCreate(Sender: TObject); begin QueryPerformanceFrequency(PerformanceCounterFreq); PerformanceCounterFreq := PerformanceCounterFreq div 1000; end; procedure TForm6.Timer1Timer(Sender: TObject); begin Memo1.Lines.Add('Ticks : ' + IntToStr(GetTickCount) + ' Calc : ' + IntToStr(GetTickCountFromPerformanceCounter)); end; and the result Share this post Link to post
Fr0sT.Brutal 900 Posted September 16, 2021 1 hour ago, Kas Ob. said: Well this still lingering in my head, i did this test and it looks working fine How about performance? Share this post Link to post
Guest Posted September 16, 2021 20 minutes ago, Fr0sT.Brutal said: How about performance? QueryPerformanceCounter is also not system call just like GetTickCount and GetTickCount64, and the difference should be minimum, looking at the code in the kernel it is around few tens of cycle range in worst case. I don't think this should be a problem for supporting Windows XP, and it is lock free. Now i had the emulated version of GetTickCount64 from GetTickCount is lingering in my head, and i have know how to do it. Share this post Link to post
Guest Posted September 16, 2021 As base idea i came up with the following, might be buggy though, but in general and for what i care about the most, i can and will sleep tonight better. var GTickCountHighOf64: UInt64; // lower 32bit will be always zero GTickCountLastUpdated: Int64; GTickCountInterval: Int64; GTickLock: NativeUInt = 0; const GTC64EMU_CHECK_INTERVAL = 1000 * 60 * 5; // in ms = 5 minutes function GetTickCount64Emu: UInt64; procedure SpinLockForGTC(A: NativeUInt = 0; B: NativeUInt = 0); // parameters should be removed and replaced with registers asm // Compiles for 32bit and 64bit, we don't need PAUSE here as it will be always used for GTC64 short code mov B, 1 @LOOP: mov A, [GTickLock] test A, A jnz @LOOP LOCK cmpxchg[GTickLock], B jnz @LOOP end; var TickerDateNow, Freq: Int64; begin Result := GetTickCount; // Will check within the specified interval after System boot and every 49.7 days, this will last for GTC64EMU_CHECK_INTERVAL if Result < GTC64EMU_CHECK_INTERVAL then begin SpinLockForGTC; try // update the interval in high resolution counter this will happen only once, can be in different place like initialization if GTickCountInterval = 0 then begin QueryPerformanceFrequency(Freq); GTickCountInterval := Freq * (GTC64EMU_CHECK_INTERVAL * 1000) * 2; // *2 to make sure we are far from GTC64EMU_CHECK_INTERVAL end; QueryPerformanceCounter(TickerDateNow); // will be true once per 49.7 days if TickerDateNow + GTickCountInterval > GTickCountLastUpdated then begin GTickCountLastUpdated := TickerDateNow + GTickCountInterval; // ensure consequent (if) to be false Inc(GTickCountHighOf64, $100000000); end; finally GTickLock := 0; end; end; Result := Result or GTickCountHighOf64; end; Share this post Link to post
Remy Lebeau 1397 Posted September 16, 2021 10 hours ago, Kas Ob. said: That works and a good solution too, but my idea is to think something locking-free. I'm not sure this can be solved truly lock-free. Even if you make the low-part of the counter thread-local to avoid a lock, you still have the high-part of the counter to deal with to track rollovers, and that will have to be protected from concurrent access, either with a lock, or atomic access, etc. 10 hours ago, Kas Ob. said: But this introduce another problem, what if a thread created after 49 days from continuous running, then it will have different time by 2^32 ms, the solution is make the higher part of that ticker a global var and the lower part a local class field I really don't know if that will work or not. I think the entire counter needs to be global, so that new threads will start with the latest accumulated value properly. I'm thinking something like the following, based on ideas I've seen in other implementations: var TickCount64: UInt64 = 0; function GetTickCount64Emu: UInt64; var OrigValue, NewValue, TmpValue: UInt64; CurrTicks: UInt32; begin OrigValue := TInterlocked.Read(TickCount64); repeat CurrTicks := Windows.GetTickCount; NewValue := (OldValue and $FFFFFFFF00000000) + CurrTicks; if CurrTicks < UInt32(OrigValue and $FFFFFFFF) then Inc(NewValue, $100000000); TmpValue := TInterlocked.CompareExchange(TickCount64, NewValue, OrigValue); if OrigValue = TmpValue then Break; if TmpValue > NewValue then Exit(TmpValue); OrigValue := TmpValue; until False; Result := NewValue; end; 10 hours ago, Kas Ob. said: also i expect GetTickCount64 to be loaded dynamically, so if it does not exist then use the emulated one Yes, that would be required no matter what. 10 hours ago, Kas Ob. said: but on other hand declaring kernel function as delayed makes no sense at all as kernel is loaded always and delaying an import for it is simply wrong, Oh yeah, I forgot about that. Well, then just call GetProcAddress() manually at startup (or first call) instead of using 'delayed'. This is what Indy does. 1 Share this post Link to post
Guest Posted September 16, 2021 22 minutes ago, Remy Lebeau said: I really don't know if that will work or not. I think the entire counter needs to be global, so that new threads will start with the latest accumulated value properly. I'm thinking something like the following, based on ideas I've seen in other implementations: Nice ! and short. About using the full 64bit it can be it can be reduced to 32bit same as i did in last post, only i made it 64bit to remove shifting with OR. Also in your code, an interval to check and conditionally enter the loop will remove the overhead leaving it for few minutes every very long time, in other words the carry increment will only happen in well predictable time range. 27 minutes ago, Remy Lebeau said: Oh yeah, I forgot about that. Well, then just call GetProcAddress() manually at startup (or first call) instead of using 'delayed'. This is what Indy does. My point there is about the wrong doing by Delphi RTL, this most likely will increase the irritation of AV seeing delayed call for a dll that already imported statically specially for kernel API's, AV will mark these as might be injected and wasn't done by a legit compiler/linker. Share this post Link to post
Remy Lebeau 1397 Posted September 16, 2021 (edited) 13 hours ago, Kas Ob. said: I don't see GetTickCount64 in Seattle, so if someone with higher version can shed some light on how it is declared, if it is delayed then it should be fixed, and replaced with dynamic address resolving, later to use it in TThread it could depend on its pointer value instead of TOSVersion. From RSP-35459: Quote GetTickCount64 is marked as delayed: Edited September 16, 2021 by Remy Lebeau Share this post Link to post
Remy Lebeau 1397 Posted September 16, 2021 6 hours ago, Kas Ob. said: Well this still lingering in my head, i did this test and it looks working fine The problem with using QueryPerformanceCounter()/QueryPerformanceFrequency() is that it is not consistent on all systems, especially on multi-core systems, or systems without a stable TSC (Mozilla had to write code to work around that for https://bugzilla.mozilla.org/show_bug.cgi?id=784859). That is the main reason Indy stopped using QPC/QPF over a decade ago for the implementation of its Ticks/64() functions, now favoring GetTickCount64() instead (use of QPC/QPF can be re-enabed with a compiler define). Share this post Link to post
Joseph MItzen 251 Posted September 17, 2021 On 9/14/2021 at 8:52 AM, Vandrovnik said: From my point of view, compatibility with old versions of Windows is one of important benefits of applications written in Delphi. If they broke this compatibility just because of GetTickCount64, they are throwing this benefit away needlessly. Compatibility with versions of Windows that are no longer supported though? Share this post Link to post
Joseph MItzen 251 Posted September 17, 2021 On 9/14/2021 at 11:15 AM, Dmitry Arefiev said: Not at all. Why the heck not? Why waste resources supporting dead operating systems? Quote As of July 2021, 0.58% of Windows PCs run Windows XP (on all continents the share is below 1%), and 0.18% of all devices across all platforms run Windows XP. Share this post Link to post
Darian Miller 361 Posted September 17, 2021 46 minutes ago, Joseph MItzen said: As of July 2021, 0.58% of Windows PCs run Windows XP (on all continents the share is below 1%), and 0.18% of all devices across all platforms run Windows XP. I think that number is probably underestimated as many of the XP machines aren't connecting to the internet. Just busy running 24x7 on a factory floor somewhere, in a kiosk, or cash register. (Not to mention all the Windows XP still in use by government and military) 4 Share this post Link to post
Guest Posted September 17, 2021 1 hour ago, Darian Miller said: I think that number is probably underestimated as many of the XP machines aren't connecting to the internet. Just busy running 24x7 on a factory floor somewhere, in a kiosk, or cash register. (Not to mention all the Windows XP still in use by government and military) May be not underestimated but more like underweighted, https://theconversation.com/airports-atms-hospitals-microsoft-windows-xp-leak-would-be-less-of-an-issue-if-so-many-didnt-use-it-147018 I know for sure that huge numbers of ATM machines in the world are still running Windows XP. Found this, Though the following article is from 2014, but still relevant, i my self worked on a project two years ago to update a software running on both XP and 98, the client has huge amount of PC and their spare parts and they are working fine, but the limitation of their technology prevent him from using newer software, and the astonishing cost to update the hardware (working fine and doing-its-job-perfectly hardware) doesn't justify cost, for the owner is way cheaper to update his software, even if it called legacy. https://www.computerworld.com/article/2700811/95-percent-of-atms-run-windows-xp--here-s-everything-you-need-to-know-about-the-security-threat.html My bank now in 2021, and judging by how the forms, icons, buttons and controls looks, still running software that is compiled either Delphi 5 or Delphi 6. Share this post Link to post
Anders Melander 1784 Posted September 17, 2021 4 hours ago, Darian Miller said: I think that number is probably underestimated as many of the XP machines aren't connecting to the internet. Just busy running 24x7 on a factory floor somewhere, in a kiosk, or cash register. (Not to mention all the Windows XP still in use by government and military) You are probably right on that, but do the software running on those systems really need to be supported by Delphi 11? I doubt it. Share this post Link to post
Vandrovnik 214 Posted September 17, 2021 9 hours ago, Joseph MItzen said: Compatibility with versions of Windows that are no longer supported though? In fact, these unsupported machines created no problem this year, while supported Windows 10 created a few of problems, one of them really serious (after one actualization, printing to Kyocera printers resulted in BSOD). Share this post Link to post
Lars Fosdal 1792 Posted September 17, 2021 That is not a Windows 10 problem. That is a Kyocera printer driver problem. Share this post Link to post
Vandrovnik 214 Posted September 17, 2021 (edited) 13 minutes ago, Lars Fosdal said: That is not a Windows 10 problem. That is a Kyocera printer driver problem. No, it was Windows problem (affecting Kyocera and a few others). https://www.windowslatest.com/2021/03/10/windows-10-kb5000802-march-update-is-crashing-pcs-with-bsod/ https://www.kyoceradocumentsolutions.com/asia/en/about-us/press/20210317_news.html Edited September 17, 2021 by Vandrovnik Share this post Link to post
Lars Fosdal 1792 Posted September 17, 2021 Ah, ok. Now I recall that incident. With XP no longer getting patches, I am not sure if that qualifies it as more stable? Share this post Link to post
Alexander Elagin 143 Posted September 17, 2021 15 minutes ago, Lars Fosdal said: With XP no longer getting patches, I am not sure if that qualifies it as more stable? It is more stable in the configurations it is being used now. If nothing in the OS has broken thus far and no updates expected which can break something (as it regularily happens with "supported" OSes) I'd say XP machines will run until they break physically. Again, those computers are mostly not exposed to internet and are therefore not vulnerable to net exploits. Share this post Link to post
Lars Fosdal 1792 Posted September 17, 2021 3 minutes ago, Alexander Elagin said: mostly not exposed to internet and are therefore not vulnerable to net exploits. Frequently, that turns out to be a myth. Share this post Link to post
FredS 138 Posted September 17, 2021 11 hours ago, Darian Miller said: probably underestimated Yup, I have one running but don't expect newer versions of Delphi to be practical for any updates to that code.. Share this post Link to post
FredS 138 Posted September 17, 2021 1 hour ago, Alexander Elagin said: XP machines will run until they break physically The VMware slogan was: Run XP forever.. Share this post Link to post
Darian Miller 361 Posted September 17, 2021 4 hours ago, Lars Fosdal said: Frequently, that turns out to be a myth. And frequently it happens to be true. Share this post Link to post
Darian Miller 361 Posted September 17, 2021 9 hours ago, Anders Melander said: You are probably right on that, but do the software running on those systems really need to be supported by Delphi 11? I doubt it. No, not really except you simply have another version of Delphi to support, which is typically another VM to keep around. It would be nice to delete the old Delphi VM and simply use the latest version of RAD Studio to support all of your projects, including the ancient ones. I know that's a big ask but in this case, it's not a major change to allow that to happen. 1 Share this post Link to post
Anders Melander 1784 Posted September 17, 2021 29 minutes ago, Darian Miller said: I know that's a big ask but in this case, it's not a major change to allow that to happen. Sure, except you simply have another version of Windows to support, which is typically another VM to keep around. It would be nice to delete the old Windows VM and simply use the latest version of Windows to support all of your projects, including the ancient ones. Share this post Link to post