60 lines
2.4 KiB
C++
60 lines
2.4 KiB
C++
#pragma once
|
|
#include <array>
|
|
#include <chrono>
|
|
#include <cstddef>
|
|
#include <algorithm>
|
|
#include <cstdint>
|
|
#include <string_view>
|
|
namespace fluidsim::port {
|
|
enum class ProfileStage : std::size_t { Total, Controls, Solver, Boundary, Pipe, Components, Audio, Count };
|
|
inline constexpr std::array<std::string_view,7> profile_stage_names{
|
|
"total", "controls", "solver", "boundary", "pipe", "components", "audio"};
|
|
struct ProfileTotals {
|
|
std::array<std::uint64_t,static_cast<std::size_t>(ProfileStage::Count)> nanoseconds{};
|
|
std::uint64_t sampled_steps{};
|
|
std::array<std::uint64_t,512> frame_histogram{};
|
|
};
|
|
inline double profile_percentile_ms(const ProfileTotals& totals,double quantile) {
|
|
if(!totals.sampled_steps) return 0;
|
|
const auto target=static_cast<std::uint64_t>(quantile*(totals.sampled_steps-1));
|
|
std::uint64_t count=0;
|
|
for(std::size_t i=0;i<totals.frame_histogram.size();++i) {
|
|
count+=totals.frame_histogram[i];
|
|
if(count>target) return (i+.5)*.001;
|
|
}
|
|
return .512;
|
|
}
|
|
class RuntimeProfiler {
|
|
public:
|
|
void enable(bool value) { enabled_=value; frame_=0; totals_={}; }
|
|
bool begin_step() { return enabled_ && (frame_++%2==0); }
|
|
void add(ProfileStage stage,std::uint64_t ns) { totals_.nanoseconds[static_cast<std::size_t>(stage)]+=ns; }
|
|
void finish_step(std::uint64_t elapsed_ns) {
|
|
++totals_.sampled_steps;
|
|
const auto bin=std::min<std::uint64_t>(elapsed_ns/1000,totals_.frame_histogram.size()-1);
|
|
++totals_.frame_histogram[bin];
|
|
}
|
|
double frame_percentile_ms(double quantile) const {
|
|
return profile_percentile_ms(totals_,quantile);
|
|
}
|
|
const ProfileTotals& totals() const { return totals_; }
|
|
bool enabled() const { return enabled_; }
|
|
private:
|
|
bool enabled_{};
|
|
std::uint64_t frame_{};
|
|
ProfileTotals totals_{};
|
|
};
|
|
class ProfileScope {
|
|
public:
|
|
ProfileScope(RuntimeProfiler* profiler,bool active,ProfileStage stage)
|
|
: profiler_(active?profiler:nullptr),stage_(stage),start_(profiler_?Clock::now():Clock::time_point{}) {}
|
|
~ProfileScope() { if(profiler_) profiler_->add(stage_,std::chrono::duration_cast<std::chrono::nanoseconds>(Clock::now()-start_).count()); }
|
|
std::uint64_t elapsed_ns() const {
|
|
return profiler_?std::chrono::duration_cast<std::chrono::nanoseconds>(Clock::now()-start_).count():0;
|
|
}
|
|
private:
|
|
using Clock=std::chrono::steady_clock;
|
|
RuntimeProfiler* profiler_{}; ProfileStage stage_{}; Clock::time_point start_{};
|
|
};
|
|
}
|