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