103 lines
2.8 KiB
C++
103 lines
2.8 KiB
C++
// Copyright © 2008-2021 Pioneer Developers. See AUTHORS.txt for details
|
|
// Licensed under the terms of the GPL v3. See licenses/GPL-3.txt
|
|
|
|
#pragma once
|
|
|
|
#include <atomic>
|
|
#include <cassert>
|
|
#include <cstddef>
|
|
#include <map>
|
|
#include <mutex>
|
|
#include <set>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
namespace Perf {
|
|
/**
|
|
* Simple atomic counter implementation for performance counters.
|
|
*
|
|
* Create counters by calling auto ref = stats->GetOrCreateCounter("Triangles Drawn").
|
|
* Once you have a counter reference, you can call stats->CounterAdd(ref, 12) to update the counter.
|
|
* The Counter* functions are thread-safe so long as they are called with a proper CounterRef.
|
|
* Call FlushFrame() to collate all stats from the current frame and write them to the frame cache.
|
|
*/
|
|
class Stats {
|
|
public:
|
|
using FrameInfo = std::map<std::string, uint32_t>;
|
|
|
|
// Simple opaque struct to make it more difficult to accidentally clobber memory or threading constraints
|
|
struct CounterRef {
|
|
CounterRef() = delete;
|
|
explicit CounterRef(std::nullptr_t) :
|
|
id(0) {}
|
|
size_t id;
|
|
|
|
private:
|
|
friend class Stats;
|
|
CounterRef(std::size_t t) :
|
|
id(t) {}
|
|
};
|
|
|
|
CounterRef GetOrCreateCounter(std::string name, bool resetOnNewFrame = true);
|
|
|
|
void CounterAdd(CounterRef ref, uint32_t amount = 1) const
|
|
{
|
|
assert(ref.id != 0);
|
|
m_counters.at(ref.id).ctr.fetch_add(amount);
|
|
}
|
|
|
|
void CounterDec(CounterRef ref, uint32_t amount = 1) const
|
|
{
|
|
assert(ref.id != 0);
|
|
m_counters.at(ref.id).ctr.fetch_sub(amount);
|
|
}
|
|
|
|
void CounterSet(CounterRef ref, uint32_t value) const
|
|
{
|
|
assert(ref.id != 0);
|
|
m_counters.at(ref.id).ctr.store(value);
|
|
}
|
|
|
|
void CounterReset(CounterRef ref) const
|
|
{
|
|
assert(ref.id != 0);
|
|
m_counters.at(ref.id).ctr.store(0);
|
|
}
|
|
|
|
void EnableReset(bool enabled) { m_neverReset = !enabled; }
|
|
|
|
const FrameInfo &GetFrameStats() const { return m_frameCache; }
|
|
|
|
std::string GetNameForCounter(CounterRef ref) const { return m_definedCounters.at(ref.id); }
|
|
|
|
// Terminate the current frame and make performance counters available with GetFrameStats().
|
|
void FlushFrame();
|
|
|
|
private:
|
|
struct Counter {
|
|
Counter(bool reset) :
|
|
resetOnNewFrame(reset){};
|
|
// mutable because the only thing we're modifying via non-const references is the atomic counters
|
|
mutable std::atomic<uint32_t> ctr;
|
|
bool resetOnNewFrame;
|
|
};
|
|
|
|
// hashmap of counter ID to counter value
|
|
std::map<std::size_t, Counter> m_counters;
|
|
|
|
// Cache the previous frame
|
|
FrameInfo m_frameCache;
|
|
|
|
bool m_neverReset = false;
|
|
|
|
// hashmap of counter IDs to counter names
|
|
std::map<std::size_t, std::string> m_definedCounters;
|
|
|
|
// mutex used to synchronize updates to definedCounters
|
|
std::mutex m_counterMutex;
|
|
// store a std::hash instance so we don't have to recreate it every time we want to hash a string.
|
|
std::hash<std::string> m_strHashFn;
|
|
};
|
|
|
|
} // namespace Perf
|