aboutsummaryrefslogtreecommitdiff
path: root/zencore/include
diff options
context:
space:
mode:
authorMartin Ridgers <[email protected]>2021-10-01 11:50:43 +0200
committerMartin Ridgers <[email protected]>2021-10-01 11:50:43 +0200
commita2dc648979bad70037e19ce75ae506f9455e8fd3 (patch)
tree4d902270db982a24df05eecdf53d0535b601d582 /zencore/include
parentRemoved `-fshort-wchar` compiler flag on Linux (diff)
parentAdded upstream cache perf metrics. (diff)
downloadzen-a2dc648979bad70037e19ce75ae506f9455e8fd3.tar.xz
zen-a2dc648979bad70037e19ce75ae506f9455e8fd3.zip
Merged main
Diffstat (limited to 'zencore/include')
-rw-r--r--zencore/include/zencore/iobuffer.h9
-rw-r--r--zencore/include/zencore/refcount.h2
-rw-r--r--zencore/include/zencore/stats.h146
-rw-r--r--zencore/include/zencore/thread.h20
-rw-r--r--zencore/include/zencore/timer.h20
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