The Gaudi Framework  master (b9786168)
Loading...
Searching...
No Matches
AlgTimingAuditor.cpp
Go to the documentation of this file.
1/***********************************************************************************\
2* (c) Copyright 2023-2025 CERN for the benefit of the LHCb and ATLAS collaborations *
3* *
4* This software is distributed under the terms of the Apache version 2 licence, *
5* copied verbatim in the file "LICENSE". *
6* *
7* In applying this licence, CERN does not waive the privileges and immunities *
8* granted to it by virtue of its status as an Intergovernmental Organization *
9* or submit itself to any jurisdiction. *
10\***********************************************************************************/
11#include <Gaudi/Auditor.h>
14#include <GaudiKernel/SmartIF.h>
15#include <chrono>
16#include <format>
17#include <string>
18#include <type_traits>
19#include <unordered_map>
20#include <vector>
21
22struct AlgTimingAuditor final : extends<Gaudi::Auditor, IIncidentListener> {
24
25 using Auditor::after;
26 using Auditor::before;
27
29 return base_class::initialize().andThen( [&]() {
30 m_incSvc = service( "IncidentSvc" );
31 if ( m_incSvc ) {
32 m_incSvc->addListener( this, IncidentType::BeginEvent );
33 m_incSvc->addListener( this, IncidentType::EndEvent );
35 } else {
36 debug() << "no IncidentSvc, I cannot measure overall event processing time" << endmsg;
37 }
38 } );
39 }
40
41 void before( std::string const& evt, std::string const& alg, EventContext const& ) override {
42 if ( evt == Gaudi::IAuditor::Initialize ) {
43 stats( alg ); // this implicitly adds the algorithm to the list of known ones
45 } else if ( evt == Gaudi::IAuditor::Execute ) {
46 stats( alg ).start();
47 }
48 }
49
50 void after( std::string const& evt, std::string const& alg, EventContext const&, const StatusCode& ) override {
51 if ( evt == Gaudi::IAuditor::Initialize ) {
53 } else if ( evt == Gaudi::IAuditor::Execute ) {
54 stats( alg ).stop();
55 }
56 }
57
58 void handle( const Incident& i ) override {
59 if ( IncidentType::BeginEvent == i.type() ) {
60 m_eventLoopStats.start();
61 } else if ( IncidentType::EndEvent == i.type() ) {
62 m_eventLoopStats.stop();
63 }
64 }
65
66 StatusCode finalize() override {
67 using ms = std::chrono::duration<float, std::milli>;
68 using s = std::chrono::duration<float>;
69 info() << "-------------------------------------------------------------------" << endmsg;
70 info() << "Algorithm | exec (ms) | count | total (s)" << endmsg;
71 info() << "-------------------------------------------------------------------" << endmsg;
72 if ( m_incSvc ) {
73 const auto count = m_eventLoopStats.count;
74 const auto total_time = m_eventLoopStats.total_time;
75 info() << std::format( "{:<30.30} | {:9.4} | {:9} | {:9.4}", "EVENT LOOP",
76 count ? ms( total_time ).count() / count : 0.f, count, s( total_time ).count() )
77 << endmsg;
78 }
79 std::vector<std::pair<std::string, std::size_t>> offsets{ begin( m_offsets ), end( m_offsets ) };
80 std::sort( begin( offsets ), end( offsets ), []( auto& a, auto& b ) { return a.second < b.second; } );
81 for ( const auto& [name, offset] : offsets ) {
82 std::string indented_name = std::string( m_depths[offset], ' ' ) + name;
83 const auto count = m_stats[offset].count;
84 const auto total_time = m_stats[offset].total_time;
85 info() << std::format( "{:<30.30} | {:9.4} | {:9} | {:9.4}", indented_name,
86 count ? ms( total_time ).count() / count : 0.f, count, s( total_time ).count() )
87 << endmsg;
88 }
89 info() << "-------------------------------------------------------------------" << endmsg;
90
91 if ( m_incSvc ) {
92 m_incSvc->removeListener( this, IncidentType::BeginEvent );
93 m_incSvc->removeListener( this, IncidentType::EndEvent );
94 m_incSvc.reset();
95 }
96 return base_class::finalize();
97 }
98
99 using clock_t = std::conditional_t<std::chrono::high_resolution_clock::is_steady, std::chrono::high_resolution_clock,
100 std::chrono::steady_clock>;
101
102 struct stats_t {
103 clock_t::duration total_time{};
104 std::size_t count{};
105 clock_t::time_point started{};
106
107 void start() { started = clock_t::now(); }
108 void stop() {
109 total_time += clock_t::now() - started;
110 ++count;
111 }
112 };
113
114 stats_t& stats( std::string const& alg ) {
115 if ( auto it = m_offsets.find( alg ); it != end( m_offsets ) ) {
116 return m_stats[it->second];
117 } else {
118 m_depths.push_back( m_currentDepth );
119 m_stats.emplace_back();
120 m_offsets[alg] = m_stats.size() - 1;
121 return m_stats.back();
122 }
123 }
124
126
127 std::unordered_map<std::string, std::size_t> m_offsets;
128 std::vector<std::uint16_t> m_depths;
129 std::vector<stats_t> m_stats;
131 std::uint16_t m_currentDepth{ 0 };
132};
133
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
Definition MsgStream.h:198
#define DECLARE_COMPONENT(type)
MsgStream & debug() const
shortcut for the method msgStream(MSG::DEBUG)
MsgStream & info() const
shortcut for the method msgStream(MSG::INFO)
This class represents an entry point to all the event specific data.
const std::string & name() const override
Definition Auditor.h:51
SmartIF< T > service(std::string_view name, bool createIf=false) const
Access a service by name, creating it if it doesn't already exist.
Definition Auditor.h:63
static const std::string Initialize
Definition IAuditor.h:47
static const std::string Execute
Definition IAuditor.h:51
Base class for all Incidents (computing events).
Definition Incident.h:24
const std::string & type() const
Access to the incident type.
Definition Incident.h:43
Small smart pointer class with automatic reference counting for IInterface.
Definition SmartIF.h:28
This class is used for returning status codes from appropriate routines.
Definition StatusCode.h:64
StatusCode andThen(F &&f, ARGS &&... args) const
Chain code blocks making the execution conditional a success result.
Definition StatusCode.h:163
Base class used to extend a class implementing other interfaces.
Definition extends.h:19
extends base_class
Typedef to this class.
Definition extends.h:23
StatusCode initialize() override
void after(std::string const &evt, std::string const &alg, EventContext const &, const StatusCode &) override
std::vector< std::uint16_t > m_depths
std::vector< stats_t > m_stats
std::conditional_t< std::chrono::high_resolution_clock::is_steady, std::chrono::high_resolution_clock, std::chrono::steady_clock > clock_t
void handle(const Incident &i) override
SmartIF< IIncidentSvc > m_incSvc
std::unordered_map< std::string, std::size_t > m_offsets
void before(std::string const &evt, std::string const &alg, EventContext const &) override
stats_t & stats(std::string const &alg)
StatusCode finalize() override
std::uint16_t m_currentDepth