ATLAS Offline Software
Loading...
Searching...
No Matches
AthenaSummarySvc.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
5/*****************************************************************************
6 *
7 * AthenaSummarySvc.cxx
8 * AthenaSummarySvc
9 *
10 * Author: Charles Leggett
11 *
12 * Provides summary at end of athena job
13 *
14 *****************************************************************************/
15
16#include "AthenaSummarySvc.h"
17
18#include "GaudiKernel/FileIncident.h"
19#include "GaudiKernel/ISvcLocator.h"
20#include "GaudiKernel/Incident.h"
21#include "GaudiKernel/System.h"
22
23#include <fstream>
24#include <print>
25#include <unistd.h>
26#include <exception>
27#include <string_view>
28#include <ctype.h>
29
30static constexpr std::string levelNames[MSG::NUM_LEVELS] = {"NIL", "VERBOSE", "DEBUG", "INFO",
31 "WARNING", "ERROR", "FATAL", "ALWAYS"};
32
33using namespace std;
34
35char* AthenaSummarySvc::s_block = nullptr;
36bool AthenaSummarySvc::s_badalloc = false;
37const char* const II("\001");
38
39
40//
42//
43
44class PD {
45public:
46 PD(){};
47 PD(const string& a, const string& b) { add(a,b); }
48
49 void add(const string& a, const char* b) {
50 add(a,(string)b);
51 }
52 void add(const string& a, const string& b) {
53 m_dat[a].push_back( b );
54 }
55 void add(const string& a, const PD& p) {
56 m_dat[a].push_back( p.dump() );
57 }
58 template <typename T>
59 void add(const string& a, const T t) {
60 m_dat[a].push_back(std::format("\001{}", t));
61 }
62
63 operator const string () const
64 {
65 return dump();
66 }
67
68 string dump() const {
69 string x("{");
70 map<string,vector<string> >::const_iterator itr;
71 unsigned int iv;
72 for (itr=m_dat.begin(); itr != m_dat.end(); ++itr) {
73 if (x.length() > 1) { x+= ','; }
74 x += "\"" + itr->first + "\":";
75 vector<string> v = itr->second;
76 if (v.size() > 1) { x += '['; }
77 for (iv = 0; iv < v.size(); ++iv) {
78 if (iv > 0) { x += ','; }
79 if (v[iv][0] == '{') {
80 x += v[iv];
81 } else if (v[iv].compare(0,1, II)==0) {
82 x.append( v[iv], 1,v[iv].length());
83 } else {
84 x += "\"" + v[iv] + "\"";
85 }
86 }
87 if (v.size() > 1) { x += ']'; }
88 }
89 x += '}';
90 return x;
91 }
92
93
94private:
95
96 map<string, vector<string> > m_dat;
97
98};
99
100
101inline void tolower(std::string &s)
102{
103 // cf https://en.cppreference.com/w/cpp/string/byte/tolower
104 std::transform(s.begin(), s.end(), s.begin(),
105 [](unsigned char c){ return std::tolower(c); } );
106}
107
108//
110//
111
112AthenaSummarySvc::AthenaSummarySvc( const std::string& name, ISvcLocator* svc )
113 : base_class( name, svc ),
114 p_incSvc("IncidentSvc",name),
115 m_new (std::set_new_handler( &AthenaSummarySvc::newHandler ))
116{
117}
118
119/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
120
122
123 ATH_MSG_DEBUG("Initializing AthenaSummarySvc");
124
125 int pri=100;
126 p_incSvc->addListener( this, "BeginInputFile", pri, true);
127 p_incSvc->addListener( this, "EndInputFile", pri, true);
128 p_incSvc->addListener( this, "BeginOutputFile", pri, true);
129 p_incSvc->addListener( this, "FailOutputFile", pri, true);
130 p_incSvc->addListener( this, "WroteToOutputFile", pri, true);
131 p_incSvc->addListener( this, "EndOutputFile", pri, true);
132
133 p_incSvc->addListener( this, "AbortEvent", pri, true);
134
135 p_incSvc->addListener( this, "BeginEvent", pri, true);
136 p_incSvc->addListener( this, "EndEvent", pri, true);
137 p_incSvc->addListener( this, "BeginRun", pri, true);
138 p_incSvc->addListener( this, "EndRun", pri, true);
139
140 p_incSvc->addListener( this, "FirstInputFile", pri, true );
141
142 vector<string>::const_iterator itr;
143 for (itr=m_extraInc.value().begin(); itr != m_extraInc.value().end(); ++itr) {
144 ATH_MSG_DEBUG("Tracking incident \"{}\"", *itr);
145 addListener(*itr);
146 }
147
148 p_logMsg = dynamic_cast< ILoggedMessageSvc* > ( msgSvc().get() );
149 if (p_logMsg == nullptr) {
150 ATH_MSG_INFO("unable dcast IMessageSvc to ILoggedMessageSvc: "
151 "not scanning for keywords in logs, or printing logged messages");
152 } else {
153
154 if (m_keywords.value().size() > 0) {
155 IProperty *ip = dynamic_cast<IProperty*>( p_logMsg );
156 if (ip != nullptr) {
157 if (ip->setProperty(m_keywords).isFailure()) {
158 ATH_MSG_ERROR("could not set keywords property of LoggedMessageSvc");
159 } else {
160 ATH_MSG_INFO("Scanning log for keyword \"{}\". CAVEAT EMPTOR - THIS IS VERY SLOW!!",
161 m_keywords);
162 }
163 } else {
164 ATH_MSG_ERROR("could not dcast LoggedMessageSvc to IProperty");
165 }
166 }
167 }
168
169 std::string fmt = m_summaryFormat.value();
170 tolower(fmt);
172
173 // save some space for the summary output if we run out of memory
174 ATH_MSG_DEBUG("allocating block of 100 pages");
175 const long pageSize = sysconf( _SC_PAGESIZE );
176 if (pageSize < 1 || pageSize > 1024*1024*1024) {
177 ATH_MSG_FATAL ("Bad page size from sysconf");
178 return StatusCode::FAILURE;
179 }
180 s_block = new char[ pageSize * 100 ];
181
182
183 return StatusCode(s_block!=nullptr);
184
185}
186
187/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
188
190
191 delete[] s_block; s_block = nullptr;
192 long pageSize = sysconf( _SC_PAGESIZE );
193 if (pageSize < 1 || pageSize > 1024*1024*1024) {
194 ATH_MSG_FATAL ("Bad page size from sysconf");
195 return StatusCode::FAILURE;
196 }
197 s_block = new char[ pageSize * 100 ];
198 return s_block ? StatusCode::SUCCESS : StatusCode::FAILURE;
199
200}
201/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
202
204
205 createSummary().ignore();
206
207 // cleanup
208 delete[] s_block; s_block = nullptr;
209 std::set_new_handler( m_new );
210
211 return StatusCode::SUCCESS;
212}
213
214/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
215
216void
217AthenaSummarySvc::addListener( const std::string& inc ) {
218
219 ATH_MSG_DEBUG("now listening to incident {}", inc);
220
221 if (m_extraIncidents.find( inc ) == m_extraIncidents.end()) {
222 p_incSvc->addListener( this, inc, 100, true);
223 m_extraIncidents[inc] = map<string,int>();
224 } else {
225 ATH_MSG_INFO("already listening to Incident {}", inc);
226 }
227
228}
229
230/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
231
232void
233AthenaSummarySvc::addSummary(const std::string& dict, const std::string& info) {
234
235 ATH_MSG_DEBUG("adding extra info: {}/{}", dict, info);
236
237 m_extraInfo.push_back( make_pair(dict,info) );
238
239}
240
241
242/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
243
244void
246
247 s_badalloc = true;
248
249 if ( ! s_block )
250 throw std::bad_alloc(); // default behavior (no print-out)
251
252 // release our block to create working space for finalize()
253 delete[] s_block; s_block = nullptr;
254
255 // print onto std::cerr rather than MsgStream, as it's more innocuous
256 std::println (std::cerr, "AthenaSummarySvc FATAL out of memory: saving summary ...");
257
258 SmartIF<IAthenaSummarySvc> ipa(Gaudi::svcLocator()->service("AthenaSummarySvc"));
259
260 if (ipa) {
261 std::string btrace;
262 if ( System::backTrace(btrace,5,3) ) {
263 ipa->addSummary("badalloc backtrace",btrace);
264 }
265
266 ipa->setStatus(99);
267 ipa->createSummary().ignore();
268 } else {
269 std::println (std::cerr, "AthenaSummarySvc ERROR unable to get hold of myself and print summary");
270 }
271
272
273 // in order to abort the job, throw a bad_alloc, which should make its way
274 // through to python, even if the ExceptionSvc is used, and that will shutdown
275 // (finalize/terminate) the application on exit
276 throw std::bad_alloc();
277
278}
279
280/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
281
282void
283AthenaSummarySvc::handle(const Incident &inc) {
284
285 ATH_MSG_DEBUG("handle incident: {} {}", inc.type(), inc.source());
286
287 string fileName;
288
289 const FileIncident *fi = dynamic_cast<const FileIncident*>( &inc );
290 if (fi != nullptr) {
291 // FIXME!!! waiting on AthenaPoolKernel-00-00-07
292 ATH_MSG_INFO(" -> file incident: {} [GUID: {}]",
293 fi->fileName(), fi->fileGuid());
294 fileName = fi->fileName();
295 } else {
296 fileName = inc.source();
297 }
298
299 if (inc.type() == "BeginInputFile" ) {
300 m_inputFilesRead.emplace_back( std::move(fileName) );
301 } else if (inc.type() == "BeginOutputFile") {
302 m_outputFiles.emplace_back( std::move(fileName) );
303 } else if (inc.type() == "FailOutputFile") {
304 m_outputFilesError.push_back( std::move(fileName) );
305 } else if (inc.type() == "BeginEvent") {
306 m_eventsRead ++;
307 } else if (inc.type() == "SkipEvent") {
309 } else if (inc.type() == "WriteEvent") {
311 } else if (inc.type() == "BeginRun") {
312 m_runs ++;
313 } else if (inc.type() == "EndRun") {
314 }
315
316 map<std::string, map<string,int> >::iterator itr
317 ( m_extraIncidents.find(inc.type()) );
318
319 if (itr != m_extraIncidents.end()) {
320 map<string,int>::iterator it = itr->second.find(inc.source());
321 if (it != itr->second.end()) {
322 m_extraIncidents[inc.type()][inc.source()]++;
323 } else {
324 m_extraIncidents[inc.type()][inc.source()] = 1;
325 }
326 }
327
328}
329
330
331/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
332
333StatusCode
335
336 ATH_MSG_DEBUG("createSummary");
337
338 std::ofstream ofs;
339 ofs.open(m_summaryFile.value().c_str());
340 if (!ofs) {
341 ATH_MSG_ERROR("Unable to open output file \"{}\"",
342 m_summaryFile.value());
343 return StatusCode::FAILURE;
344 }
345
346 ATH_MSG_DEBUG("Writing to \"{}\"", m_summaryFile.value());
347
348 if (m_summaryFormat.value() == "ascii" || m_summaryFormat.value() == "both") {
349 createASCII(ofs);
350 }
351
352 if (m_summaryFormat.value() == "python" || m_summaryFormat.value() == "both") {
353 createDict(ofs);
354 }
355
356 ofs.close();
357
358 return StatusCode::SUCCESS;
359
360
361}
362
363/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
364
365void
366AthenaSummarySvc::createASCII( std::ofstream& ofs ) {
367
368 ATH_MSG_DEBUG("createASCII");
369
370 list<string>::const_iterator itr;
371
372 std::println (ofs, "Files read: {}", m_inputFilesRead.size());
373 for (itr=m_inputFilesRead.begin(); itr != m_inputFilesRead.end(); ++itr) {
374 std::println (ofs, " {}", *itr);
375 }
376
377 std::println (ofs, "Files written: {}", m_outputFiles.size());
378 for (itr=m_outputFiles.begin(); itr != m_outputFiles.end(); ++itr) {
379 std::println (ofs, " {}", *itr);
380 }
381
382 std::println (ofs, "File Write Error: {}", m_outputFilesError.size());
383 for (itr=m_outputFilesError.begin(); itr != m_outputFilesError.end(); ++itr) {
384 std::println (ofs, " {}", *itr);
385 }
386
387 std::println (ofs, "Events Read: {}", m_eventsRead);
388 std::println (ofs, "Events Written: {}", m_eventsWritten);
389 std::println (ofs, "Events Skipped: {}", m_eventsSkipped);
390
391 std::println (ofs, "Runs: {}", m_runs);
392
393
394 std::println (ofs, "Message Count: ");
395 std::println (ofs, " FATAL: {}", msgSvc()->messageCount( MSG::FATAL ));
396 std::println (ofs, " ERROR: {}", msgSvc()->messageCount( MSG::ERROR ));
397 std::println (ofs, " WARNING: {}", msgSvc()->messageCount( MSG::WARNING ));
398 std::println (ofs, " INFO: {}", msgSvc()->messageCount( MSG::INFO ));
399
400 if (p_logMsg != nullptr) {
401
402 IntegerProperty thresh("loggingLevel",MSG::VERBOSE);
403 IProperty *ip = dynamic_cast<IProperty*>( p_logMsg );
404 if (ip != nullptr) {
405 if (ip->getProperty(&thresh).isFailure()) {
406 ATH_MSG_ERROR("could not get loggingLevel property of LoggedMessageSvc");
407 }
408 } else {
409 ATH_MSG_ERROR("could not dcast LoggedMessageSvc to IProperty");
410 }
411
412
413
414 std::println (ofs, "Message Log: ");
415 vector<pair<string,string> > msgs;
416 vector<pair<string,string> >::const_iterator mitr;
417 for (unsigned int l=thresh.value(); l < MSG::ALWAYS; l++) {
418 std::print (ofs, " {}", levelNames[l]);
419 msgs = p_logMsg->getMessages( MSG::Level(l) );
420 std::println (ofs, " {}", msgs.size());
421 for (mitr=msgs.begin(); mitr != msgs.end(); ++mitr) {
422 std::println (ofs, " {} : {}", mitr->first, mitr->second);
423 }
424 }
425
426 std::println (ofs, "Keyword tracked messages: ");
427 for (const auto& msg : p_logMsg->getKeyMessages()) {
428 std::println (ofs, " {} {} {}",
429 levelNames[msg.level], msg.source, msg.message);
430 }
431
432 }
433
434 if (m_extraInfo.size() > 0) {
435 std::println (ofs, "Extra Summary Info:");
436 vector<pair<string,string> >::const_iterator itr (m_extraInfo.begin() );
437 for (; itr != m_extraInfo.end(); ++itr) {
438 std::println (ofs, " {} : {}", itr->first, itr->second);
439 }
440 }
441
442 if (m_extraIncidents.size() > 0) {
443 std::println (ofs, "Extra Incident Counts:");
444 map<string, map<string,int> >::const_iterator itr(m_extraIncidents.begin());
445 for (; itr != m_extraIncidents.end(); ++itr) {
446 std::print (ofs, " {}", itr->first);
447 if (itr->second.begin() == itr->second.end()) {
448 std::println (ofs, " : 0");
449 } else {
450 for (map<string,int>::const_iterator it=itr->second.begin();
451 it != itr->second.end(); ++it) {
452 std::print (ofs, " :: {}: {}", it->first, it->second);
453 }
454 std::println (ofs);
455 }
456 }
457 }
458
459 if (s_badalloc) {
460 std::println (ofs, "std::bad_alloc caught: out of memory condition detected");
461 }
462
463 std::println (ofs, "Exit Status: {}", m_status);
464
465
466}
467/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
468
469void
470AthenaSummarySvc::createDict( std::ofstream& ofd) {
471
472 ATH_MSG_DEBUG("createDict");
473
474 list<string>::const_iterator itr;
475
476 PD p;
477
478 PD files;
479 string f;
480 for (itr=m_inputFilesRead.begin(); itr != m_inputFilesRead.end(); ++itr) {
481 if (f.length() > 0) { f += ","; }
482 f += *itr;
483 }
484 files.add("read",f);
485
486 f.clear();
487 for (itr=m_outputFiles.begin(); itr != m_outputFiles.end(); ++itr) {
488 if (f.length() > 0) { f += ","; }
489 f += *itr;
490 }
491 files.add("write",f);
492
493 f.clear();
494 for (itr=m_outputFilesError.begin(); itr != m_outputFilesError.end(); ++itr) {
495 if (f.length() > 0) { f += ","; }
496 f += *itr;
497 }
498 files.add("write error",f);
499
500 p.add("files",files);
501
502 PD events;
503 events.add("read",m_eventsRead);
504 events.add("write",m_eventsWritten);
505 events.add("skip",m_eventsSkipped);
506
507 p.add("events",events);
508
509 p.add("runs",m_runs);
510
511 PD msg;
512 msg.add("FATAL",msgSvc()->messageCount( MSG::FATAL ));
513 msg.add("ERROR",msgSvc()->messageCount( MSG::ERROR ));
514 msg.add("WARNING",msgSvc()->messageCount( MSG::WARNING ));
515 msg.add("INFO",msgSvc()->messageCount( MSG::INFO ));
516
517 p.add("message count",msg);
518
519 if (p_logMsg != nullptr) {
520
521 IntegerProperty thresh("loggingLevel",MSG::VERBOSE);
522 IProperty *ip = dynamic_cast<IProperty*>( p_logMsg );
523 if (ip != nullptr) {
524 if (ip->getProperty(&thresh).isFailure()) {
525 ATH_MSG_ERROR("could not get loggingLevel property of LoggedMessageSvc");
526 }
527 } else {
528 ATH_MSG_ERROR("could not dcast LoggedMessageSvc to IProperty");
529 }
530
531 PD mlog;
532 vector<pair<string,string> > msgs;
533 vector<pair<string,string> >::const_iterator mitr;
534 for (unsigned int l=thresh.value(); l < MSG::ALWAYS; l++) {
535 PD slog;
536 msgs = p_logMsg->getMessages( MSG::Level(l) );
537 for (mitr=msgs.begin(); mitr != msgs.end(); ++mitr) {
538 slog.add(mitr->first, mitr->second);
539 }
540 mlog.add(levelNames[l],slog);
541 }
542
543 p.add("messages",mlog);
544
545 }
546
547 if (m_extraInfo.size() > 0) {
548 PD user;
549 vector<pair<string,string> >::const_iterator itr (m_extraInfo.begin() );
550 for (; itr != m_extraInfo.end(); ++itr) {
551 string dat = itr->second;
552 while( dat.find("\n") != string::npos) {
553 dat.erase(dat.find("\n"),1);
554 }
555 user.add(itr->first, dat);
556 }
557 p.add("user data",user);
558 }
559
560 if (m_extraIncidents.size() > 0) {
561 PD inc;
562 map<string, map<string,int> >::const_iterator itr(m_extraIncidents.begin());
563 for (; itr != m_extraIncidents.end(); ++itr) {
564 if (itr->second.begin() == itr->second.end()) {
565 inc.add(itr->first,0);
566 } else {
567 PD inc2;
568 for (map<string,int>::const_iterator it=itr->second.begin();
569 it != itr->second.end(); ++it) {
570 inc2.add(it->first, it->second);
571 }
572 inc.add(itr->first, inc2);
573 }
574 }
575
576// PD inc;
577// map<string, int>::const_iterator itr(m_extraIncidents.begin());
578// for (; itr != m_extraIncidents.end(); ++itr) {
579// inc.add(itr->first, itr->second);
580// }
581
582 p.add("extra incidents",inc);
583 }
584
585 p.add("exit",m_status);
586 p.add("bad_alloc",s_badalloc);
587
588 std::println (ofd, "{}", p.dump());
589}
#define ATH_MSG_DEBUG(x,...)
#define ATH_MSG_ERROR(x,...)
#define ATH_MSG_INFO(x,...)
#define ATH_MSG_FATAL(x,...)
const char *const II("\001")
static constexpr std::string levelNames[MSG::NUM_LEVELS]
void tolower(std::string &s)
double length(const pvec &v)
static Double_t a
const char *const fmt
#define x
std::list< std::string > m_outputFilesError
StringArrayProperty m_extraInc
virtual StatusCode createSummary() override
std::vector< std::pair< std::string, std::string > > m_extraInfo
StringArrayProperty m_keywords
void createASCII(std::ofstream &)
unsigned int m_eventsWritten
ServiceHandle< IIncidentSvc > p_incSvc
std::list< std::string > m_inputFilesRead
unsigned int m_runs
virtual void addListener(const std::string &incident_name) override
std::new_handler m_new
std::map< std::string, std::map< std::string, int > > m_extraIncidents
StringProperty m_summaryFile
std::list< std::string > m_outputFiles
void createDict(std::ofstream &)
AthenaSummarySvc(const std::string &name, ISvcLocator *svc)
virtual StatusCode initialize() override
virtual StatusCode reinitialize() override
StringProperty m_summaryFormat
virtual StatusCode finalize() override
virtual void handle(const Incident &inc) override
virtual void addSummary(const std::string &dict_key, const std::string &data) override
static void newHandler()
ILoggedMessageSvc * p_logMsg
unsigned int m_eventsRead
unsigned int m_eventsSkipped
Extends IMessageSvc to get logged messages.
void add(const string &a, const T t)
void add(const string &a, const char *b)
PD(const string &a, const string &b)
string dump() const
void add(const string &a, const string &b)
void add(const string &a, const PD &p)
map< string, vector< string > > m_dat
STL iterator class.
STL iterator class.
std::vector< std::string > files
file names and file pointers
Definition hcg.cxx:52
STL namespace.
MsgStream & msg
Definition testRead.cxx:32