timing.hpp algorithm chrono cstddef cstdint memory string vector nameof.hpp serif/utils/dependencies/observers.hpp src/compile_time_checks/serif/utils/dependencies/computation_graph.cpp serif::utils::dependencies::NodeTiming serif::utils::dependencies::GraphTimingRun serif::utils::dependencies::GraphTiming serif::utils::dependencies::SteadyNodeClock serif::utils::dependencies::GraphTimingFactory serif serif::utils serif::utils::dependencies serif::utils::dependencies::detail #pragmaonce #include<algorithm> #include<chrono> #include<cstddef> #include<cstdint> #include<memory> #include<string> #include<vector> #include"nameof.hpp" #include"serif/utils/dependencies/observers.hpp" namespaceserif::utils::dependencies{ structNodeTiming{ std::size_tindex{}; std::stringkey_name; std::uint64_tcalls{}; std::uint64_tcompleted{}; std::uint64_trejected{}; std::uint64_texceptions{}; doubleseconds{}; doublemaximum_seconds{}; voidfinish(doubleduration,NodeOutcomeoutcome)noexcept{ ++calls; seconds+=duration; maximum_seconds=std::max(maximum_seconds,duration); switch(outcome){ caseNodeOutcome::completed:++completed;break; caseNodeOutcome::rejected:++rejected;break; caseNodeOutcome::exception:++exceptions;break; } } }; structGraphTimingRun{ std::vector<NodeTiming>nodes; }; classGraphTiming{ public: [[nodiscard]]conststd::vector<std::shared_ptr<constGraphTimingRun>>&runs()constnoexcept{returnm_runs;} template<typenameGraphT> [[nodiscard]]std::shared_ptr<GraphTimingRun>start_run(std::type_identity<GraphT>){ autorun=std::make_shared<GraphTimingRun>(); run->nodes=[]<typename...Keys>(KeyList<Keys...>){ returnstd::vector<NodeTiming>{NodeTiming{.index=GraphT::templateindex<Keys>(), .key_name=std::string{nameof::nameof_type<Keys>()}}...}; }(typenameGraphT::Results{}); m_runs.push_back(run); returnrun; } private: std::vector<std::shared_ptr<constGraphTimingRun>>m_runs; }; structSteadyNodeClock{ [[nodiscard]]std::chrono::steady_clock::time_pointoperator()()constnoexcept{ returnstd::chrono::steady_clock::now(); } }; namespacedetail{ template<typenameTimePoint> inlineconstexprboolnode_time_point_v=false; template<typenameClock,typenameDuration> inlineconstexprboolnode_time_point_v<std::chrono::time_point<Clock, Duration>>=std::is_arithmetic_v<typenameDuration::rep>; } template<typenameClock> conceptNodeTimingClock=std::is_nothrow_invocable_v<Clock&>&& detail::node_time_point_v<std::invoke_result_t<Clock&>>; template<NodeTimingClockClock=SteadyNodeClock> structGraphTimingFactory{ GraphTiming&timing; std::shared_ptr<Clock>clock; template<typenameGraphT> [[nodiscard]]autooperator()(std::type_identity<GraphT>graph)const{ constautorun=timing.start_run(graph); usingTimePoint=std::invoke_result_t<Clock&>; structInvocation{ std::size_tindex; TimePointstarted; }; returnmake_observers(observe_nodes( [clock=clock]<typenameKey>(std::type_identity<Key>)noexcept{ returnInvocation{.index=GraphT::templateindex<Key>(),.started=std::invoke(*clock)}; }, [run,clock=clock](Invocation&invocation,NodeOutcomeoutcome)noexcept{ constdoubleduration=std::chrono::duration<double>{std::invoke(*clock)-invocation.started}.count(); run->nodes[invocation.index].finish(duration,outcome); })); } }; template<NodeTimingClockClock=SteadyNodeClock> [[nodiscard]]autotime_graph_nodes(GraphTiming&timing,Clockclock={}){ returnGraphTimingFactory<Clock>{.timing=timing,.clock=std::make_shared<Clock>(std::move(clock))}; } }