ATLAS Offline Software
Loading...
Searching...
No Matches
Worker.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
6
7
8//
9// includes
10//
11
12#include <EventLoop/Worker.h>
13
16#include <EventLoop/BatchJob.h>
19#include <EventLoop/Driver.h>
21#include <EventLoop/Job.h>
23#include <EventLoop/Module.h>
37#include <TFile.h>
38#include <TH1.h>
39#include <TROOT.h>
40#include <TSystem.h>
41#include <TTree.h>
42#include <TObjString.h>
43#include <fstream>
44#include <memory>
45#include <stdexcept>
46#include <exception>
47
48//
49// method implementations
50//
51
52namespace EL
53{
54 namespace
55 {
56 StatusCode make_module (std::unique_ptr<Detail::Module>& module, asg::AsgComponentConfig config)
57 {
58 using namespace msgEventLoop;
59 ANA_MSG_DEBUG ("making EventLoop module of type " + config.type());
60 ANA_CHECK (config.makeComponentExpert (module, "new %1% (\"%2%\")", false, "ELModule."));
61 ANA_MSG_DEBUG ("Created EventLoop module of type " << config.type());
62 return StatusCode::SUCCESS;
63 }
64 }
65
66
67
68 void Worker ::
69 testInvariant () const
70 {
71 RCU_INVARIANT (this != nullptr);
72 for (std::size_t iter = 0, end = m_algs.size(); iter != end; ++ iter)
73 {
74 RCU_INVARIANT (m_algs[iter].m_algorithm != nullptr);
75 }
76 }
77
78
79
80 Worker ::
81 ~Worker ()
82 {
84 }
85
86
87
88 void Worker ::
89 addOutput (TObject *output_swallow)
90 {
91 std::unique_ptr<TObject> output (output_swallow);
92
94 RCU_REQUIRE_SOFT (output_swallow != 0);
95
96 RCU::SetDirectory (output_swallow, 0);
97 ModuleData::addOutput (std::move (output));
98 }
99
100
101
102 void Worker ::
103 addOutputList (const std::string& name, TObject *output_swallow)
104 {
105 std::unique_ptr<TObject> output (output_swallow);
106
108 RCU_REQUIRE_SOFT (output_swallow != 0);
109
110 RCU::SetDirectory (output_swallow, 0);
111 std::unique_ptr<TList> list (new TList);
112 list->SetName (name.c_str());
113 list->Add (output.release());
114 addOutput (list.release());
115 }
116
117
118
119 TObject *Worker ::
120 getOutputHist (const std::string& name) const
121 {
122 RCU_READ_INVARIANT (this);
123
124 TObject *result = m_histOutput->getOutputHist (name);
125 if (result == nullptr) throw std::runtime_error ("unknown output histogram: " + name);
126 return result;
127 }
128
129
130
131 TFile *Worker ::
132 getOutputFile (const std::string& label) const
133 {
134 RCU_READ_INVARIANT (this);
135 TFile *result = getOutputFileNull (label);
136 if (result == 0)
137 throw std::runtime_error ("no output dataset defined with label: " + label);
138 return result;
139 }
140
141
142
143 TFile *Worker ::
144 getOutputFileNull (const std::string& label) const
145 {
146 RCU_READ_INVARIANT (this);
147 auto iter = m_outputs.find (label);
148 if (iter == m_outputs.end())
149 return 0;
150 return iter->second->file();
151 }
152
153
154
156 addTree( const TTree& tree, const std::string& stream )
157 {
158 using namespace msgEventLoop;
159 RCU_READ_INVARIANT( this );
160
161 auto outputIter = m_outputs.find (stream);
162 if (outputIter == m_outputs.end())
163 {
164 ANA_MSG_ERROR ( "No output file with stream name \"" + stream +
165 "\" found" );
166 return ::StatusCode::FAILURE;
167 }
168
169 outputIter->second->addClone (tree);
170
171 // Return gracefully:
172 return ::StatusCode::SUCCESS;
173 }
174
175
176
177 TTree *Worker::
178 getOutputTree( const std::string& name, const std::string& stream ) const
179 {
180 using namespace msgEventLoop;
181 RCU_READ_INVARIANT( this );
182
183 auto outputIter = m_outputs.find (stream);
184 if (outputIter == m_outputs.end())
185 {
186 throw std::runtime_error ("No output file with stream name \"" + stream + "\" found");
187 }
188
189 TTree *result = outputIter->second->getOutputTree( name );
190 if( result == nullptr ) {
191 throw std::runtime_error ("No tree with name \"" + name + "\" in stream \"" + stream + "\"");
192 }
193 return result;
194 }
195
196
197
198 const SH::MetaObject *Worker ::
199 metaData () const
200 {
201 RCU_READ_INVARIANT (this);
202 return m_metaData;
203 }
204
205
206
207 TTree *Worker ::
208 tree () const
209 {
210 RCU_READ_INVARIANT (this);
211 return m_inputTree;
212 }
213
214
215
216 Long64_t Worker ::
217 treeEntry () const
218 {
219 RCU_READ_INVARIANT (this);
220 return m_inputEntry;
221 }
222
223
224
225 TFile *Worker ::
226 inputFile () const
227 {
228 RCU_READ_INVARIANT (this);
229 return m_inputFile.get();
230 }
231
232
233 bool Worker ::
234 hasInputEvents () const
235 {
236 // no invariant used
237 return m_hasInputEvents;
238 }
239
240
241 std::string Worker ::
242 inputFileName () const
243 {
244 // no invariant used
245 std::string path = inputFile()->GetName();
246 auto split = path.rfind ('/');
247 if (split != std::string::npos)
248 return path.substr (split + 1);
249 else
250 return path;
251 }
252
253
254
255 TTree *Worker ::
256 triggerConfig () const
257 {
258 RCU_READ_INVARIANT (this);
259 return dynamic_cast<TTree*>(inputFile()->Get("physicsMeta/TrigConfTree"));
260 }
261
262
263
264 xAOD::Event *Worker ::
265 xaodEvent () const
266 {
267 RCU_READ_INVARIANT (this);
268
269 if (m_event == nullptr)
270 throw std::runtime_error ("Worker::xaodEvent: Job not configured for xAOD support");
271 return m_event;
272 }
273
274
275
276 xAOD::TStore *Worker ::
277 xaodStore () const
278 {
279 RCU_READ_INVARIANT (this);
280
281 if (m_tstore == nullptr)
282 throw std::runtime_error ("Worker::xaodStore: Job not configured for xAOD support");
283 return m_tstore;
284 }
285
286
287
288 Algorithm *Worker ::
289 getAlg (const std::string& name) const
290 {
291 RCU_READ_INVARIANT (this);
292 for (auto& alg : m_algs)
293 {
294 if (alg->hasName (name))
295 return alg.m_algorithm->getLegacyAlg();
296 }
297 return 0;
298 }
299
300
301
302 void Worker ::
303 skipEvent ()
304 {
306 m_skipEvent = true;
307 }
308
309
310
311 bool Worker ::
312 filterPassed () const noexcept
313 {
314 RCU_READ_INVARIANT (this);
315 return !m_skipEvent;
316 }
317
318
319
320 void Worker ::
321 setFilterPassed (bool val_filterPassed) noexcept
322 {
324 m_skipEvent = !val_filterPassed;
325 }
326
327
328
329 Worker ::
330 Worker ()
331 {
332 m_worker = this;
333
334 RCU_NEW_INVARIANT (this);
335 }
336
337
338
339 void Worker ::
340 setMetaData (const SH::MetaObject *val_metaData)
341 {
343 RCU_REQUIRE (val_metaData != 0);
344
345 m_metaData = val_metaData;
346 }
347
348
349
350 void Worker ::
351 setOutputHist (const std::string& val_outputTarget)
352 {
354
355 m_outputTarget = val_outputTarget;
356 }
357
358
359
360 void Worker ::
361 setSegmentName (const std::string& val_segmentName)
362 {
364
365 m_segmentName = val_segmentName;
366 }
367
368
369
370 void Worker ::
371 setJobConfig (JobConfig&& jobConfig)
372 {
374 for (auto& alg : jobConfig.extractAlgorithms())
375 {
376 m_algs.push_back (std::move (alg));
377 }
378 }
379
380
381
382 ::StatusCode Worker ::
383 initialize ()
384 {
385 using namespace msgEventLoop;
387
388 const bool xAODInput = m_metaData->castBool (Job::optXAODInput, false);
389
390 ANA_MSG_INFO ("xAODInput = " << xAODInput);
391
392 if (metaData()->castBool (Job::optAlgorithmMemoryMonitor, false))
393 m_moduleConfig.emplace_back ("EL::Detail::MemoryMonitorModule/EarlyMemoryMonitorModule");
394 if (auto cacheSize = metaData()->castDouble (Job::optCacheSize, 0); cacheSize > 0)
395 {
396 m_moduleConfig.emplace_back ("EL::Detail::TreeCacheModule/TreeCacheModule");
397 ANA_CHECK (m_moduleConfig.back().setProperty ("cacheSize", Long64_t (cacheSize)));
398 ANA_CHECK (m_moduleConfig.back().setProperty ("cacheLearnEntries", Long64_t (metaData()->castInteger (Job::optCacheLearnEntries, 0))));
399 ANA_CHECK (m_moduleConfig.back().setProperty ("printPerFileStats", metaData()->castBool (Job::optPrintPerFileStats, false)));
400 }
401 if (xAODInput)
402 {
403 m_moduleConfig.emplace_back ("EL::Detail::EventModule/EventModule");
404 if (metaData()->castDouble (Job::optXAODSummaryReport, 1) == 0)
405 ANA_CHECK (m_moduleConfig.back().setProperty ("summaryReport", false));
406 ANA_CHECK (m_moduleConfig.back().setProperty ("useStats", metaData()->castBool (Job::optXAODPerfStats, false)));
407 }
408 auto factoryPreload = metaData()->castString (Job::optFactoryPreload, "");
409 if (!factoryPreload.empty())
410 {
411 m_moduleConfig.emplace_back ("EL::Detail::FactoryPreloadModule/FactoryPreloadModule");
412 ANA_CHECK (m_moduleConfig.back().setProperty ("preloader", factoryPreload));
413 }
414 m_moduleConfig.emplace_back ("EL::Detail::LeakCheckModule/LeakCheckModule");
415 ANA_CHECK (m_moduleConfig.back().setProperty ("failOnLeak", metaData()->castBool (Job::optMemFailOnLeak, false)));
416 ANA_CHECK (m_moduleConfig.back().setProperty ("absResidentLimit", metaData()->castInteger (Job::optMemResidentIncreaseLimit, 10000)));
417 ANA_CHECK (m_moduleConfig.back().setProperty ("absVirtualLimit", metaData()->castInteger (Job::optMemVirtualIncreaseLimit, 0)));
418 ANA_CHECK (m_moduleConfig.back().setProperty ("perEvResidentLimit", metaData()->castInteger (Job::optMemResidentPerEventIncreaseLimit, 10)));
419 ANA_CHECK (m_moduleConfig.back().setProperty ("perEvVirtualLimit", metaData()->castInteger (Job::optMemVirtualPerEventIncreaseLimit, 0)));
420 m_moduleConfig.emplace_back ("EL::Detail::StopwatchModule/StopwatchModule");
421 if (metaData()->castBool (Job::optGridReporting, false))
422 m_moduleConfig.emplace_back ("EL::Detail::GridReportingModule/GridReportingModule");
423 if (metaData()->castBool (Job::optAlgorithmTimer, false))
424 m_moduleConfig.emplace_back ("EL::Detail::AlgorithmTimerModule/AlgorithmTimerModule");
425 if (metaData()->castBool (Job::optAlgorithmMemoryMonitor, false))
426 m_moduleConfig.emplace_back ("EL::Detail::AlgorithmMemoryModule/AlgorithmMemoryModule");
427 m_moduleConfig.emplace_back ("EL::Detail::FileExecutedModule/FileExecutedModule");
428 m_moduleConfig.emplace_back ("EL::Detail::EventCountModule/EventCountModule");
429 m_moduleConfig.emplace_back ("EL::Detail::WorkerConfigModule/WorkerConfigModule");
430 m_moduleConfig.emplace_back ("EL::Detail::AlgorithmStateModule/AlgorithmStateModule");
431 m_moduleConfig.emplace_back ("EL::Detail::PostClosedOutputsModule/PostClosedOutputsModule");
432 if (metaData()->castBool (Job::optAlgorithmMemoryMonitor, false))
433 m_moduleConfig.emplace_back ("EL::Detail::MemoryMonitorModule/LateMemoryMonitorModule");
434
435 for (const auto& config : m_moduleConfig)
436 {
437 std::unique_ptr<Detail::Module> module;
438 ANA_CHECK (make_module (module, config));
439 m_modules.push_back (std::move (module));
440 }
441
442 if (m_outputs.find (Job::histogramStreamName) == m_outputs.end())
443 {
445 m_outputTarget + "/hist-" + m_segmentName + ".root", "RECREATE"};
447 }
450 if (auto aliases = metaData()->castString (Job::optStreamAliases, ""); !aliases.empty())
451 {
452 // the format of aliases is "alias1=realname1,alias2=realname2"
453 std::istringstream iss (aliases);
454 std::string alias;
455 while (std::getline (iss, alias, ','))
456 {
457 auto pos = alias.find ('=');
458 if (pos == std::string::npos)
459 {
460 ANA_MSG_ERROR ("Invalid alias format: " << alias);
461 return ::StatusCode::FAILURE;
462 }
463 auto aliasName = alias.substr (0, pos);
464 auto realName = alias.substr (pos + 1);
465 auto realOutput = m_outputs.find (realName);
466 if (realOutput == m_outputs.end())
467 {
468 ANA_MSG_ERROR ("output stream " << realName << " not found for alias " << aliasName);
469 return ::StatusCode::FAILURE;
470 }
471 auto [aliasOutput, success] = m_outputs.emplace (aliasName, realOutput->second);
472 if (!success)
473 {
474 ANA_MSG_ERROR ("output stream " << aliasName << " already exists, can't make alias");
475 return ::StatusCode::FAILURE;
476 }
477 }
478 }
479
480 m_jobStats = std::make_unique<TTree>
481 ("EventLoop_JobStats", "EventLoop job statistics");
482 m_jobStats->SetDirectory (nullptr);
483
484 ANA_MSG_INFO ("calling firstInitialize on all modules");
485 for (auto& module : m_modules)
486 ANA_CHECK (module->firstInitialize (*this));
487 ANA_MSG_INFO ("calling preFileInitialize on all modules");
488 for (auto& module : m_modules)
489 ANA_CHECK (module->preFileInitialize (*this));
490
491 return ::StatusCode::SUCCESS;
492 }
493
494
495
496 ::StatusCode Worker ::
497 processInputs ()
498 {
499 using namespace msgEventLoop;
500
502
503 for (auto& module : m_modules)
504 ANA_CHECK (module->processInputs (*this, *this));
505
506 return ::StatusCode::SUCCESS;
507 }
508
509
510
511 ::StatusCode Worker ::
512 finalize ()
513 {
514 using namespace msgEventLoop;
515
517
518 if (m_algorithmsInitialized == false)
519 {
520 ANA_MSG_ERROR ("algorithms never got initialized");
521 return StatusCode::FAILURE;
522 }
523
525 for (auto& module : m_modules)
526 ANA_CHECK (module->onFinalize (*this));
527 for (auto& output : m_outputs)
528 {
529 if (output.first != Job::histogramStreamName && output.second->mainStreamName() == output.first)
530 {
531 output.second->saveOutput ();
532 output.second->close ();
533 std::string path = output.second->finalFileName ();
534 if (!path.empty())
535 addOutputList ("EventLoop_OutputStream_" + output.first, new TObjString (path.c_str()));
536 }
537 }
538 for (auto& module : m_modules)
539 ANA_CHECK (module->postFinalize (*this));
540 if (m_jobStats->GetListOfBranches()->GetEntries() > 0)
541 {
542 if (m_jobStats->Fill() <= 0)
543 {
544 ANA_MSG_ERROR ("failed to fill the job statistics tree");
545 return ::StatusCode::FAILURE;
546 }
547 ModuleData::addOutput (std::move (m_jobStats));
548 }
549 m_histOutput->saveOutput ();
550 for (auto& module : m_modules)
551 ANA_CHECK (module->onWorkerEnd (*this));
552 m_histOutput->saveOutput ();
553 m_histOutput->close ();
554
555 for (auto& module : m_modules){
556 ANA_CHECK (module->postFileClose(*this));
557 }
558 ANA_MSG_INFO ("worker finished successfully");
559 return ::StatusCode::SUCCESS;
560 }
561
562
563
564 ::StatusCode Worker ::
565 processEvents (EventRange& eventRange)
566 {
567 using namespace msgEventLoop;
568
570 RCU_REQUIRE (!eventRange.m_url.empty());
571 RCU_REQUIRE (eventRange.m_beginEvent >= 0);
572 RCU_REQUIRE (eventRange.m_endEvent == EventRange::eof || eventRange.m_endEvent >= eventRange.m_beginEvent);
573
574 ANA_CHECK (openInputFile (eventRange.m_url));
575
576 if (eventRange.m_beginEvent > inputFileNumEntries())
577 {
578 ANA_MSG_ERROR ("first event (" << eventRange.m_beginEvent << ") points beyond last event in file (" << inputFileNumEntries() << ")");
579 return ::StatusCode::FAILURE;
580 }
581 if (eventRange.m_endEvent == EventRange::eof)
582 {
583 eventRange.m_endEvent = inputFileNumEntries();
584 } else if (eventRange.m_endEvent > inputFileNumEntries())
585 {
586 ANA_MSG_ERROR ("end event (" << eventRange.m_endEvent << ") points beyond last event in file (" << inputFileNumEntries() << ")");
587 return ::StatusCode::FAILURE;
588 }
589
590 m_inputEntry = eventRange.m_beginEvent;
591
592 if (m_algorithmsInitialized == false)
593 {
594 for (auto& module : m_modules)
595 ANA_CHECK (module->onInitialize (*this));
597 }
598
599 if (m_newInputFile)
600 {
601 m_newInputFile = false;
602 for (auto& module : m_modules)
603 ANA_CHECK (module->onNewInputFile (*this));
604 }
605
606 if (eventRange.m_beginEvent == 0)
607 {
608 for (auto& module : m_modules)
609 ANA_CHECK (module->onFileExecute (*this));
610 }
611
612 ANA_MSG_INFO ("Processing events " << eventRange.m_beginEvent << "-" << eventRange.m_endEvent << " in file " << eventRange.m_url);
613
614 for (uint64_t event = eventRange.m_beginEvent;
615 event != uint64_t (eventRange.m_endEvent);
616 ++ event)
617 {
618 m_inputEntry = event;
619 for (auto& module : m_modules)
620 {
621 if (module->onExecute (*this).isFailure())
622 {
623 ANA_MSG_ERROR ("processing event " << treeEntry() << " on file " << inputFileName());
624 return ::StatusCode::FAILURE;
625 }
626 }
627 if (m_firstEvent)
628 {
629 m_firstEvent = false;
630 for (auto& module : m_modules)
631 ANA_CHECK (module->postFirstEvent (*this));
632 }
634 if (m_eventsProcessed % 10000 == 0)
635 ANA_MSG_INFO ("Processed " << m_eventsProcessed << " events");
636 }
637 return ::StatusCode::SUCCESS;
638 }
639
640
641
642 bool Worker ::
643 fileOpenErrorFilter(int level, bool /*b1*/, const char* s1, const char * s2)
644 {
645 // Don't fail on missing dictionary messages.
646 if (strstr (s2, "no streamer or dictionary") != nullptr) {
647 return true;
648 }
649
650 // For messages above warning level (SysError, Error, Fatal)
651 if( level > kWarning ) {
652 // We won't output further; ROOT should have already put something in the log file
653 std::string msg = "ROOT error detected in Worker.cxx: ";
654 msg += s1;
655 msg += " ";
656 msg += s2;
657 throw std::runtime_error(msg);
658
659 // No need for further error handling
660 return false;
661 }
662
663 // Pass to the default error handlers
664 return true;
665 }
666
667 ::StatusCode Worker ::
668 openInputFile (const std::string& inputFileUrl)
669 {
670 using namespace msgEventLoop;
671
672 // Enable custom error handling in a nice way
674
676
677 if (m_inputFileUrl == inputFileUrl)
678 return ::StatusCode::SUCCESS;
679
680 if (!m_inputFileUrl.empty())
681 {
682 if (m_newInputFile == false)
683 {
684 for (auto& module : m_modules)
685 ANA_CHECK (module->onCloseInputFile (*this));
686 for (auto& module : m_modules)
687 ANA_CHECK (module->postCloseInputFile (*this));
688 }
689 m_newInputFile = false;
690 m_hasInputEvents = false;
691 m_inputTree = nullptr;
692 m_inputFile.reset ();
693 m_inputFileUrl.clear ();
694 }
695
696 if (inputFileUrl.empty())
697 return ::StatusCode::SUCCESS;
698
699 ANA_MSG_INFO ("Opening file " << inputFileUrl);
700 std::unique_ptr<TFile> inputFile;
701 try
702 {
703 inputFile = SH::openFile (inputFileUrl, *metaData());
704 } catch (...)
705 {
706 Detail::report_exception (std::current_exception());
707 }
708 if (inputFile.get() == 0)
709 {
710 ANA_MSG_ERROR ("failed to open file " << inputFileUrl);
711 for (auto& module : m_modules)
712 module->reportInputFailure (*this);
713 return ::StatusCode::FAILURE;
714 }
715 if (inputFile->IsZombie())
716 {
717 ANA_MSG_ERROR ("input file is a zombie: " << inputFileUrl);
718 for (auto& module : m_modules)
719 module->reportInputFailure (*this);
720 return ::StatusCode::FAILURE;
721 }
722
723 // Direct TTree access
724 TTree *tree = 0;
725 const std::string treeName
727 tree = dynamic_cast<TTree*>(inputFile->Get (treeName.c_str()));
728 if (tree == nullptr)
729 {
730 ANA_MSG_INFO ("tree " << treeName << " not found in input file: " << inputFileUrl);
731 ANA_MSG_INFO ("treating this like a tree with no events");
732 }
733 else {
734 m_hasInputEvents = (tree->GetEntries() > 0);
735 }
736
737 m_newInputFile = true;
739 m_inputEntry = 0;
740 m_inputFile = std::move (inputFile);
741 m_inputFileUrl = std::move (inputFileUrl);
742
743 // onFirstInputFile to setup Event object
745 {
746 for (auto& module : m_modules)
747 ANA_CHECK (module->onFirstInputFile (*this));
748 m_firstInputFile = false;
749 }
750 else {
751 for (auto& module : m_modules)
752 ANA_CHECK (module->onNextInputFile (*this));
753 }
754
755 // Check if we have input events - done above for TTree
756 if (m_inputTree == nullptr) {
757 if (m_event) m_hasInputEvents = (m_event->getEntries() > 0);
758 }
759
760 return ::StatusCode::SUCCESS;
761 }
762
763
764
765 ::StatusCode Worker ::
766 addOutputStream (const std::string& label,
768 {
769 using namespace msgEventLoop;
771
772 if (m_outputs.find (label) != m_outputs.end())
773 {
774 ANA_MSG_ERROR ("output file already defined for label: " + label);
775 return ::StatusCode::FAILURE;
776 }
777 if (data.file() == nullptr)
778 {
779 ANA_MSG_ERROR ("output stream does not have a file attached");
780 return ::StatusCode::FAILURE;
781 }
782 if (data.mainStreamName().empty())
783 data.setMainStreamName (label);
784 m_outputs.insert (std::make_pair (label, std::make_shared<Detail::OutputStreamData>(std::move (data))));
785 return ::StatusCode::SUCCESS;
786 }
787
788
789
790 Long64_t Worker ::
791 inputFileNumEntries () const
792 {
793 RCU_READ_INVARIANT (this);
794 RCU_REQUIRE (inputFile() != 0);
795
796 if (m_event) {
797 return m_event->getEntries();
798 }
799 else if (m_inputTree != 0)
800 return m_inputTree->GetEntries();
801 else
802 return 0;
803 }
804
805
806
807 uint64_t Worker ::
808 eventsProcessed () const noexcept
809 {
810 RCU_READ_INVARIANT (this);
811 return m_eventsProcessed;
812 }
813
814
815
816 ::StatusCode Worker ::
817 directExecute (const SH::Sample& sample, const Job& job,
818 const std::string& location, const SH::MetaObject& options)
819 {
820 using namespace msgEventLoop;
822
823 SH::MetaObject meta (*sample.meta());
824 meta.fetchDefaults (options);
825
826 setMetaData (&meta);
827 setOutputHist (location);
828 setSegmentName (sample.name());
829
830 ANA_MSG_INFO ("Running sample: " << sample.name());
831
832 setJobConfig (JobConfig (job.jobConfig()));
833
834 for (Job::outputIter out = job.outputBegin(),
835 end = job.outputEnd(); out != end; ++ out)
836 {
838 out->output()->makeWriter (sample.name(), "", ".root")};
839 ANA_CHECK (addOutputStream (out->label(), std::move (data)));
840 }
841
842 {
843 m_moduleConfig.emplace_back ("EL::Detail::DirectInputModule/DirectInputModule");
844 ANA_CHECK (m_moduleConfig.back().setProperty ("fileList", sample.makeFileList()));
845 Long64_t maxEvents = metaData()->castDouble (Job::optMaxEvents, -1);
846 if (maxEvents != -1)
847 ANA_CHECK (m_moduleConfig.back().setProperty ("maxEvents", maxEvents));
848 Long64_t skipEvents = metaData()->castDouble (Job::optSkipEvents, 0);
849 if (skipEvents != 0)
850 ANA_CHECK (m_moduleConfig.back().setProperty ("skipEvents", skipEvents));
851 }
852
855 ANA_CHECK (finalize ());
856 return ::StatusCode::SUCCESS;
857 }
858
859
860
861 ::StatusCode Worker ::
862 batchExecute (unsigned job_id, const char *confFile)
863 {
864 using namespace msgEventLoop;
866
867 try
868 {
869 std::unique_ptr<TFile> file (TFile::Open (confFile, "READ"));
870 if (file.get() == nullptr || file->IsZombie())
871 {
872 ANA_MSG_ERROR ("failed to open file: " << confFile);
873 return ::StatusCode::FAILURE;
874 }
875
876 std::unique_ptr<BatchJob> job (dynamic_cast<BatchJob*>(file->Get ("job")));
877 m_batchJob = job.get();
878 if (job.get() == nullptr)
879 {
880 ANA_MSG_ERROR ("failed to retrieve BatchJob object");
881 return ::StatusCode::FAILURE;
882 }
883
884 if (job_id >= job->segments.size())
885 {
886 ANA_MSG_ERROR ("invalid job-id " << job_id << ", max is " << job->segments.size());
887 return ::StatusCode::FAILURE;
888 }
889 BatchSegment *segment = &job->segments[job_id];
890 RCU_ASSERT (segment->job_id == job_id);
891 RCU_ASSERT (segment->sample < job->samples.size());
892 BatchSample *sample = &job->samples[segment->sample];
893
894 gSystem->Exec ("pwd");
895 gSystem->MakeDirectory ("output");
896
897 setMetaData (&sample->meta);
898 setOutputHist (job->location + "/fetch");
899 setSegmentName (segment->fullName);
900
901 setJobConfig (JobConfig (job->job.jobConfig()));
902
903 for (Job::outputIter out = job->job.outputBegin(),
904 end = job->job.outputEnd(); out != end; ++ out)
905 {
907 out->output()->makeWriter (segment->sampleName, segment->segmentName, ".root")};
908 ANA_CHECK (addOutputStream (out->label(), std::move (data)));
909 }
910
911 {
912 m_moduleConfig.emplace_back ("EL::Detail::BatchInputModule/BatchInputModule");
913 ANA_CHECK (m_moduleConfig.back().setProperty ("jobId", job_id));
914 Long64_t maxEvents = metaData()->castDouble (Job::optMaxEvents, -1);
915 if (maxEvents != -1)
916 ANA_CHECK (m_moduleConfig.back().setProperty ("maxEvents", maxEvents));
917 }
918
921 ANA_CHECK (finalize ());
922
923 std::ostringstream job_name;
924 job_name << job_id;
925 std::ofstream completed ((job->location + "/status/completed-" + job_name.str()).c_str());
926 return ::StatusCode::SUCCESS;
927 } catch (...)
928 {
929 Detail::report_exception (std::current_exception());
930 return ::StatusCode::FAILURE;
931 }
932 }
933
934
935
936 ::StatusCode Worker ::
937 gridExecute (const std::string& sampleName, Long64_t SkipEvents, Long64_t nEventsPerJob)
938 {
939 using namespace msgEventLoop;
941
942 ANA_MSG_INFO ("Running with ROOT version " << gROOT->GetVersion()
943 << " (" << gROOT->GetVersionDate() << ")");
944
945 ANA_MSG_INFO ("Loading EventLoop grid job");
946
947
948 TList bigOutputs;
949 std::unique_ptr<JobConfig> jobConfig;
950 SH::MetaObject *mo = 0;
951
952 std::unique_ptr<TFile> f (TFile::Open("jobdef.root"));
953 if (f == nullptr || f->IsZombie()) {
954 ANA_MSG_ERROR ("Could not read jobdef");
955 return ::StatusCode::FAILURE;
956 }
957
958 mo = dynamic_cast<SH::MetaObject*>(f->Get(sampleName.c_str()));
959 if (!mo)
960 mo = dynamic_cast<SH::MetaObject*>(f->Get("defaultMetaObject"));
961 if (!mo) {
962 ANA_MSG_ERROR ("Could not read in sample meta object");
963 return ::StatusCode::FAILURE;
964 }
965
966 jobConfig.reset (dynamic_cast<JobConfig*>(f->Get("jobConfig")));
967 if (jobConfig == nullptr)
968 {
969 ANA_MSG_ERROR ("failed to read jobConfig object");
970 return ::StatusCode::FAILURE;
971 }
972
973 {
974 std::unique_ptr<TList> outs ((TList*)f->Get("outputs"));
975 if (outs == nullptr)
976 {
977 ANA_MSG_ERROR ("Could not read list of outputs");
978 return ::StatusCode::FAILURE;
979 }
980
981 TIter itr(outs.get());
982 TObject *obj = 0;
983 while ((obj = itr())) {
984 EL::OutputStream * out = dynamic_cast<EL::OutputStream*>(obj);
985 if (out) {
986 bigOutputs.Add(out);
987 }
988 else {
989 ANA_MSG_ERROR ("Encountered unexpected entry in list of outputs");
990 return ::StatusCode::FAILURE;
991 }
992 }
993 }
994
995 f->Close();
996 f.reset ();
997
998 const std::string location = ".";
999
1000 mo->setBool (Job::optGridReporting, true);
1001 setMetaData (mo);
1002 setOutputHist (location);
1003 setSegmentName ("output");
1004
1005 ANA_MSG_INFO ("Starting EventLoop Grid worker");
1006
1007 {//Create and register the "big" output files with base class
1008 TIter itr(&bigOutputs);
1009 TObject *obj = 0;
1010 while ((obj = itr())) {
1011 EL::OutputStream *os = dynamic_cast<EL::OutputStream*>(obj);
1012 if (os == nullptr)
1013 {
1014 ANA_MSG_ERROR ("Bad input");
1015 return ::StatusCode::FAILURE;
1016 }
1017 {
1019 location + "/" + os->label() + ".root", "RECREATE"};
1020 ANA_CHECK (addOutputStream (os->label(), std::move (data)));
1021 }
1022 }
1023 }
1024
1025 setJobConfig (std::move (*jobConfig));
1026
1027 {
1028 std::vector<std::string> fileList;
1029 std::ifstream infile("input.txt");
1030 while (infile) {
1031 std::string sLine;
1032 if (!getline(infile, sLine)) break;
1033 std::istringstream ssLine(sLine);
1034 while (ssLine) {
1035 std::string sFile;
1036 if (!getline(ssLine, sFile, ',')) break;
1037 fileList.push_back(sFile);
1038 }
1039 }
1040 if (fileList.size() == 0) {
1041 ANA_MSG_ERROR ("no input files provided");
1042 //User was expecting input after all.
1043 gSystem->Exit(EC_BADINPUT);
1044 }
1045 m_moduleConfig.emplace_back ("EL::Detail::DirectInputModule/DirectInputModule");
1046 ANA_CHECK (m_moduleConfig.back().setProperty ("fileList", fileList));
1047
1048 if (nEventsPerJob != -1)
1049 ANA_CHECK (m_moduleConfig.back().setProperty ("maxEvents", nEventsPerJob));
1050 if (SkipEvents != 0)
1051 ANA_CHECK (m_moduleConfig.back().setProperty ("skipEvents", SkipEvents));
1052 }
1053
1056 ANA_CHECK (finalize ());
1057
1058 int nEvents = eventsProcessed();
1059 ANA_MSG_INFO ("Loop finished.");
1060 ANA_MSG_INFO ("Read/processed " << nEvents << " events.");
1061
1062 ANA_MSG_INFO ("EventLoop Grid worker finished");
1063 ANA_MSG_INFO ("Saving output");
1064 return ::StatusCode::SUCCESS;
1065 }
1066}
#define RCU_INVARIANT(x)
Definition Assert.h:189
#define RCU_ASSERT(x)
Definition Assert.h:210
#define RCU_DESTROY_INVARIANT(x)
Definition Assert.h:223
#define RCU_CHANGE_INVARIANT(x)
Definition Assert.h:219
#define RCU_NEW_INVARIANT(x)
Definition Assert.h:221
#define RCU_REQUIRE(x)
Definition Assert.h:196
#define RCU_REQUIRE_SOFT(x)
Definition Assert.h:141
#define RCU_READ_INVARIANT(x)
Definition Assert.h:217
#define ANA_MSG_INFO(xmsg)
Macro printing info messages.
#define ANA_MSG_ERROR(xmsg)
Macro printing error messages.
#define ANA_MSG_DEBUG(xmsg)
Macro printing debug messages.
#define ANA_CHECK(EXP)
check whether the given expression was successful
Run a MT piece of code with an alternate root error handler.
all data needed to manage a given output stream
the job configuration that is independent of driver and dataset
Definition JobConfig.h:45
Definition Job.h:42
static const std::string optPrintPerFileStats
description: the option to turn on printing of i/o statistics at the end of each file rationale: whil...
Definition Job.h:404
static const std::string optMemFailOnLeak
Failure behaviour of the code when a "significant memory leak" is found.
Definition Job.h:586
static const std::string optMaxEvents
description: the name of the option used for setting the maximum number of events to process per samp...
Definition Job.h:221
static const std::string optGridReporting
whether to use grid reporting even when not running on the grid
Definition Job.h:489
static const std::string optAlgorithmTimer
a boolean flag for whether to add a timer for the algorithms
Definition Job.h:201
static const std::string optMemResidentIncreaseLimit
The minimal resident memory increase necessary to trigger an error.
Definition Job.h:564
static const std::string optXAODPerfStats
description: the name of the option for turning on XAODPerfStats.
Definition Job.h:352
const OutputStream * outputIter
Definition Job.h:139
static const std::string optXAODSummaryReport
the option to turn on/off the xAOD summary reporting at the end of the job
Definition Job.h:394
static const std::string optCacheLearnEntries
description: this option allows to configure the number of tree entries used for learning cache behav...
Definition Job.h:323
static const std::string optCacheSize
description: this option allows to configure the TTreeCache size for this job.
Definition Job.h:308
static const std::string optAlgorithmMemoryMonitor
a boolean flag for whether to add a memory monitor for the algorithms
Definition Job.h:206
static const std::string optXAODInput
the option to select whether our input is xAODs
Definition Job.h:389
static const std::string optMemResidentPerEventIncreaseLimit
The minimal per-event resident memory increase for triggering an error.
Definition Job.h:546
static const std::string optMemVirtualIncreaseLimit
The minimal virtual memory increase necessary to trigger an error.
Definition Job.h:572
static const std::string optMemVirtualPerEventIncreaseLimit
The minimal per-event virtual memory increase for triggering an error.
Definition Job.h:556
static const std::string optSkipEvents
description: the name of the option used for skipping a certain number of events in the beginning rat...
Definition Job.h:229
static const std::string optStreamAliases
an option for stream aliases
Definition Job.h:213
static const std::string optFactoryPreload
a boolean flag for whether to perform a component factory preload
Definition Job.h:210
static const std::string histogramStreamName
the name of the histogram output stream
Definition Job.h:597
Long64_t treeEntry() const override
description: the entry in the tree we are reading guarantee: no-fail
Definition Worker.cxx:217
std::string inputFileName() const override
the name of the file we are reading the current tree from, without the path component
Definition Worker.cxx:242
@ EC_BADINPUT
Definition Worker.h:260
void addOutputList(const std::string &name, TObject *output_swallow) override
effects: add a given object to the output.
Definition Worker.cxx:103
::StatusCode addTree(const TTree &tree, const std::string &stream) final override
effects: adds a tree to an output file specified by the stream/label failures: Incorrect stream/label...
Definition Worker.cxx:156
TFile * inputFile() const override
description: the file we are reading the current tree from guarantee: no-fail
Definition Worker.cxx:226
TTree * getOutputTree(const std::string &name, const std::string &stream) const final override
effects: get the tree that was added to an output file earlier failures: Tree doesn't exist
Definition Worker.cxx:178
static bool fileOpenErrorFilter(int level, bool, const char *, const char *)
Error handler for file opening.
Definition Worker.cxx:643
void setOutputHist(const std::string &val_outputTarget)
set the histogram output list
Definition Worker.cxx:351
std::vector< asg::AsgComponentConfig > m_moduleConfig
the module configurations we use
Definition Worker.h:457
::StatusCode addOutputStream(const std::string &label, Detail::OutputStreamData output)
effects: add another output file guarantee: strong failures: low level errors II failures: label alre...
Definition Worker.cxx:766
const SH::MetaObject * metaData() const override
description: the sample meta-data we are working on guarantee: no-fail invariant: metaData !...
Definition Worker.cxx:199
std::string m_segmentName
the name of the segment we are processing
Definition Worker.h:442
::StatusCode finalize()
finalize the worker
Definition Worker.cxx:512
bool m_firstInputFile
whether this is the first input file
Definition Worker.h:426
void setJobConfig(JobConfig &&jobConfig)
set the JobConfig
Definition Worker.cxx:371
::StatusCode openInputFile(const std::string &inputFileUrl) override
open the given input file without processing it
Definition Worker.cxx:668
uint64_t eventsProcessed() const noexcept
the number of events that have been processed
Definition Worker.cxx:808
bool m_newInputFile
whether this is a new input file (i.e.
Definition Worker.h:432
TTree * tree() const override
description: the tree we are running on guarantee: no-fail
Definition Worker.cxx:208
void setMetaData(const SH::MetaObject *val_metaData)
set the metaData
Definition Worker.cxx:340
bool m_algorithmsInitialized
whether the algorithms are initialized
Definition Worker.h:447
std::vector< std::unique_ptr< Detail::Module > > m_modules
the list of modules we hold
Definition Worker.h:421
void addOutput(TObject *output_swallow) final override
effects: add an object to the output.
Definition Worker.cxx:89
::StatusCode initialize()
initialize the worker
Definition Worker.cxx:383
TFile * getOutputFileNull(const std::string &label) const override
effects: get the output file that goes into the dataset with the given label.
Definition Worker.cxx:144
void setSegmentName(const std::string &val_segmentName)
set the segment name
Definition Worker.cxx:361
Long64_t inputFileNumEntries() const override
the number of events in the input file
Definition Worker.cxx:791
::StatusCode processInputs()
process all the inputs
Definition Worker.cxx:497
bool m_firstEvent
whether we are still to process the first event
Definition Worker.h:452
std::string m_outputTarget
the target file to which we will write the histogram output
Definition Worker.h:437
Run a MT piece of code with an alternate root error handler.
A class that manages meta-data to be associated with an object.
Definition MetaObject.h:48
void setBool(const std::string &name, bool value)
set the meta-data boolean with the given name
a base class that manages a set of files belonging to a particular data set and the associated meta-d...
Definition Sample.h:49
Base class for the event (xAOD::TEvent and xAOD::REvent) classes.
Definition Event.h:61
A relatively simple transient store for objects created in analysis.
Definition TStore.h:45
const int nEvents
std::vector< std::string > split(const std::string &s, const std::string &t=":")
Definition hcg.cxx:179
std::string label(const std::string &format, int i)
Definition label.h:19
void report_exception(std::exception_ptr eptr)
print out the currently evaluated exception
This module defines the arguments passed from the BATCH driver to the BATCH worker.
::StatusCode StatusCode
StatusCode definition for legacy code.
bool SetDirectory(TObject *object, TDirectory *directory)
effects: set the directory this object is associated with returns: whether the object type actively k...
Definition RootUtils.cxx:25
std::unique_ptr< TFile > openFile(const std::string &name, const MetaObject &options)
open a file with the given options
-diff
void initialize()
UInt_t job_id
description: the job id of this segment
std::string segmentName
the name/id to use for this segment (not including the sample name)
std::string fullName
the name/id to use for this segment (including the sample name)
UInt_t sample
description: the index of the sample we are using
std::string sampleName
the name of the sample for this segment
std::string m_inputFileUrl
the input file url of the currently opened file
Definition ModuleData.h:70
const SH::MetaObject * m_metaData
the meta-data we use
Definition ModuleData.h:89
Worker * m_worker
the worker (to pass on to the algorithms)
Definition ModuleData.h:110
TTree * m_inputTree
the (main) tree in the input file
Definition ModuleData.h:76
uint64_t m_inputEntry
the entry in the input tree we are currently looking at
Definition ModuleData.h:80
BatchJob * m_batchJob
the BatchJob configuration (if used)
Definition ModuleData.h:116
xAOD::TStore * m_tstore
the TStore structure, if we use one
Definition ModuleData.h:104
bool m_skipEvent
whether we are skipping the current event
Definition ModuleData.h:86
OutputStreamData * m_histOutput
the histogram output stream
Definition ModuleData.h:95
std::unique_ptr< TTree > m_jobStats
Tree saving per-job statistics information.
Definition ModuleData.h:98
bool m_hasInputEvents
flag whether the most recently opened input file has events or not
Definition ModuleData.h:83
std::unique_ptr< TFile > m_inputFile
the input file pointer of the currently opened filed
Definition ModuleData.h:73
std::map< std::string, std::shared_ptr< Detail::OutputStreamData > > m_outputs
the list of output files
Definition ModuleData.h:113
std::vector< Detail::AlgorithmData > m_algs
the list of algorithms
Definition ModuleData.h:67
uint64_t m_eventsProcessed
the number of events that have been processed
Definition ModuleData.h:92
xAOD::Event * m_event
the Event object, if we use one
Definition ModuleData.h:101
a range of events in a given file
Definition EventRange.h:22
std::string m_url
the location of the file
Definition EventRange.h:24
static constexpr Long64_t eof
the special value to indicate that the range includes all events until the end of the file
Definition EventRange.h:34
Long64_t m_beginEvent
the first event to process
Definition EventRange.h:27
Long64_t m_endEvent
the event past the last event, or eof
Definition EventRange.h:30
static const std::string treeName_default
the default value of treeName
Definition MetaFields.h:47
static const std::string treeName
the name of the tree in the sample
Definition MetaFields.h:44
MsgStream & msg
Definition testRead.cxx:32
TFile * file