16 #include <boost/algorithm/string.hpp>
18 #include <fmt/format.h>
21 #include <string_view>
35 static const auto registry = std::map<std::string_view, std::string_view>{
36 {
"counter",
"{0:nEntries|10d}" },
37 {
"counter:AveragingCounter",
"{0:nEntries|10d} |{0:sum|11.7g} |{0:mean|#11.5g}" },
38 {
"counter:SigmaCounter",
"{0:nEntries|10d} |{0:sum|11.7g} |{0:mean|#11.5g} |{0:standard_deviation|#11.5g}" },
39 {
"counter:StatCounter",
"{0:nEntries|10d} |{0:sum|11.7g} |{0:mean|#11.5g} |{0:standard_deviation|#11.5g} "
40 "|{0:min|#12.5g} |{0:max|#12.5g}" },
41 {
"counter:BinomialCounter",
42 "{0:nEntries|10d} |{0:nTrueEntries|11d} |({0:efficiency|#9.7p} +- {0:efficiencyErr|-#8.7p})%" },
48 using HistoBinHandler =
49 std::pair<
unsigned int,
51 namespace Acc = ::Gaudi::Accumulators;
56 std::map<std::type_index, HistoBinHandler>
const binRegistry = {
58 { 4, &Gaudi::Histograming::Sink::printProfileHisto1D<Acc::atomicity::full, double> } },
60 { 4, &Gaudi::Histograming::Sink::printProfileHisto1D<Acc::atomicity::none, double> } },
62 { 4, &Gaudi::Histograming::Sink::printProfileHisto1D<Acc::atomicity::full, float> } },
64 { 4, &Gaudi::Histograming::Sink::printProfileHisto1D<Acc::atomicity::none, float> } },
66 { 5, &Gaudi::Histograming::Sink::printProfileHisto2D<Acc::atomicity::full, double> } },
68 { 5, &Gaudi::Histograming::Sink::printProfileHisto2D<Acc::atomicity::none, double> } },
70 { 5, &Gaudi::Histograming::Sink::printProfileHisto2D<Acc::atomicity::full, float> } },
72 { 5, &Gaudi::Histograming::Sink::printProfileHisto2D<Acc::atomicity::none, float> } },
74 { 6, &Gaudi::Histograming::Sink::printProfileHisto3D<Acc::atomicity::full, double> } },
76 { 6, &Gaudi::Histograming::Sink::printProfileHisto3D<Acc::atomicity::none, double> } },
78 { 6, &Gaudi::Histograming::Sink::printProfileHisto3D<Acc::atomicity::full, float> } },
80 { 6, &Gaudi::Histograming::Sink::printProfileHisto3D<Acc::atomicity::none, float> } },
102 class fmt::formatter<json_fmt_arg> {
104 template <
typename ParseContext>
106 auto fmt_begin =
ctx.begin();
107 auto fmt_end = std::find( fmt_begin,
ctx.end(),
'}' );
108 if ( fmt_begin == fmt_end ) {
113 auto fmt_colon = std::find( fmt_begin, fmt_end,
'|' );
114 currentName = std::string( fmt_begin, fmt_colon - fmt_begin );
115 currentFormat = std::string( fmt_colon + 1, fmt_end - fmt_colon - 1 );
119 template <
typename FormatContext>
120 auto format(
const json_fmt_arg& json_arg, FormatContext&
ctx )
const {
121 const auto&
j = json_arg.payload;
122 if ( currentFormat.size() == 0 ) {
124 const auto type =
j.at(
"type" ).get<std::string>();
126 std::string_view type_key{
type };
128 auto entry =
registry.find( type_key );
130 auto sep = type_key.rfind(
':' );
131 while ( sep != type_key.npos && entry ==
registry.end() ) {
133 type_key.remove_suffix( type_key.size() - sep );
135 sep = type_key.rfind(
':' );
144 return fmt::format_to(
ctx.out(), fmt::runtime( entry->second ), json_arg );
147 auto actualFormat =
"{:" + currentFormat +
'}';
148 switch ( currentFormat.back() ) {
150 return fmt::format_to(
ctx.out(), fmt::runtime( actualFormat ),
151 j.at( currentName ).template get<unsigned int>() );
153 return fmt::format_to(
ctx.out(), fmt::runtime( actualFormat ),
j.at( currentName ).template get<double>() );
155 actualFormat[actualFormat.size() - 2] =
'g';
156 return fmt::format_to(
ctx.out(), fmt::runtime( actualFormat ),
157 j.at( currentName ).template get<double>() * 100 );
159 return fmt::format_to(
ctx.out(),
"Unknown counter format : {}", currentFormat );
171 void printCounter( std::ostringstream&
log, std::string_view
id,
const nlohmann::json&
j ) {
172 const auto type =
j.at(
"type" ).get<std::string>();
175 if (
type ==
"statentity" ) {
176 using boost::algorithm::icontains;
177 bool isBinomial = icontains(
id,
"eff" ) || icontains(
id,
"acc" ) || icontains(
id,
"filt" ) ||
178 icontains(
id,
"fltr" ) || icontains(
id,
"pass" );
180 nj[
"type"] = isBinomial ?
"counter:BinomialCounter" :
"counter:StatCounter";
181 return printCounter(
log,
id, nj );
187 ( std::string_view{
type }.substr( 0, 23 ) ==
"counter:BinomialCounter" ?
'*' :
' ' ),
188 fmt::format( fmt::runtime(
"\"{}\"" ),
id ), json_fmt_arg{
j } );
205 setProperty(
"TypesToSave", std::vector<std::string>{
"counter:.*",
"statentity",
"histogram:.*" } )
206 .orThrow(
"Unable to set TypesToSave property",
"Gaudi::Monitoring::MessageSvcSink" );
208 setProperty(
"ComponentsToSave", std::vector<std::string>{
"^.+$" } )
209 .orThrow(
"Unable to set ComponentsToSave property",
"Gaudi::Monitoring::MessageSvcSink" );
212 void flush(
bool )
override;
214 "length of histograms names and titles in the output" };
221 std::string curAlgo =
"";
225 std::array<std::ostringstream, 7> curLog;
228 std::array<unsigned int, 7> nbNonEmptyEntities{};
229 auto dumpAlgoCounters = [&]() {
232 if ( nbNonEmptyEntities[0] > 0 ) {
233 log <<
MSG::INFO <<
"Number of counters : " << nbNonEmptyEntities[0] <<
"\n"
234 <<
" | Counter | # | "
235 <<
" sum | mean/eff^* | rms/err^* | min | max |";
239 unsigned int nHistos = nbNonEmptyEntities[1] + nbNonEmptyEntities[2] + nbNonEmptyEntities[3] +
240 nbNonEmptyEntities[4] + nbNonEmptyEntities[5] + nbNonEmptyEntities[6];
242 log <<
MSG::INFO <<
"Booked " << nHistos <<
" Histogram(s) : 1D=" << nbNonEmptyEntities[1]
243 <<
" 2D=" << nbNonEmptyEntities[2] <<
" 3D=" << nbNonEmptyEntities[3] <<
" 1DProf=" << nbNonEmptyEntities[4]
244 <<
" 2DProf=" << nbNonEmptyEntities[5] <<
" 3DProf=" << nbNonEmptyEntities[6] <<
endmsg;
245 if ( nbNonEmptyEntities[1] > 0 ) {
246 log <<
MSG::INFO <<
"1D histograms in directory \"" << curAlgo <<
"\" : " << nbNonEmptyEntities[1] <<
"\n"
249 " | {:{}s} | {:{}s} | # | Mean | RMS | Skewness | Kurtosis |" ),
251 << curLog[1].str() <<
endmsg;
253 if ( nbNonEmptyEntities[2] > 0 ) {
254 log <<
MSG::INFO <<
"2D histograms in directory \"" << curAlgo <<
"\" : " << nbNonEmptyEntities[2]
255 << curLog[2].str() <<
endmsg;
257 if ( nbNonEmptyEntities[3] > 0 ) {
258 log <<
MSG::INFO <<
"3D histograms in directory \"" << curAlgo <<
"\" : " << nbNonEmptyEntities[3]
259 << curLog[3].str() <<
endmsg;
261 if ( nbNonEmptyEntities[4] > 0 ) {
262 log <<
MSG::INFO <<
"1D profile histograms in directory \"" << curAlgo <<
"\" : " << nbNonEmptyEntities[4]
266 " | {:{}s} | {:{}s} | # | Mean | RMS | Skewness | Kurtosis |" ),
268 << curLog[4].str() <<
endmsg;
270 if ( nbNonEmptyEntities[5] > 0 ) {
271 log <<
MSG::INFO <<
"2D profile histograms in directory \"" << curAlgo <<
"\" : " << nbNonEmptyEntities[5]
272 << curLog[5].str() <<
endmsg;
274 if ( nbNonEmptyEntities[6] > 0 ) {
275 log <<
MSG::INFO <<
"3D profile histograms in directory \"" << curAlgo <<
"\" : " << nbNonEmptyEntities[6]
276 << curLog[6].str() <<
endmsg;
283 if ( algo != curAlgo ) {
286 nbNonEmptyEntities = { 0, 0, 0, 0, 0, 0, 0 };
287 curLog = { std::ostringstream{}, std::ostringstream{}, std::ostringstream{}, std::ostringstream{},
288 std::ostringstream{}, std::ostringstream{}, std::ostringstream{} };
292 auto binWriter = binRegistry.find( typeIndex );
293 if ( binWriter != binRegistry.end() ) {
294 auto index = binWriter->second.first;
295 ++nbNonEmptyEntities[
index];
297 if ( logLine.size() > 0 ) { curLog[
index] <<
"\n" << logLine; }
302 const auto type =
j.at(
"type" ).get<std::string>();
303 if (
type.find(
"histogram" ) == 0 ) {
304 if ( !
j.at(
"empty" ).template get<bool>() ) {
305 unsigned int d =
j.at(
"dimension" ).get<
int>();
306 auto subtype = std::string_view(
type ).substr( 10 );
307 bool isProfile = subtype.substr( 0, 15 ) ==
"WeightedProfile" || subtype.substr( 0, 7 ) ==
"Profile";
308 unsigned int index = ( isProfile ? 3 : 0 ) + d;
309 auto title =
j.at(
"title" ).get<std::string>();
310 std::string logLine{
"" };
322 if ( logLine.size() > 0 ) {
323 curLog[
index] <<
"\n" << logLine;
324 ++nbNonEmptyEntities[
index];
329 if ( !
j.at(
"empty" ).template get<bool>() ) {
330 ++nbNonEmptyEntities[0];
332 printCounter( curLog[0],
name,
j );