diff options
| author | Martin Ridgers <[email protected]> | 2021-10-01 11:50:43 +0200 |
|---|---|---|
| committer | Martin Ridgers <[email protected]> | 2021-10-01 11:50:43 +0200 |
| commit | a2dc648979bad70037e19ce75ae506f9455e8fd3 (patch) | |
| tree | 4d902270db982a24df05eecdf53d0535b601d582 /zencore/include | |
| parent | Removed `-fshort-wchar` compiler flag on Linux (diff) | |
| parent | Added upstream cache perf metrics. (diff) | |
| download | zen-a2dc648979bad70037e19ce75ae506f9455e8fd3.tar.xz zen-a2dc648979bad70037e19ce75ae506f9455e8fd3.zip | |
Merged main
Diffstat (limited to 'zencore/include')
| -rw-r--r-- | zencore/include/zencore/iobuffer.h | 9 | ||||
| -rw-r--r-- | zencore/include/zencore/refcount.h | 2 | ||||
| -rw-r--r-- | zencore/include/zencore/stats.h | 146 | ||||
| -rw-r--r-- | zencore/include/zencore/thread.h | 20 | ||||
| -rw-r--r-- | zencore/include/zencore/timer.h | 20 |
5 files changed, 157 insertions, 40 deletions
diff --git a/zencore/include/zencore/iobuffer.h b/zencore/include/zencore/iobuffer.h index 54801f9ac..36ecbd9a7 100644 --- a/zencore/include/zencore/iobuffer.h +++ b/zencore/include/zencore/iobuffer.h @@ -290,10 +290,6 @@ IoBufferCore::ExtendedCore() const class IoBuffer { public: - enum EAssumeOwnershipTag - { - AssumeOwnership - }; enum ECloneTag { Clone @@ -339,11 +335,6 @@ public: memcpy(const_cast<void*>(m_Core->DataPointer()), DataPtr, SizeBytes); } - inline IoBuffer(EAssumeOwnershipTag, const void* DataPtr, size_t Sz) : m_Core(new IoBufferCore(DataPtr, Sz)) - { - m_Core->SetIsOwnedByThis(true); - } - ZENCORE_API IoBuffer(EFileTag, void* FileHandle, uint64_t ChunkFileOffset, uint64_t ChunkSize); ZENCORE_API IoBuffer(EBorrowedFileTag, void* FileHandle, uint64_t ChunkFileOffset, uint64_t ChunkSize); diff --git a/zencore/include/zencore/refcount.h b/zencore/include/zencore/refcount.h index 0a1e15614..320718f5b 100644 --- a/zencore/include/zencore/refcount.h +++ b/zencore/include/zencore/refcount.h @@ -17,7 +17,7 @@ namespace zen { class RefCounted { public: - RefCounted() = default; + RefCounted() = default; virtual ~RefCounted() = default; inline uint32_t AddRef() const { return AtomicIncrement(const_cast<RefCounted*>(this)->m_RefCount); } diff --git a/zencore/include/zencore/stats.h b/zencore/include/zencore/stats.h index 0554f620d..dfa8dac34 100644 --- a/zencore/include/zencore/stats.h +++ b/zencore/include/zencore/stats.h @@ -2,11 +2,16 @@ #pragma once -#include <atomic> -#include <type_traits> #include "zencore.h" +#include <atomic> +#include <random> + namespace zen { +class CbObjectWriter; +} + +namespace zen::metrics { template<typename T> class Gauge @@ -76,18 +81,19 @@ public: Meter(); ~Meter(); - double Rate1(); // One-minute rate - double Rate5(); // Five-minute rate - double Rate15(); // Fifteen-minute rate - double MeanRate(); // Mean rate since instantiation of this meter - void Mark(uint64_t Count = 1); // Register one or more events + inline uint64_t Count() const { return m_TotalCount; } + double Rate1(); // One-minute rate + double Rate5(); // Five-minute rate + double Rate15(); // Fifteen-minute rate + double MeanRate() const; // Mean rate since instantiation of this meter + void Mark(uint64_t Count = 1); // Register one or more events private: std::atomic<uint64_t> m_TotalCount{0}; // Accumulator counting number of marks since beginning std::atomic<uint64_t> m_PendingCount{0}; // Pending EWMA update accumulator std::atomic<uint64_t> m_StartTick{0}; // Time this was instantiated (for mean) std::atomic<uint64_t> m_LastTick{0}; // Timestamp of last EWMA tick - std::atomic<int64_t> m_Remain{0}; // Tracks the "modulo" of tick time + std::atomic<int64_t> m_Remainder{0}; // Tracks the "modulo" of tick time bool m_IsFirstTick = true; RawEWMA m_RateM1; RawEWMA m_RateM5; @@ -97,6 +103,130 @@ private: void Tick(); }; +/** Moment-in-time snapshot of a distribution + */ +class SampleSnapshot +{ +public: + SampleSnapshot(std::vector<double>&& Values); + ~SampleSnapshot(); + + uint32_t Size() const { return (uint32_t)m_Values.size(); } + double GetQuantileValue(double Quantile); + double GetMedian() { return GetQuantileValue(0.5); } + double Get75Percentile() { return GetQuantileValue(0.75); } + double Get95Percentile() { return GetQuantileValue(0.95); } + double Get98Percentile() { return GetQuantileValue(0.98); } + double Get99Percentile() { return GetQuantileValue(0.99); } + double Get999Percentile() { return GetQuantileValue(0.999); } + const std::vector<double>& GetValues() const; + +private: + std::vector<double> m_Values; +}; + +/** Randomly selects samples from a stream. Uses Vitter's + Algorithm R to produce a statistically representative sample. + + http://www.cs.umd.edu/~samir/498/vitter.pdf - Random Sampling with a Reservoir + */ + +class UniformSample +{ +public: + UniformSample(uint32_t ReservoirSize); + ~UniformSample(); + + void Clear(); + uint32_t Size() const; + void Update(int64_t Value); + SampleSnapshot Snapshot() const; + + template<std::invocable<int64_t> T> + void IterateValues(T Callback) const + { + for (const auto& Value : m_Values) + { + Callback(Value); + } + } + +private: + std::atomic<uint64_t> m_SampleCounter{0}; + std::vector<std::atomic<int64_t>> m_Values; +}; + +/** Track (probabilistic) sample distribution along with min/max + */ +class Histogram +{ +public: + Histogram(int32_t SampleCount = 1028); + ~Histogram(); + + void Clear(); + void Update(int64_t Value); + int64_t Max() const; + int64_t Min() const; + double Mean() const; + uint64_t Count() const; + SampleSnapshot Snapshot() const { return m_Sample.Snapshot(); } + +private: + UniformSample m_Sample; + std::atomic<int64_t> m_Min{0}; + std::atomic<int64_t> m_Max{0}; + std::atomic<int64_t> m_Sum{0}; + std::atomic<int64_t> m_Count{0}; +}; + +/** Track timing and frequency of some operation + + Example usage would be to track frequency and duration of network + requests, or function calls. + + */ +class OperationTiming +{ +public: + OperationTiming(int32_t SampleCount = 514); + ~OperationTiming(); + + void Update(int64_t Duration); + int64_t Max() const; + int64_t Min() const; + double Mean() const; + uint64_t Count() const; + SampleSnapshot Snapshot() const { return m_Histogram.Snapshot(); } + + double Rate1() { return m_Meter.Rate1(); } + double Rate5() { return m_Meter.Rate5(); } + double Rate15() { return m_Meter.Rate15(); } + double MeanRate() const { return m_Meter.MeanRate(); } + + struct Scope + { + Scope(OperationTiming& Outer); + ~Scope(); + + private: + OperationTiming& m_Outer; + uint64_t m_StartTick; + }; + +private: + Meter m_Meter; + Histogram m_Histogram; +}; + +void EmitSnapshot(std::string_view Tag, OperationTiming& Stat, CbObjectWriter& Cbo); +void EmitSnapshot(std::string_view Tag, const Histogram& Stat, CbObjectWriter& Cbo); +void EmitSnapshot(std::string_view Tag, Meter& Stat, CbObjectWriter& Cbo); + +} // namespace zen::metrics + +namespace zen { + extern void stats_forcelink(); } // namespace zen diff --git a/zencore/include/zencore/thread.h b/zencore/include/zencore/thread.h index 7889682cd..410ffbd1e 100644 --- a/zencore/include/zencore/thread.h +++ b/zencore/include/zencore/thread.h @@ -75,12 +75,12 @@ public: ZENCORE_API Event(); ZENCORE_API ~Event(); - Event(Event&& Rhs) : m_EventHandle(Rhs.m_EventHandle) { Rhs.m_EventHandle = nullptr; } + Event(Event&& Rhs) noexcept : m_EventHandle(Rhs.m_EventHandle) { Rhs.m_EventHandle = nullptr; } Event(const Event& Rhs) = delete; Event& operator=(const Event& Rhs) = delete; - inline Event& operator=(Event&& Rhs) + inline Event& operator=(Event&& Rhs) noexcept { std::swap(m_EventHandle, Rhs.m_EventHandle); return *this; @@ -133,14 +133,14 @@ public: ZENCORE_API ~ProcessHandle(); - ZENCORE_API void Initialize(int Pid); - ZENCORE_API void Initialize(void* ProcessHandle); /// Initialize with an existing handle - takes ownership of the handle - ZENCORE_API bool IsRunning() const; - ZENCORE_API bool IsValid() const; - ZENCORE_API bool Wait(int TimeoutMs = -1); - ZENCORE_API void Terminate(int ExitCode); - ZENCORE_API void Reset(); - inline int Pid() const { return m_Pid; } + ZENCORE_API void Initialize(int Pid); + ZENCORE_API void Initialize(void* ProcessHandle); /// Initialize with an existing handle - takes ownership of the handle + ZENCORE_API [[nodiscard]] bool IsRunning() const; + ZENCORE_API [[nodiscard]] bool IsValid() const; + ZENCORE_API bool Wait(int TimeoutMs = -1); + ZENCORE_API void Terminate(int ExitCode); + ZENCORE_API void Reset(); + inline [[nodiscard]] int Pid() const { return m_Pid; } private: void* m_ProcessHandle = nullptr; diff --git a/zencore/include/zencore/timer.h b/zencore/include/zencore/timer.h index eb284eaee..693b6daaa 100644 --- a/zencore/include/zencore/timer.h +++ b/zencore/include/zencore/timer.h @@ -18,30 +18,26 @@ namespace zen { ZENCORE_API uint64_t GetHifreqTimerValue(); ZENCORE_API uint64_t GetHifreqTimerFrequency(); +ZENCORE_API double GetHifreqTimerToSeconds(); ZENCORE_API uint64_t GetHifreqTimerFrequencySafe(); // May be used during static init class Stopwatch { public: - Stopwatch() : m_StartValue(GetHifreqTimerValue()) {} + inline Stopwatch() : m_StartValue(GetHifreqTimerValue()) {} - inline uint64_t getElapsedTimeMs() { return (GetHifreqTimerValue() - m_StartValue) * 1000 / GetHifreqTimerFrequency(); } + inline uint64_t GetElapsedTimeMs() const { return (GetHifreqTimerValue() - m_StartValue) * 1'000 / GetHifreqTimerFrequency(); } + inline uint64_t GetElapsedTimeUs() const { return (GetHifreqTimerValue() - m_StartValue) * 1'000'000 / GetHifreqTimerFrequency(); } + inline uint64_t GetElapsedTicks() const { return GetHifreqTimerValue() - m_StartValue; } + inline void Reset() { m_StartValue = GetHifreqTimerValue(); } - inline void reset() { m_StartValue = GetHifreqTimerValue(); } + static inline uint64_t GetElapsedTimeMs(uint64_t Ticks) { return Ticks * 1'000 / GetHifreqTimerFrequency(); } + static inline uint64_t GetElapsedTimeUs(uint64_t Ticks) { return Ticks * 1'000'000 / GetHifreqTimerFrequency(); } private: uint64_t m_StartValue; }; -// CPU timers - -inline uint64_t -GetCpuTimerValue() -{ - unsigned int foo; - return __rdtscp(&foo); -} - void timer_forcelink(); // internal } // namespace zen |