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