#pragma once #include #include #include #include #include #include namespace fluidsim::port { enum class ProfileStage : std::size_t { Total, Controls, Solver, Boundary, Pipe, Components, Audio, Count }; inline constexpr std::array profile_stage_names{ "total", "controls", "solver", "boundary", "pipe", "components", "audio"}; struct ProfileTotals { std::array(ProfileStage::Count)> nanoseconds{}; std::uint64_t sampled_steps{}; std::array frame_histogram{}; }; inline double profile_percentile_ms(const ProfileTotals& totals,double quantile) { if(!totals.sampled_steps) return 0; const auto target=static_cast(quantile*(totals.sampled_steps-1)); std::uint64_t count=0; for(std::size_t i=0;itarget) 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(stage)]+=ns; } void finish_step(std::uint64_t elapsed_ns) { ++totals_.sampled_steps; const auto bin=std::min(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(Clock::now()-start_).count()); } std::uint64_t elapsed_ns() const { return profiler_?std::chrono::duration_cast(Clock::now()-start_).count():0; } private: using Clock=std::chrono::steady_clock; RuntimeProfiler* profiler_{}; ProfileStage stage_{}; Clock::time_point start_{}; }; }