AuroraRuntime/Source/Time/AuClock.cpp

413 lines
12 KiB
C++
Raw Normal View History

2021-06-27 21:25:29 +00:00
/***
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: AuClock.cpp
2021-06-27 21:25:29 +00:00
Date: 2021-6-13
Author: Reece
Note: Screw it, std::chrono has been widly shilled at C++11s answer to all these painful macros, asm linkage, and all the other bullshit that pulling clock counters entails.
Semantics can and will continue to change over time. I remember when, in 2016 or something like that, msvcs implementation of chrono kept changing in minor ways.
However, every platform that remotely pretends to support a C++ toolchain has a chrono high performance clock, and any PC-like platform that uses clang and C++ more than likely uses a vendor hacked liblibc++ stl.
The following should be portable enough. Worst case scenario, you're on a platform with a platform-specific high res clock function you could hack into here alongside portable timezone-unaware timegm/mktime functions linked somewhere else.
There is so much quirky shit one has to deal with when relying on timestamp/cycle counters (cycle to ~time pred, plus positive delta, sometimes inlined assembly), it's just not worth it to
implement a CNTVCT_EL0 / RDSC / related interface ourselves.
[*/+/-] MEGA COMMIT. ~2 weeks compressed. The intention is to quickly improve and add util apis, enhance functionality given current demands, go back to the build pipeline, finish that, publish runtime tests, and then use what we have to go back to to linux support with a more stable api. [+] AuMakeSharedArray [+] Technet ArgvQuote [+] Grug subsystem (UNIX signal thread async safe ipc + telemetry flusher + log flusher.) [+] auEndianness -> Endian swap utils [+] AuGet<N>(...) [*] AUE_DEFINE conversion for ECompresionType, EAnsiColor, EHashType, EStreamError, EHexDump [+] ConsoleMessage ByteBuffer serialization [+] CmdLine subsystem for parsing command line arguments and simple switch/flag checks [*] Split logger from console subsystem [+] StartupParameters -> A part of a clean up effort under Process [*] Refactor SysErrors header + get caller hack [+] Atomic APIs [+] popcnt [+] Ring Buffer sink [+] Added more standard errors Catch, Submission, LockError, NoAccess, ResourceMissing, ResourceLocked, MalformedData, InSandboxContext, ParseError [+] Added ErrorCategorySet, ErrorCategoryClear, GetStackTrace [+] IExitSubscriber, ETriggerLevel [*] Write bias the high performance RWLockImpl read-lock operation operation [+] ExitHandlerAdd/ExitHandlerRemove (exit subsystem) [*] Updated API style Digests [+] CpuId::CpuBitCount [+] GetUserProgramsFolder [+] GetPackagePath [*] Split IStreamReader with an inl file [*] BlobWriter/BlobReader/BlobArbitraryReader can now take shared pointers to bytebuffers. default constructor allocates a new scalable bytebuffer [+] ICharacterProvider [+] ICharacterProviderEx [+] IBufferedCharacterConsumer [+] ProviderFromSharedString [+] ProviderFromString [+] BufferConsumerFromProvider [*] Parse Subsystem uses character io bufferer [*] Rewritten NT's high perf semaphore to use userland SRW/ConVars [like mutex, based on generic semaphore] [+] ByteBuffer::ResetReadPointer [*] Bug fix bytebuffer base not reset on free and some scaling issues [+] ProcessMap -> Added kSectionNameStack, kSectionNameFile, kSectionNameHeap for Section [*] ProcessMap -> Refactor Segment to Section. I was stupid for keeping a type conflict hack API facing [+] Added 64 *byte* fast RNG seeds [+] File Advisorys/File Lock Awareness [+] Added extended IAuroraThread from OS identifier caches for debug purposes [*] Tweaked how memory is reported on Windows. Better consistency of what values mean across functions. [*] Broke AuroraUtils/Typedefs out into a separate library [*] Update build script [+] Put some more effort into adding detail to the readme before rewriting it, plus, added some media [*] Improved public API documentation [*] Bug fix `SetConsoleCtrlHandler` [+] Locale TimeDateToFileNameISO8601 [+] Console config stdOutShortTime [*] Begin using internal UTF8/16 decoders when platform support isnt available (instead of stl) [*] Bug fixes in decoders [*] Major bug fix, AuMax [+] RateLimiter [+] Binary file sink [+] Log directory sink [*] Data header usability (more operators) [+] AuRemoveRange [+] AuRemove [+] AuTryRemove [+] AuTryRemoveRange [+] auCastUtils [+] Finish NewLSWin32Source [+] AuTryFindByTupleN, AuTryRemoveByTupleN [+] Separated AuRead/Write types, now in auTypeUtils [+] Added GetPosition/SetPosition to FileWriter [*] Fix stupid AuMin in place of AuMax in SpawnThread.Unix.Cpp [*] Refactored Arbitrary readers to SeekingReaders (as in, they could be atomic and/or parallelized, and accept an arbitrary position as a work parameter -> not Seekable, as in, you can simply set the position) [*] Hack back in the sched deinit [+] File AIO loop source interop [+] Begin to prototype a LoopQueue object I had in mind for NT, untested btw [+] Stub code for networking [+] Compression BaseStream/IngestableStreamBase [*] Major: read/write locks now support write-entrant read routines. [*] Compression subsystem now uses the MemoryView concept [*] Rewrite the base stream compressions, made them less broken [*] Update hashing api [*] WriterTryGoForward and ReaderTryGoForward now revert to the previous relative index instead of panicing [+] Added new AuByteBuffer apis Trim, Pad, WriteFrom, WriteString, [TODO: ReadString] [+] Added ByteBufferPushReadState [+] Added ByteBufferPushWriteState [*] Move from USC-16 to full UTF-16. Win32 can handle full UTF-16. [*] ELogLevel is now an Aurora enum [+] Raised arbitrary limit in header to 255, the max filter buffer [+] Explicit GZip support [+] Explicit Zip support [+] Added [some] compressors et al
2022-02-17 00:11:40 +00:00
I'll wave the white flag and use the STL in here for.now
2021-06-27 21:25:29 +00:00
***/
2021-09-30 14:57:41 +00:00
#include <Source/RuntimeInternal.hpp>
#include "AuClock.hpp"
2021-06-27 21:25:29 +00:00
#if defined(AURORA_IS_MODERNNT_DERIVED)
// TODO (Reece): ....
// benchmarking:
// https://github.com/microsoft/STL/issues/2085
struct steady_clock_fast
{ // wraps QueryPerformanceCounter
using rep = long long;
using period = std::nano;
using duration = std::chrono::nanoseconds;
using time_point = _CHRONO time_point<steady_clock_fast>;
static constexpr bool is_steady = true;
_NODISCARD static time_point now() noexcept
{ // get current time
static const long long _Freq = _Query_perf_frequency(); // doesn't change after system boot
const long long _Ctr = _Query_perf_counter();
static_assert(period::num == 1, "This assumes period::num == 1.");
// Instead of just having "(_Ctr * period::den) / _Freq",
// the algorithm below prevents overflow when _Ctr is sufficiently large.
// It assumes that _Freq * period::den does not overflow, which is currently true for nano period.
// It is not realistic for _Ctr to accumulate to large values from zero with this assumption,
// but the initial value of _Ctr could be large.
// 10 MHz is a very common QPC frequency on modern PCs. Optimizing for
// this specific frequency can double the performance of this function by
// avoiding the expensive frequency conversion path.
if (_Freq == 10000000)
{
return time_point(duration(_Ctr * 100));
}
else
{
const long long _Whole = (_Ctr / _Freq) * period::den;
const long long _Part = (_Ctr % _Freq) * period::den / _Freq;
return time_point(duration(_Whole + _Part));
}
}
};
// ~3.0741 seconds
using high_res_clock = steady_clock_fast;
// holy fuck, we're keeping this
// ~2x improvement
#else
// ~6.07 seconds
2021-06-27 21:25:29 +00:00
using high_res_clock = std::chrono::high_resolution_clock;
#endif
2021-06-27 21:25:29 +00:00
using sys_clock = std::chrono::system_clock;
using steady_clock = std::chrono::steady_clock;
2021-06-27 21:25:29 +00:00
#if defined(AURORA_PLATFORM_WIN32)
#define timegm _mkgmtime
2021-06-27 21:25:29 +00:00
#endif
static sys_clock::duration gEpoch;
static sys_clock::duration gUnixDelta;
static auto InitEpoch()
{
std::tm start{0, 15, 10, 29, 7, 101, 0, 0, 0};
2021-06-27 21:25:29 +00:00
auto epoch = sys_clock::from_time_t(timegm(&start)).time_since_epoch();
std::tm unixStart{};
unixStart.tm_mday = 1;
unixStart.tm_year = 70;
[*/+/-] MEGA COMMIT. ~2 weeks compressed. The intention is to quickly improve and add util apis, enhance functionality given current demands, go back to the build pipeline, finish that, publish runtime tests, and then use what we have to go back to to linux support with a more stable api. [+] AuMakeSharedArray [+] Technet ArgvQuote [+] Grug subsystem (UNIX signal thread async safe ipc + telemetry flusher + log flusher.) [+] auEndianness -> Endian swap utils [+] AuGet<N>(...) [*] AUE_DEFINE conversion for ECompresionType, EAnsiColor, EHashType, EStreamError, EHexDump [+] ConsoleMessage ByteBuffer serialization [+] CmdLine subsystem for parsing command line arguments and simple switch/flag checks [*] Split logger from console subsystem [+] StartupParameters -> A part of a clean up effort under Process [*] Refactor SysErrors header + get caller hack [+] Atomic APIs [+] popcnt [+] Ring Buffer sink [+] Added more standard errors Catch, Submission, LockError, NoAccess, ResourceMissing, ResourceLocked, MalformedData, InSandboxContext, ParseError [+] Added ErrorCategorySet, ErrorCategoryClear, GetStackTrace [+] IExitSubscriber, ETriggerLevel [*] Write bias the high performance RWLockImpl read-lock operation operation [+] ExitHandlerAdd/ExitHandlerRemove (exit subsystem) [*] Updated API style Digests [+] CpuId::CpuBitCount [+] GetUserProgramsFolder [+] GetPackagePath [*] Split IStreamReader with an inl file [*] BlobWriter/BlobReader/BlobArbitraryReader can now take shared pointers to bytebuffers. default constructor allocates a new scalable bytebuffer [+] ICharacterProvider [+] ICharacterProviderEx [+] IBufferedCharacterConsumer [+] ProviderFromSharedString [+] ProviderFromString [+] BufferConsumerFromProvider [*] Parse Subsystem uses character io bufferer [*] Rewritten NT's high perf semaphore to use userland SRW/ConVars [like mutex, based on generic semaphore] [+] ByteBuffer::ResetReadPointer [*] Bug fix bytebuffer base not reset on free and some scaling issues [+] ProcessMap -> Added kSectionNameStack, kSectionNameFile, kSectionNameHeap for Section [*] ProcessMap -> Refactor Segment to Section. I was stupid for keeping a type conflict hack API facing [+] Added 64 *byte* fast RNG seeds [+] File Advisorys/File Lock Awareness [+] Added extended IAuroraThread from OS identifier caches for debug purposes [*] Tweaked how memory is reported on Windows. Better consistency of what values mean across functions. [*] Broke AuroraUtils/Typedefs out into a separate library [*] Update build script [+] Put some more effort into adding detail to the readme before rewriting it, plus, added some media [*] Improved public API documentation [*] Bug fix `SetConsoleCtrlHandler` [+] Locale TimeDateToFileNameISO8601 [+] Console config stdOutShortTime [*] Begin using internal UTF8/16 decoders when platform support isnt available (instead of stl) [*] Bug fixes in decoders [*] Major bug fix, AuMax [+] RateLimiter [+] Binary file sink [+] Log directory sink [*] Data header usability (more operators) [+] AuRemoveRange [+] AuRemove [+] AuTryRemove [+] AuTryRemoveRange [+] auCastUtils [+] Finish NewLSWin32Source [+] AuTryFindByTupleN, AuTryRemoveByTupleN [+] Separated AuRead/Write types, now in auTypeUtils [+] Added GetPosition/SetPosition to FileWriter [*] Fix stupid AuMin in place of AuMax in SpawnThread.Unix.Cpp [*] Refactored Arbitrary readers to SeekingReaders (as in, they could be atomic and/or parallelized, and accept an arbitrary position as a work parameter -> not Seekable, as in, you can simply set the position) [*] Hack back in the sched deinit [+] File AIO loop source interop [+] Begin to prototype a LoopQueue object I had in mind for NT, untested btw [+] Stub code for networking [+] Compression BaseStream/IngestableStreamBase [*] Major: read/write locks now support write-entrant read routines. [*] Compression subsystem now uses the MemoryView concept [*] Rewrite the base stream compressions, made them less broken [*] Update hashing api [*] WriterTryGoForward and ReaderTryGoForward now revert to the previous relative index instead of panicing [+] Added new AuByteBuffer apis Trim, Pad, WriteFrom, WriteString, [TODO: ReadString] [+] Added ByteBufferPushReadState [+] Added ByteBufferPushWriteState [*] Move from USC-16 to full UTF-16. Win32 can handle full UTF-16. [*] ELogLevel is now an Aurora enum [+] Raised arbitrary limit in header to 255, the max filter buffer [+] Explicit GZip support [+] Explicit Zip support [+] Added [some] compressors et al
2022-02-17 00:11:40 +00:00
// dont care what the spec says, you can't trust some ms stls
// sys_clock can have its own epoch for all we care
auto nixEpoch = sys_clock::from_time_t(timegm(&unixStart)).time_since_epoch();
2021-06-27 21:25:29 +00:00
[*/+/-] MEGA COMMIT. ~2 weeks compressed. The intention is to quickly improve and add util apis, enhance functionality given current demands, go back to the build pipeline, finish that, publish runtime tests, and then use what we have to go back to to linux support with a more stable api. [+] AuMakeSharedArray [+] Technet ArgvQuote [+] Grug subsystem (UNIX signal thread async safe ipc + telemetry flusher + log flusher.) [+] auEndianness -> Endian swap utils [+] AuGet<N>(...) [*] AUE_DEFINE conversion for ECompresionType, EAnsiColor, EHashType, EStreamError, EHexDump [+] ConsoleMessage ByteBuffer serialization [+] CmdLine subsystem for parsing command line arguments and simple switch/flag checks [*] Split logger from console subsystem [+] StartupParameters -> A part of a clean up effort under Process [*] Refactor SysErrors header + get caller hack [+] Atomic APIs [+] popcnt [+] Ring Buffer sink [+] Added more standard errors Catch, Submission, LockError, NoAccess, ResourceMissing, ResourceLocked, MalformedData, InSandboxContext, ParseError [+] Added ErrorCategorySet, ErrorCategoryClear, GetStackTrace [+] IExitSubscriber, ETriggerLevel [*] Write bias the high performance RWLockImpl read-lock operation operation [+] ExitHandlerAdd/ExitHandlerRemove (exit subsystem) [*] Updated API style Digests [+] CpuId::CpuBitCount [+] GetUserProgramsFolder [+] GetPackagePath [*] Split IStreamReader with an inl file [*] BlobWriter/BlobReader/BlobArbitraryReader can now take shared pointers to bytebuffers. default constructor allocates a new scalable bytebuffer [+] ICharacterProvider [+] ICharacterProviderEx [+] IBufferedCharacterConsumer [+] ProviderFromSharedString [+] ProviderFromString [+] BufferConsumerFromProvider [*] Parse Subsystem uses character io bufferer [*] Rewritten NT's high perf semaphore to use userland SRW/ConVars [like mutex, based on generic semaphore] [+] ByteBuffer::ResetReadPointer [*] Bug fix bytebuffer base not reset on free and some scaling issues [+] ProcessMap -> Added kSectionNameStack, kSectionNameFile, kSectionNameHeap for Section [*] ProcessMap -> Refactor Segment to Section. I was stupid for keeping a type conflict hack API facing [+] Added 64 *byte* fast RNG seeds [+] File Advisorys/File Lock Awareness [+] Added extended IAuroraThread from OS identifier caches for debug purposes [*] Tweaked how memory is reported on Windows. Better consistency of what values mean across functions. [*] Broke AuroraUtils/Typedefs out into a separate library [*] Update build script [+] Put some more effort into adding detail to the readme before rewriting it, plus, added some media [*] Improved public API documentation [*] Bug fix `SetConsoleCtrlHandler` [+] Locale TimeDateToFileNameISO8601 [+] Console config stdOutShortTime [*] Begin using internal UTF8/16 decoders when platform support isnt available (instead of stl) [*] Bug fixes in decoders [*] Major bug fix, AuMax [+] RateLimiter [+] Binary file sink [+] Log directory sink [*] Data header usability (more operators) [+] AuRemoveRange [+] AuRemove [+] AuTryRemove [+] AuTryRemoveRange [+] auCastUtils [+] Finish NewLSWin32Source [+] AuTryFindByTupleN, AuTryRemoveByTupleN [+] Separated AuRead/Write types, now in auTypeUtils [+] Added GetPosition/SetPosition to FileWriter [*] Fix stupid AuMin in place of AuMax in SpawnThread.Unix.Cpp [*] Refactored Arbitrary readers to SeekingReaders (as in, they could be atomic and/or parallelized, and accept an arbitrary position as a work parameter -> not Seekable, as in, you can simply set the position) [*] Hack back in the sched deinit [+] File AIO loop source interop [+] Begin to prototype a LoopQueue object I had in mind for NT, untested btw [+] Stub code for networking [+] Compression BaseStream/IngestableStreamBase [*] Major: read/write locks now support write-entrant read routines. [*] Compression subsystem now uses the MemoryView concept [*] Rewrite the base stream compressions, made them less broken [*] Update hashing api [*] WriterTryGoForward and ReaderTryGoForward now revert to the previous relative index instead of panicing [+] Added new AuByteBuffer apis Trim, Pad, WriteFrom, WriteString, [TODO: ReadString] [+] Added ByteBufferPushReadState [+] Added ByteBufferPushWriteState [*] Move from USC-16 to full UTF-16. Win32 can handle full UTF-16. [*] ELogLevel is now an Aurora enum [+] Raised arbitrary limit in header to 255, the max filter buffer [+] Explicit GZip support [+] Explicit Zip support [+] Added [some] compressors et al
2022-02-17 00:11:40 +00:00
gUnixDelta = epoch - nixEpoch;
2021-06-27 21:25:29 +00:00
gEpoch = epoch;
return 0;
}
static auto ___ = InitEpoch();
template<typename T>
static inline T NormalizeEpoch(T sysEpoch)
{
return sysEpoch - gEpoch;
}
template<typename T>
static inline T DecodeEpoch(T auroraEpoch)
{
return auroraEpoch + gEpoch;
}
template<typename Clock_t, typename Duration_t>
static auto TimeFromDurationSinceEpoch(Duration_t in)
{
auto duration = std::chrono::duration_cast<typename Clock_t::duration>(in);
2021-06-27 21:25:29 +00:00
return std::chrono::time_point<Clock_t>(DecodeEpoch(duration));
}
template<typename Duration_t>
static time_t CalculateTimeT(AuUInt64 in)
{
return sys_clock::to_time_t(TimeFromDurationSinceEpoch<sys_clock>(Duration_t(in)));
}
namespace Aurora::Time
{
AUKN_SYM time_t SToCTime(AuInt64 time)
{
return CalculateTimeT<std::chrono::seconds>(time);
}
AUKN_SYM time_t NSToCTime(AuInt64 time)
{
return CalculateTimeT<std::chrono::nanoseconds>(time);
}
AUKN_SYM time_t MSToCTime(AuInt64 time)
{
return CalculateTimeT<std::chrono::milliseconds>(time);
}
AUKN_SYM AuInt64 CurrentClock()
2021-06-27 21:25:29 +00:00
{
return NormalizeEpoch(sys_clock::now().time_since_epoch()).count();
}
AUKN_SYM AuInt64 CurrentClockMS()
2021-06-27 21:25:29 +00:00
{
return std::chrono::duration_cast<std::chrono::milliseconds>(NormalizeEpoch(sys_clock::now().time_since_epoch())).count();
}
AUKN_SYM AuInt64 CurrentClockNS()
2021-06-27 21:25:29 +00:00
{
return std::chrono::duration_cast<std::chrono::nanoseconds>(NormalizeEpoch(sys_clock::now().time_since_epoch())).count();
}
AUKN_SYM AuUInt64 SteadyClock()
{
return SteadyClockNS();
}
AUKN_SYM AuUInt64 SteadyClockMS()
{
#if defined(AURORA_IS_POSIX_DERIVED)
::timespec spec {};
if (::clock_gettime(CLOCK_MONOTONIC, &spec) == 0)
{
return AuSToMS<AuUInt64>(spec.tv_sec) + AuNSToMS<AuUInt64>(spec.tv_nsec);
}
#endif
#if defined(AURORA_IS_MODERNNT_DERIVED)
return std::chrono::duration_cast<std::chrono::milliseconds>(high_res_clock::now().time_since_epoch()).count();
#endif
return std::chrono::duration_cast<std::chrono::milliseconds>(steady_clock::now().time_since_epoch()).count();
}
AUKN_SYM AuUInt64 SteadyClockNS()
{
#if defined(AURORA_IS_POSIX_DERIVED)
::timespec spec {};
if (::clock_gettime(CLOCK_MONOTONIC, &spec) == 0)
{
return AuMSToNS<AuUInt64>(AuSToMS<AuUInt64>(spec.tv_sec)) + (AuUInt64)spec.tv_nsec;
}
#endif
#if defined(AURORA_IS_MODERNNT_DERIVED)
return std::chrono::duration_cast<std::chrono::nanoseconds>(high_res_clock::now().time_since_epoch()).count();
#endif
return std::chrono::duration_cast<std::chrono::nanoseconds>(steady_clock::now().time_since_epoch()).count();
}
AUKN_SYM AuInt64 CTimeToMS(time_t time)
{
return std::chrono::duration_cast<std::chrono::milliseconds>(NormalizeEpoch(sys_clock::from_time_t(time).time_since_epoch())).count();
}
AUKN_SYM AuUInt64 HighResClock()
2021-06-27 21:25:29 +00:00
{
return high_res_clock::now().time_since_epoch().count();
}
AUKN_SYM AuUInt64 HighResClockMS()
2021-06-27 21:25:29 +00:00
{
#if defined(AURORA_IS_POSIX_DERIVED)
return SteadyClockMS();
#endif
2021-06-27 21:25:29 +00:00
return std::chrono::duration_cast<std::chrono::milliseconds>(high_res_clock::now().time_since_epoch()).count();
}
AUKN_SYM AuUInt64 HighResClockNS()
2021-06-27 21:25:29 +00:00
{
#if defined(AURORA_IS_POSIX_DERIVED)
return SteadyClockNS();
#endif
2021-06-27 21:25:29 +00:00
return std::chrono::duration_cast<std::chrono::nanoseconds>(high_res_clock::now().time_since_epoch()).count();
}
AUKN_SYM AuInt64 ConvertAuroraToUnixMS(AuInt64 in)
{
return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::milliseconds(in) + gUnixDelta).count();
}
AUKN_SYM AuInt64 ConvertAuroraToUnixNS(AuInt64 in)
{
return std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::nanoseconds(in) + gUnixDelta).count();
}
AUKN_SYM AuInt64 ConvertUnixToAuroraMS(AuInt64 in)
{
return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::milliseconds(in) - gUnixDelta).count();
}
AUKN_SYM AuInt64 ConvertUnixToAuroraNS(AuInt64 in)
{
return std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::nanoseconds(in) - gUnixDelta).count();
}
AUKN_SYM AuUInt64 ConvertInternalToAuroraEpochMS(AuUInt64 in)
{
static AuInt64 epochDelta = 0;
if (epochDelta == 0)
{
epochDelta = CurrentClockMS() - HighResClockMS();
2021-06-27 21:25:29 +00:00
}
return epochDelta + in;
}
AUKN_SYM AuUInt64 ConvertInternalToAuroraEpochNS(AuUInt64 in)
{
static AuInt64 epochDelta = 0;
if (epochDelta == 0)
{
epochDelta = CurrentClockNS() - HighResClockNS();
2021-06-27 21:25:29 +00:00
}
return epochDelta + in;
}
AUKN_SYM double CPUFrequencyDeltaNS()
{
static double frequency = 0;
if (frequency != 0)
{
return frequency;
}
return frequency = (static_cast<double>(high_res_clock::period::num) / static_cast<double>(high_res_clock::period::den) * 1'000'000'000.f);
}
AUKN_SYM double CPUFrequencyDeltaMS()
{
static double frequency = 0;
if (frequency != 0)
{
return frequency;
}
return frequency = (static_cast<double>(high_res_clock::period::num) / static_cast<double>(high_res_clock::period::den) * 1'000.f);
}
AUKN_SYM AuUInt64 SteadyClockJiffies()
{
static AuUInt64 frequency = 0;
if (frequency != 0)
{
return frequency;
}
#if defined(AURORA_COMPILER_MSVC)
return frequency = _Query_perf_frequency();
#endif
#if defined(AURORA_IS_POSIX_DERIVED)
::timespec spec {};
if (::clock_getres(CLOCK_MONOTONIC, &spec) == 0)
{
if (spec.tv_nsec && !spec.tv_sec)
{
return frequency = 1000000000ull / spec.tv_nsec;
}
}
#endif
return frequency = static_cast<double>(steady_clock::period::den) / static_cast<double>(steady_clock::period::num);
}
AUKN_SYM AuUInt64 HighResClockJiffies()
2021-06-27 21:25:29 +00:00
{
static AuUInt64 frequency = 0;
if (frequency != 0)
{
return frequency;
}
#if defined(AURORA_COMPILER_MSVC)
return frequency = _Query_perf_frequency();
#endif
#if defined(AURORA_IS_POSIX_DERIVED)
::timespec spec {};
if (::clock_getres(CLOCK_MONOTONIC, &spec) == 0)
{
if (spec.tv_nsec && !spec.tv_sec)
{
return frequency = 1000000000ull / spec.tv_nsec;
}
}
#endif
2021-06-27 21:25:29 +00:00
return frequency = static_cast<double>(high_res_clock::period::den) / static_cast<double>(high_res_clock::period::num);
}
AUKN_SYM tm ToCivilTime(AuInt64 time, bool UTC)
2021-06-27 21:25:29 +00:00
{
2022-03-08 01:36:12 +00:00
std::tm ret {};
2021-06-27 21:25:29 +00:00
auto timet = MSToCTime(time);
if (UTC)
{
2022-03-08 01:36:12 +00:00
#if defined(AURORA_COMPILER_MSVC)
2021-06-27 21:25:29 +00:00
auto tm = gmtime_s(&ret, &timet);
2022-03-08 01:36:12 +00:00
#else
auto tm = gmtime_r(&timet, &ret);
2022-03-08 01:36:12 +00:00
#endif
#if defined(AURORA_COMPILER_MSVC)
2021-06-27 21:25:29 +00:00
SysAssert(!tm, "couldn't convert civil time");
2022-03-08 01:36:12 +00:00
#else
2021-06-27 21:25:29 +00:00
SysAssert(tm, "couldn't convert civil time");
2022-03-08 01:36:12 +00:00
#endif
2021-06-27 21:25:29 +00:00
}
else
{
2022-03-08 01:36:12 +00:00
#if defined(AURORA_COMPILER_MSVC)
2021-06-27 21:25:29 +00:00
if (localtime_s(&ret, &timet))
#else
if (!localtime_r(&timet, &ret))
#endif
{
AuLogWarn("Couldn't convert local civil time");
return ToCivilTime(time, true);
2021-06-27 21:25:29 +00:00
}
}
tm _;
_.CopyFrom(ret);
return _;
2021-06-27 21:25:29 +00:00
}
AUKN_SYM AuInt64 FromCivilTime(const tm &time, bool UTC)
2021-06-27 21:25:29 +00:00
{
::tm tm;
2021-06-27 21:25:29 +00:00
time_t timet;
2022-03-08 01:36:12 +00:00
time.CopyTo(tm);
2021-06-27 21:25:29 +00:00
if (UTC)
{
tm.tm_isdst = 0;
timet = timegm(&tm);
}
else
{
tm.tm_isdst = -1; // out of the 2 crts i've bothered to check, out of 3, this is legal
2021-06-27 21:25:29 +00:00
timet = mktime(&tm);
}
2022-03-08 01:36:12 +00:00
2021-06-27 21:25:29 +00:00
if ((timet == 0) || (timet == -1))
{
return 0;
}
2022-03-08 01:36:12 +00:00
2021-06-27 21:25:29 +00:00
return std::chrono::duration_cast<std::chrono::milliseconds>(NormalizeEpoch(std::chrono::system_clock::from_time_t(timet).time_since_epoch())).count();
}
AUKN_SYM tm NormalizeCivilTimezone(const Time::tm &time, ETimezoneShift shift)
{
if ((time.tm_isdst == 0) && (shift == ETimezoneShift::eUTC))
{
return time;
}
return ToCivilTime(FromCivilTime(time, shift == ETimezoneShift::eUTC));
}
2022-03-08 01:36:12 +00:00
}