[+] Process and threaded user and kernel time keeping clocks
This commit is contained in:
parent
2d6dca4e21
commit
47746de462
@ -13,6 +13,10 @@ namespace Aurora::Time
|
||||
eWall,
|
||||
eSteady,
|
||||
eProcessTime,
|
||||
eThreadTime
|
||||
eProcessKernelTime,
|
||||
eProcessUserTime,
|
||||
eThreadTime,
|
||||
eThreadKernelTime,
|
||||
eThreadUserTime
|
||||
))
|
||||
}
|
@ -91,19 +91,19 @@ namespace Aurora::Time
|
||||
AUKN_SYM AuUInt64 ThreadClockJiffies();
|
||||
|
||||
/**
|
||||
* @brief time spent in userspace under this context [in jiffies]
|
||||
* @brief time spent in userspace and in the kernel under this thread [in jiffies]
|
||||
* @return
|
||||
*/
|
||||
AUKN_SYM AuUInt64 ThreadClock();
|
||||
|
||||
/**
|
||||
* @brief time spent in userspace under this context [in nanoseconds]
|
||||
* @brief time spent in userspace and in the kernel under this thread [in nanoseconds]
|
||||
* @return
|
||||
*/
|
||||
AUKN_SYM AuUInt64 ThreadClockNS();
|
||||
|
||||
/**
|
||||
* @brief time spent in userspace under this context [in milliseconds]
|
||||
* @brief time spent in userspace and in the kernel under this thread [in milliseconds]
|
||||
* @return
|
||||
*/
|
||||
AUKN_SYM AuUInt64 ThreadClockMS();
|
||||
@ -132,6 +132,30 @@ namespace Aurora::Time
|
||||
*/
|
||||
AUKN_SYM AuUInt64 ProcessClockMS();
|
||||
|
||||
// Advanced clocks: ////////////////////////
|
||||
|
||||
AUKN_SYM AuUInt64 ThreadUserClock();
|
||||
AUKN_SYM AuUInt64 ThreadUserClockNS();
|
||||
AUKN_SYM AuUInt64 ThreadUserClockMS();
|
||||
AUKN_SYM AuUInt64 ThreadUserClockJiffies();
|
||||
|
||||
AUKN_SYM AuUInt64 ProcessUserClock();
|
||||
AUKN_SYM AuUInt64 ProcessUserClockNS();
|
||||
AUKN_SYM AuUInt64 ProcessUserClockMS();
|
||||
AUKN_SYM AuUInt64 ProcessUserClockJiffies();
|
||||
|
||||
AUKN_SYM AuUInt64 ThreadKernelClock();
|
||||
AUKN_SYM AuUInt64 ThreadKernelClockNS();
|
||||
AUKN_SYM AuUInt64 ThreadKernelClockMS();
|
||||
AUKN_SYM AuUInt64 ThreadKernelClockJiffies();
|
||||
|
||||
AUKN_SYM AuUInt64 ProcessKernelClock();
|
||||
AUKN_SYM AuUInt64 ProcessKernelClockNS();
|
||||
AUKN_SYM AuUInt64 ProcessKernelClockMS();
|
||||
AUKN_SYM AuUInt64 ProcessKernelClockJiffies();
|
||||
|
||||
////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
Converts seconds from the Aurora epoch to time_t
|
||||
*/
|
||||
@ -167,12 +191,36 @@ namespace Aurora::Time
|
||||
*/
|
||||
AUKN_SYM AuSPtr<IClock> GetProcessClock();
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
AUKN_SYM AuSPtr<IClock> GetProcessUserClock();
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
AUKN_SYM AuSPtr<IClock> GetProcessKernelLock();
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
AUKN_SYM AuSPtr<IClock> GetThreadClock();
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
AUKN_SYM AuSPtr<IClock> GetThreadUserClock();
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @return
|
||||
*/
|
||||
AUKN_SYM AuSPtr<IClock> GetThreadKernelLock();
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* @param clock
|
||||
|
@ -4,16 +4,6 @@
|
||||
File: AuClock.cpp
|
||||
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.
|
||||
|
||||
I'll wave the white flag and use the STL in here for.now
|
||||
***/
|
||||
#include <Source/RuntimeInternal.hpp>
|
||||
#include "AuClock.hpp"
|
||||
@ -219,177 +209,161 @@ namespace Aurora::Time
|
||||
return std::chrono::duration_cast<std::chrono::nanoseconds>(NormalizeEpoch(std::chrono::nanoseconds(time))).count();
|
||||
}
|
||||
|
||||
AUKN_SYM AuUInt64 ThreadClockNS()
|
||||
{
|
||||
#if defined(AURORA_IS_POSIX_DERIVED)
|
||||
::timespec spec {};
|
||||
if (::clock_gettime(CLOCK_THREAD_CPUTIME_ID, &spec) == 0)
|
||||
{
|
||||
return AuMSToNS<AuUInt64>(AuSToMS<AuUInt64>(spec.tv_sec)) + (AuUInt64)spec.tv_nsec;
|
||||
}
|
||||
#endif
|
||||
#if defined(AURORA_IS_MODERNNT_DERIVED)
|
||||
|
||||
#if defined(AURORA_IS_MODERNNT_DERIVED)
|
||||
FILETIME creation, exit, kernel, user;
|
||||
if (::GetThreadTimes(GetCurrentThread(), &creation, &exit, &kernel, &user))
|
||||
{
|
||||
// i dont want to measure kernel and driver overhead under benchmarks, i dont think
|
||||
// im going to consider kernel time = syscalls = ipc to another sandbox/process/thread until i have a reason to change this
|
||||
// primary use case: microbenchmarks that dont care for external noise
|
||||
ULARGE_INTEGER ullUser;
|
||||
ullUser.LowPart = user.dwLowDateTime;
|
||||
ullUser.HighPart = user.dwHighDateTime;
|
||||
return ullUser.QuadPart * 100ull;
|
||||
}
|
||||
#endif
|
||||
|
||||
return HighResClockNS();
|
||||
#define ADD_CLOCK_FAMILY(fn, type, expr, posixId) \
|
||||
AUKN_SYM AuUInt64 fn ## ClockJiffies(); \
|
||||
\
|
||||
AUKN_SYM AuUInt64 fn ## ClockMS() \
|
||||
{ \
|
||||
return AuNSToMS<AuUInt64>(fn ## ClockNS()); \
|
||||
} \
|
||||
\
|
||||
AUKN_SYM AuUInt64 fn ## ClockNS() \
|
||||
{ \
|
||||
FILETIME creation, exit, kernel, user; \
|
||||
if (::Get ## type ## Times(GetCurrent ## type(), &creation, &exit, &kernel, &user)) \
|
||||
{ \
|
||||
ULARGE_INTEGER ullUser; \
|
||||
{ \
|
||||
ullUser.LowPart = user.dwLowDateTime; \
|
||||
ullUser.HighPart = user.dwHighDateTime; \
|
||||
} \
|
||||
\
|
||||
ULARGE_INTEGER ullKernel; \
|
||||
{ \
|
||||
ullKernel.LowPart = kernel.dwLowDateTime; \
|
||||
ullKernel.HighPart = kernel.dwHighDateTime; \
|
||||
} \
|
||||
return (expr) * 100ull; \
|
||||
} \
|
||||
return HighResClockNS(); \
|
||||
} \
|
||||
\
|
||||
AUKN_SYM AuUInt64 fn ## Clock() \
|
||||
{ \
|
||||
FILETIME creation, exit, kernel, user; \
|
||||
\
|
||||
if (::Get ## type ## Times(GetCurrent ## type(), &creation, &exit, &kernel, &user)) \
|
||||
{ \
|
||||
ULARGE_INTEGER ullUser; \
|
||||
{ \
|
||||
ullUser.LowPart = user.dwLowDateTime; \
|
||||
ullUser.HighPart = user.dwHighDateTime; \
|
||||
} \
|
||||
\
|
||||
ULARGE_INTEGER ullKernel; \
|
||||
{ \
|
||||
ullKernel.LowPart = kernel.dwLowDateTime; \
|
||||
ullKernel.HighPart = kernel.dwHighDateTime; \
|
||||
} \
|
||||
return expr; \
|
||||
} \
|
||||
\
|
||||
return fn ##ClockNS() / (1000000000ull / fn ## ClockJiffies()); \
|
||||
} \
|
||||
\
|
||||
AUKN_SYM AuUInt64 fn ## ClockJiffies() \
|
||||
{ \
|
||||
return 1000000000ull / 100u; \
|
||||
}
|
||||
|
||||
AUKN_SYM AuUInt64 ThreadClockMS()
|
||||
{
|
||||
return AuNSToMS<AuUInt64>(ThreadClockNS());
|
||||
#elif defined(AURORA_IS_POSIX_DERIVED)
|
||||
|
||||
#define ADD_CLOCK_FAMILY(fn, type, expr, posixId) \
|
||||
AUKN_SYM AuUInt64 fn ## ClockJiffies(); \
|
||||
\
|
||||
AUKN_SYM AuUInt64 fn ## ClockMS() \
|
||||
{ \
|
||||
if (!posixId) \
|
||||
{ \
|
||||
return {}; \
|
||||
} \
|
||||
return AuNSToMS<AuUInt64>(fn ## ClockNS()); \
|
||||
} \
|
||||
\
|
||||
AUKN_SYM AuUInt64 fn ## ClockNS() \
|
||||
{ \
|
||||
if (!posixId) \
|
||||
{ \
|
||||
return {}; \
|
||||
} \
|
||||
::timespec spec {}; \
|
||||
if (::clock_gettime(posixId, &spec) == 0) \
|
||||
{ \
|
||||
return AuMSToNS<AuUInt64>(AuSToMS<AuUInt64>(spec.tv_sec)) + (AuUInt64)spec.tv_nsec; \
|
||||
} \
|
||||
return HighResClockNS(); \
|
||||
} \
|
||||
\
|
||||
AUKN_SYM AuUInt64 fn ## Clock() \
|
||||
{ \
|
||||
if (!posixId) \
|
||||
{ \
|
||||
return {}; \
|
||||
} \
|
||||
return fn ##ClockNS() / (1000000000ull / fn ## ClockJiffies()); \
|
||||
} \
|
||||
\
|
||||
AUKN_SYM AuUInt64 fn ## ClockJiffies() \
|
||||
{ \
|
||||
if (!posixId) \
|
||||
{ \
|
||||
return {}; \
|
||||
} \
|
||||
static AuUInt64 frequency = 0; \
|
||||
if (frequency != 0) \
|
||||
{ \
|
||||
return frequency; \
|
||||
} \
|
||||
\
|
||||
::timespec spec {}; \
|
||||
if (::clock_getres(posixId, &spec) == 0) \
|
||||
{ \
|
||||
if (spec.tv_nsec && !spec.tv_sec) \
|
||||
{ \
|
||||
return frequency = 1000000000ull / spec.tv_nsec; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
SysUnreachable(); \
|
||||
return 0; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
return HighResClockJiffies(); \
|
||||
}
|
||||
|
||||
AUKN_SYM AuUInt64 ThreadClock()
|
||||
{
|
||||
#if defined(AURORA_IS_MODERNNT_DERIVED)
|
||||
FILETIME creation, exit, kernel, user;
|
||||
if (::GetThreadTimes(GetCurrentThread(), &creation, &exit, &kernel, &user))
|
||||
{
|
||||
ULARGE_INTEGER ull;
|
||||
ull.LowPart = user.dwLowDateTime;
|
||||
ull.HighPart = user.dwHighDateTime;
|
||||
return ull.QuadPart;
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
|
||||
return ThreadClockNS() / (1000000000ull / ThreadClockJiffies());
|
||||
AUKN_SYM AuUInt64 fn ## ClockMS()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
AUKN_SYM AuUInt64 ThreadClockJiffies()
|
||||
AUKN_SYM AuUInt64 fn ## ClockNS()
|
||||
{
|
||||
#if defined(AURORA_IS_MODERNNT_DERIVED)
|
||||
return 1000000000ull / 100u;
|
||||
#endif
|
||||
|
||||
static AuUInt64 frequency = 0;
|
||||
if (frequency != 0)
|
||||
{
|
||||
return frequency;
|
||||
}
|
||||
|
||||
#if defined(AURORA_IS_POSIX_DERIVED)
|
||||
::timespec spec {};
|
||||
if (::clock_getres(CLOCK_THREAD_CPUTIME_ID, &spec) == 0)
|
||||
{
|
||||
if (spec.tv_nsec && !spec.tv_sec)
|
||||
{
|
||||
return frequency = 1000000000ull / spec.tv_nsec;
|
||||
}
|
||||
else
|
||||
{
|
||||
SysUnreachable();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return HighResClockJiffies();
|
||||
return 0;
|
||||
}
|
||||
|
||||
AUKN_SYM AuUInt64 ProcessClockNS()
|
||||
AUKN_SYM AuUInt64 fn ## Clock()
|
||||
{
|
||||
#if defined(AURORA_IS_POSIX_DERIVED)
|
||||
::timespec spec {};
|
||||
if (::clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &spec) == 0)
|
||||
{
|
||||
return AuMSToNS<AuUInt64>(AuSToMS<AuUInt64>(spec.tv_sec)) + (AuUInt64)spec.tv_nsec;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(AURORA_IS_MODERNNT_DERIVED)
|
||||
FILETIME creation, exit, kernel, user;
|
||||
if (::GetProcessTimes(GetCurrentProcess(), &creation, &exit, &kernel, &user))
|
||||
{
|
||||
ULARGE_INTEGER ullUser;
|
||||
{
|
||||
ullUser.LowPart = user.dwLowDateTime;
|
||||
ullUser.HighPart = user.dwHighDateTime;
|
||||
}
|
||||
|
||||
ULARGE_INTEGER ullKernel;
|
||||
{
|
||||
ullKernel.LowPart = kernel.dwLowDateTime;
|
||||
ullKernel.HighPart = kernel.dwHighDateTime;
|
||||
}
|
||||
return (ullUser.QuadPart + ullKernel.QuadPart) * 100ull;
|
||||
}
|
||||
#endif
|
||||
|
||||
return HighResClockNS();
|
||||
return 0;
|
||||
}
|
||||
|
||||
AUKN_SYM AuUInt64 ProcessClockMS()
|
||||
AUKN_SYM AuUInt64 fn ## ClockJiffies()
|
||||
{
|
||||
return AuNSToMS<AuUInt64>(ProcessClockNS());
|
||||
return 0;
|
||||
}
|
||||
|
||||
AUKN_SYM AuUInt64 ProcessClock()
|
||||
{
|
||||
#if defined(AURORA_IS_MODERNNT_DERIVED)
|
||||
FILETIME creation, exit, kernel, user;
|
||||
#endif
|
||||
|
||||
if (::GetProcessTimes(GetCurrentProcess(), &creation, &exit, &kernel, &user))
|
||||
{
|
||||
ULARGE_INTEGER ullUser;
|
||||
{
|
||||
ullUser.LowPart = user.dwLowDateTime;
|
||||
ullUser.HighPart = user.dwHighDateTime;
|
||||
}
|
||||
|
||||
ULARGE_INTEGER ullKernel;
|
||||
{
|
||||
ullKernel.LowPart = kernel.dwLowDateTime;
|
||||
ullKernel.HighPart = kernel.dwHighDateTime;
|
||||
}
|
||||
return ullUser.QuadPart + ullKernel.QuadPart;
|
||||
}
|
||||
#endif
|
||||
|
||||
return ProcessClockNS() / (1000000000ull / ProcessClockJiffies());
|
||||
}
|
||||
|
||||
AUKN_SYM AuUInt64 ProcessClockJiffies()
|
||||
{
|
||||
#if defined(AURORA_IS_MODERNNT_DERIVED)
|
||||
return 1000000000ull / 100u;
|
||||
#endif
|
||||
|
||||
static AuUInt64 frequency = 0;
|
||||
if (frequency != 0)
|
||||
{
|
||||
return frequency;
|
||||
}
|
||||
|
||||
#if defined(AURORA_IS_POSIX_DERIVED)
|
||||
::timespec spec {};
|
||||
if (::clock_getres(CLOCK_PROCESS_CPUTIME_ID, &spec) == 0)
|
||||
{
|
||||
if (spec.tv_nsec && !spec.tv_sec)
|
||||
{
|
||||
return frequency = 1000000000ull / spec.tv_nsec;
|
||||
}
|
||||
else
|
||||
{
|
||||
SysUnreachable();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return HighResClockJiffies();
|
||||
}
|
||||
ADD_CLOCK_FAMILY(Process, Process, (ullUser.QuadPart + ullKernel.QuadPart), CLOCK_PROCESS_CPUTIME_ID);
|
||||
ADD_CLOCK_FAMILY(ProcessKernel, Process, (ullKernel.QuadPart), 0);
|
||||
ADD_CLOCK_FAMILY(ProcessUser, Process, (ullUser.QuadPart), CLOCK_PROCESS_CPUTIME_ID);
|
||||
ADD_CLOCK_FAMILY(Thread, Thread, (ullUser.QuadPart + ullKernel.QuadPart), CLOCK_THREAD_CPUTIME_ID);
|
||||
ADD_CLOCK_FAMILY(ThreadKernel, Thread, (ullKernel.QuadPart), 0);
|
||||
ADD_CLOCK_FAMILY(ThreadUser, Thread, (ullUser.QuadPart), CLOCK_THREAD_CPUTIME_ID);
|
||||
|
||||
AUKN_SYM AuInt64 ConvertAuroraToUnixMS(AuInt64 in)
|
||||
{
|
||||
@ -459,9 +433,9 @@ namespace Aurora::Time
|
||||
{
|
||||
#if defined(AURORA_COMPILER_MSVC)
|
||||
if (localtime_s(&ret, &timet))
|
||||
#else
|
||||
#else
|
||||
if (!localtime_r(&timet, &ret))
|
||||
#endif
|
||||
#endif
|
||||
{
|
||||
SysPushErrorGeneric("Couldn't convert local civil time");
|
||||
return ToCivilTime(time, true);
|
||||
|
@ -46,7 +46,11 @@ namespace Aurora::Time
|
||||
ADD_CLOCK(Steady, eSteady, SteadyClockJiffies, SteadyClockNS, SteadyClockMS);
|
||||
ADD_CLOCK(Wall, eWall, FILE_AND_USR_DIR_STEP + AuUInt64, CurrentClockNS, CurrentClockMS);
|
||||
ADD_CLOCK(Process, eProcessTime, ProcessClockJiffies, ProcessClockNS, ProcessClockMS);
|
||||
ADD_CLOCK(ProcessKernel, eProcessKernelTime, ProcessKernelClockJiffies, ProcessKernelClockNS, ProcessKernelClockMS);
|
||||
ADD_CLOCK(ProcessUser, eProcessUserTime, ProcessUserClockJiffies, ProcessUserClockNS, ProcessUserClockMS);
|
||||
ADD_CLOCK(Thread, eThreadTime, ThreadClockJiffies, ThreadClockNS, ThreadClockMS);
|
||||
ADD_CLOCK(ThreadKernel, eThreadKernelTime, ThreadKernelClockJiffies, ThreadKernelClockNS, ThreadKernelClockMS);
|
||||
ADD_CLOCK(ThreadUser, eThreadUserTime, ThreadUserClockJiffies, ThreadUserClockNS, ThreadUserClockMS);
|
||||
|
||||
#undef FILE_AND_USR_DIR_STEP
|
||||
#undef ADD_CLOCK
|
||||
@ -57,12 +61,20 @@ namespace Aurora::Time
|
||||
{
|
||||
case EClock::eWall:
|
||||
return GetWallClock();
|
||||
case EClock::eProcessTime:
|
||||
return GetProcessClock();
|
||||
case EClock::eThreadTime:
|
||||
return GetProcessClock();
|
||||
case EClock::eSteady:
|
||||
return GetSteadyClock();
|
||||
case EClock::eProcessTime:
|
||||
return GetProcessClock();
|
||||
case EClock::eProcessUserTime:
|
||||
return GetProcessUserClock();
|
||||
case EClock::eProcessKernelTime:
|
||||
return GetProcessKernelClock();
|
||||
case EClock::eThreadTime:
|
||||
return GetThreadClock();
|
||||
case EClock::eThreadUserTime:
|
||||
return GetThreadUserClock();
|
||||
case EClock::eThreadKernelTime:
|
||||
return GetThreadKernelClock();
|
||||
default:
|
||||
SysPushErrorArg("Invalid clock");
|
||||
return {};
|
||||
|
Loading…
Reference in New Issue
Block a user