ATLAS Offline Software
Loading...
Searching...
No Matches
AppMgr.py
Go to the documentation of this file.
1# Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
2
3# File: AthenaCommon/share/AppMgr.py
4# Author: Wim Lavrijsen (WLavrijsen@lbl.gov)
5
6"""Application manager and other global Gaudi components."""
7
8import os
9import sys
10from AthenaCommon import ExitCodes
11
12from AthenaCommon import AlgSequence, Configurable, Logging
13import GaudiCoreSvc.GaudiCoreSvcConf as GaudiCoreSvcConf
14import GaudiCommonSvc.GaudiCommonSvcConf as GaudiCommonSvcConf
15from PyUtils.Helpers import release_metadata
16
17
18__version__ = '3.2.0'
19__author__ = 'Wim Lavrijsen (WLavrijsen@lbl.gov)'
20
21__all__ = [ 'theApp', 'ServiceMgr', 'ToolSvc', 'theAuditorSvc',
22 'athMasterSeq',
23 'athCondSeq',
24 'athAlgSeq',
25 'athOutSeq',
26 ]
27
28
29def iadd( self, tool ):
30
31 if not type(tool) in (list,tuple):
32 tool = (tool,)
33
34 # only add once (allow silently)
35 if not self._useGlobalInstances:
36 # But if duplicates may not be the same Configurable instances,
37 # need to force the owner to prevent errors about public tools
38 # not in ToolSvc when old configuration fragments are imported
39 # in new configurations.
40 dups = [t for t in tool if t in self.getChildren()]
41 for t in dups:
42 t.setParent (self.name())
43 tool = [t for t in tool if t not in self.getChildren()]
44 if len(tool)==0: return self
45
46 # this is only allowed for new-style AlgTool
47 for t in tool:
48 if not isinstance( t, Configurable.ConfigurableAlgTool ):
49 raise TypeError( '"%s" is not an AlgTool' %
50 (hasattr(t,'name') and t.name() or "This configurable" ) )
51
52 super( GaudiCoreSvcConf.ToolSvc, self ).__iadd__( tool )
53
54 return self
55
56GaudiCoreSvcConf.ToolSvc.__iadd__ = iadd
57del iadd
58
59# When adding tools to ToolSvc they are stil considered "private" and thus would
60# be copied. Overwrite the copyChild method to avoid this.
61GaudiCoreSvcConf.ToolSvc.copyChild = lambda self, child : child
62
63
65 def getHandle( self ):
66 return None
67
68 def getGaudiType ( self ):
69 return 'ServiceManager'
70
71 def getType( self ):
72 return ''
73
74 def getDlls ( self ):
75 return None
76
77 def setup( self ):
78 children = self.getChildren()
79 for svc in children:
80 svc.setup()
81
82 def __iadd__( self, service ):
83 # only add once (allow silently)
84 if service in self.getChildren():
85 return self
86
87 # this is only allowed for new-style Services
88 if not isinstance( service, Configurable.ConfigurableService ):
89 msg = 'attempt to add an %s (%s) to the ServiceManager' %\
90 (type(service).__name__, service.name())
91 Logging.log.error( msg )
92 raise TypeError( msg )
93
94 super( AthServiceManager, self ).__iadd__( service )
95
96 # make all names explicitly known
97 theApp.ExtSvc += [ service.getFullName() ]
98
99 return self
100
101
102from GaudiCoreSvc.GaudiCoreSvcConf import ApplicationMgr as AppMgr
103class AthAppMgr( AppMgr ):
104 class State:
105 """Python equivalent of IService::State enum (kind of silly to load a whole
106 dictionary library for just this quartet of integers
107 """
108
109 # for reference, the numbers below can also be obtained through a dictionary:
110 # import cppyy
111 # cppyy.gbl.Gaudi.StateMachine.OFFLINE, ...
112
113 OFFLINE = 0
114 CONFIGURED = 1
115 INITIALIZED = 2
116 RUNNING = 3
117
118 def __init__( self, name = "ApplicationMgr", **kw ):
119 kw['name'] = name
120 if 'outputLevel' not in kw: kw['outputLevel'] = 3
121 if 'jobOptions' not in kw : kw['jobOptions'] = None
122
123 # some Atlas defaults
124 if 'JobOptionsPath' not in kw: kw['JobOptionsPath'] = ""
125 if 'JobOptionsType' not in kw: kw['JobOptionsType'] = "NONE"
126 if 'EventLoop' not in kw: kw['EventLoop']="AthenaEventLoopMgr"
127 if 'StatusCodeCheck' not in kw: kw['StatusCodeCheck'] = False
128
129 # always the case in ATLAS (need early or ExtSvc should be a no-op, too)
130 kw['ExtSvcCreates'] = False
131
132 super(AthAppMgr,self).__init__( **kw )
133 self.__dict__[ '_cppApp' ] = None # proxy to C++/App.
134 self.__dict__[ '_sequences' ] = []
135 self.__dict__[ '_streams' ] = AlgSequence.AlgSequence( "Streams" )
136 self.__dict__[ 'CreateSvc' ] = [] # block the property
137 # TopAlg and OutStream are not user-settable directly (see __setattr__)
138 self.__dict__[ 'TopAlg' ] = [ AlgSequence.AthSequencer( "AthMasterSeq" ).getFullName() ]
139 self.__dict__[ 'OutStream' ] = []
140 self.__dict__[ '_exitstate' ] = ExitCodes.ALL_OK
141
142 self.__dict__['state'] = lambda : AthAppMgr.State.OFFLINE
143 self.__dict__['Dlls'] = []
144
145 # install services
146 svcMgr = self.serviceMgr() # noqa: F841
147
148 # external option (TODO: receive this cleanly; AthOptionsParser doesn't manage results, and
149 # can't be called directly due to transforms etc.)
150 self.__dict__[ '_opts' ] = None
151
152 # figure out which release are we running, for logging purposes
153 d = release_metadata()
154 msg = Logging.log.info
155 msg( 'using release [%(project name)s-%(release)s] [%(platform)s] [%(nightly name)s/%(nightly release)s] -- built on [%(date)s]' % d )
156
157 return
158
159 def __setattr__( self, name, value ):
160 # required b/c the lookup is otherwise intercepted by iProperty
161 if name[0] == '_': # private properties
162 return object.__setattr__( self, name, value )
163 # in case the C++ app has already been instantiated...
164 if hasattr(self, '_cppApp') and self._cppApp and \
165 name in AthAppMgr.__slots__:
166 handle = self.getHandle()
167 return handle.__setattr__(name, value)
168 elif name == "TopAlg" and value:
169 raise RuntimeError("Setting theApp.TopAlg is not supported. "
170 "Add the algorithm to the default AlgSequence() instead.")
171 elif name == "Dlls": # block Dlls calls
172 return
173 elif name == "OutStream" and value:
174 raise RuntimeError("Setting theApp.OutStream is not supported. "
175 "Use theApp.addOutputStream instead.")
176 elif name == "CreateSvc": # for delaying creation of services
177 self.__dict__[ name ] = value
178 else:
179 return super( AppMgr, self ).__setattr__( name, value )
180
181 def __getattribute__( self, name ):
182 if name[0] == '_':
183 return object.__getattribute__( self, name )
184 if hasattr(self, '_cppApp') and self._cppApp and \
185 name in AthAppMgr.__slots__:
186 return getattr(self._cppApp, name)
187 else:
188 if name == "Dlls": return [] # block Dlls calls
189 return super( AthAppMgr, self ).__getattribute__(name)
190
192 """helper method to build the top-level AthSequencer from all bits and
193 pieces : AthMasterSeq, AthAlgSeq, AthOutSeq
194 """
195 from . import AlgSequence as _as
196 from AthenaServices.AthenaServicesConf import AthIncFirerAlg as IFA
197 from GaudiCoreSvc.GaudiCoreSvcConf import IncidentProcAlg as IPA
198
199 def _build():
200 Logging.log.debug ("building master sequence...")
201 athMasterSeq = _as.AthSequencer ("AthMasterSeq",Sequential = True)
202 athBeginSeq = _as.AthSequencer ("AthBeginSeq",Sequential=True)
203 athCondSeq = _as.AthSequencer ("AthCondSeq", StopOverride=True)
204 athAlgSeq = _as.AthSequencer ("AthAlgSeq",IgnoreFilterPassed=True, StopOverride=True, ProcessDynamicDataDependencies=True, ExtraDataForDynamicConsumers=[])
205 athEndSeq = _as.AthSequencer ("AthEndSeq",Sequential=True)
206 athOutSeq = _as.AthSequencer ("AthOutSeq", StopOverride=True)
207 athAllAlgSeq = _as.AthSequencer ("AthAllAlgSeq", StopOverride=True)
208 athAlgEvtSeq = _as.AthSequencer ("AthAlgEvtSeq",Sequential = True, StopOverride=True)
209
210 #Setup begin and end sequences
211 # Begin Sequence
212 # IFA->BeginEvent
213 # IPA
214 ifaBeg=IFA("BeginIncFiringAlg")
215 ifaBeg.Incidents=["BeginEvent"]
216 ifaBeg.FireSerial=False # we want serial incident to be fired as well
217 athBeginSeq += ifaBeg
218 ipa=IPA("IncidentProcAlg1")
219 athBeginSeq += ipa
220
221 # EndSequence
222 # IFA->EndEvent
223 # IPA
224 ifaEnd=IFA("EndIncFiringAlg")
225 ifaEnd.Incidents=["EndEvent"]
226 ifaEnd.FireSerial=False # we want serial incident to be fired as well
227 athEndSeq += ifaEnd
228 ipa2=IPA("IncidentProcAlg2")
229 athEndSeq += ipa2
230
231 # XXX: should we discard empty sequences ?
232 # might save some CPU and memory...
233
234 # ensure that the CondInputLoader gets initialized after all
235 # other user Algorithms for MT so that base classes of data deps
236 # can be correctly determined. In MT, the order of execution
237 # is irrelevant (determined by data deps). But for serial, we
238 # need the CondAlgs to execute first, so the ordering changes.
239 from AthenaCommon.ConcurrencyFlags import jobproperties as jp
240 if ( jp.ConcurrencyFlags.NumThreads() > 0 ) :
241 athAllAlgSeq += athAlgSeq
242 athAllAlgSeq += athCondSeq
243 else:
244 athAllAlgSeq += athCondSeq
245 athAllAlgSeq += athAlgSeq
246
247 athAlgEvtSeq += athBeginSeq
248 athAlgEvtSeq += athAllAlgSeq
249 athAlgEvtSeq += athEndSeq
250
251 athMasterSeq += athAlgEvtSeq
252 athMasterSeq += athOutSeq
253
254 # Should be after all other algorithms.
255 athMasterSeq += IFA('EndAlgorithmsFiringAlg',
256 Incidents = ['EndAlgorithms'],
257 FireSerial = False)
258 athMasterSeq += IPA('IncidentProcAlg3')
259
260 if Logging.log.isEnabledFor(Logging.logging.DEBUG):
261 from AthenaCommon.AlgSequence import dumpSequence
262 dumpSequence(athMasterSeq)
263
264 Logging.log.debug ("building master sequence... [done]")
265 return athMasterSeq
266 # prevent hysteresis effect
267 if not hasattr (self, '__master_seq_built'):
269 return _build()
270 return _as.AthSequencer ("AthMasterSeq")
271
272 def algorithm( self, name ):
273 if self._cppApp:
274 return self.getHandle().algorithm( name )
275 # might be lucky...
276 return super( AppMgr, self ).algorithm( name )
277
278 def service( self, name ):
279 if self._cppApp: return self._cppApp.service(name)
280 svcMgr = self.serviceMgr()
281 if not hasattr( svcMgr, name ):
282 from AthenaCommon import CfgMgr
283 svcMgr += getattr( CfgMgr, name )()
284 return getattr( svcMgr, name )
285
286 def setOutputLevel( self, outputLevel ):
287 if outputLevel != -1 :
288 if self.state() == AthAppMgr.State.OFFLINE : # not yet configured
289 self.OutputLevel = outputLevel
290 svcMgr = self.serviceMgr()
291 if not hasattr( svcMgr, 'MessageSvc' ):
292 svcMgr += GaudiCoreSvcConf.MessageSvc()
293 svcMgr.MessageSvc.OutputLevel = outputLevel
294
295 # explicit user calls
296 def addSequence( self, seq ):
297 if seq not in self._sequences:
298 self._sequences.append( seq )
299
300 def removeSequence( self, seq ):
301 self._sequences.remove( seq )
302
303 def addOutputStream( self, stream ):
304 if stream not in self._streams.getChildren():
305 self._streams += stream
306
307 def getOutputStream( self, stream ):
308 athOutSeq = AlgSequence.AthSequencer( "AthOutSeq" )
309 for o in athOutSeq.getChildren():
310 if o.name() == stream:
311 return o
312 for o in self._streams.getChildren():
313 if o.name() == stream:
314 return o
315 return None
316
317 def removeOutputStream( self, stream ):
318 self._streams.remove( stream )
319
320 # override toolSvc to handle the transitional one
321 def toolSvc( self, name='ToolSvc' ):
322 if '_toolsvc' not in self.__dict__:
323 self.__dict__[ '_toolsvc' ] = GaudiCoreSvcConf.ToolSvc( name )
324 return self._toolsvc
325 toolsvc = toolSvc
326
327 # same for serviceMgr
328 def serviceMgr( self ):
329 if '_servicemgr' not in self.__dict__:
330 self.__dict__[ '_servicemgr' ] = AthServiceManager( 'ServiceManager' )
331 return self._servicemgr
332 servicemgr = serviceMgr
333
334 def bootProps(self):
335 props = {}
336 for k in self.getProperties().keys():
337 if k not in [ "Go", "Exit", "AuditInitialize", "AuditFinalize" ]:
338 props[k] = self.getDefaultProperty(k)
339 if hasattr(self, k):
340 props[k] = getattr(self, k)
341 props['Dlls'] = []
342 props['CreateSvc'] = []
343 return props
344
345 def getHandle( self, selfOptions = {} ):
346 if not self._cppApp:
347 # temporarily store this list as it will be touched by the C++ app
348 # through the __getattribute__ method
349 _createSvc = self.__dict__['CreateSvc']
350 if not selfOptions:
351 selfOptions = self.bootProps()
352 for k,v in selfOptions.items(): setattr(self, k, v)
353 svcMgr = self.serviceMgr()
354 # prevent the loading of ConfigurableDb when no configuration is done
355 if self._opts and not self._opts.fromdb:
356 from AthenaCommon.ConfigurableDb import getConfigurable
357 if not hasattr(svcMgr, 'JobOptionsSvc'):
358 svcMgr += getConfigurable(self.JobOptionsSvcType)("JobOptionsSvc")
359 if not hasattr(svcMgr, 'MessageSvc'):
360 svcMgr += getConfigurable(self.MessageSvcType)("MessageSvc")
361
362 from GaudiPython import AppMgr as GaudiAppMgr
363 self._cppApp = GaudiAppMgr( outputlevel = self.outputLevel,
364 joboptions = None,
365 selfoptions = selfOptions )
366 self.__dict__['state'] = self._cppApp.state
367 for k,v in selfOptions.items():
368 setattr(self._cppApp,k,v)
369 self.__dict__['CreateSvc'] = _createSvc
370 del _createSvc
371
372 import GaudiPython # this module might have disappeared b/c of cleansing # noqa: F401
373 return self._cppApp
374
375 @property
376 def _evtSeek(self):
377 """ retrieve a handle to the IEventSeek interface of the event loop mgr
378 """
379 import AthenaPython.PyAthena as PyAthena
380 return PyAthena.py_svc(self.EventLoop, iface='IEventSeek')
381
382 @property
383 def _evtSize(self):
384 """ retrieve a handle to the ICollectionSize interface of the event loop mgr
385 """
386 import AthenaPython.PyAthena as PyAthena
387 return PyAthena.py_svc(self.EventLoop, iface='ICollectionSize')
388
389 # Configurable call
390 def setup( self, recursive = False ):
391 if not recursive and (self._opts and (self._opts.drop_reload or self._opts.config_only)):
392 # store configuration on disk
393 if self._opts.config_only is True: # config-only but not storing to file
394 fn = None
395 elif self._opts.config_only:
396 fn = self._opts.config_only
397 else:
398 fn = 'TempAthenaConfig.' + str(os.getpid()) + '.pkl'
399
400 if fn is not None:
401 Logging.log.info( "storing configuration in %s", fn )
402 from AthenaCommon import ConfigurationShelve
403 ConfigurationShelve.storeJobOptionsCatalogue( fn )
404 del ConfigurationShelve
405
406 if self._opts.drop_reload:
407 # build the new set of options; replace the .py by the .pkl,
408 # and remove '-c arg'
409 del sys.argv[ sys.argv.index( '--drop-and-reload' ) ]
410 for arg in sys.argv[1:]:
411 if arg[-3:] == '.py':
412 del sys.argv[ sys.argv.index( arg ) ]
413
414 elif arg == '-c':
415 idx = sys.argv.index( arg )
416 del sys.argv[ idx : idx + 2 ]
417
418 # dump profiling
419 if self._opts.profile_python:
420 i = sys.argv.index( '--profile-python' )
421 del sys.argv[i:i+2] # delete argument and its value
422 from AthenaCommon.Debugging import dumpPythonProfile
423 dumpPythonProfile(self._opts.profile_python)
424
425 # fire ourselves up anew
426 Logging.log.info( 'restarting athena.py from %s ... ', fn )
427 sys.argv.insert( 1, fn )
428 os.execvp( sys.argv[0], sys.argv )
429
430 else:
431 # running config-only, so we're done
432 if self._opts.profile_python:
433 from AthenaCommon.Debugging import dumpPythonProfile
434 dumpPythonProfile(self._opts.profile_python)
435 Logging.log.info( "configuration complete, now exiting ... " )
436 os._exit( self._exitstate )
437
438 # normal setup() (non drop-and-reload) continues here:
439
440 # first we bring the real C++ application to life...
441 handle = self.getHandle()
442
443 # temporarily disable GaudiAppMgr.Dlls and .CreateSvc calls
444 handle.__dict__['CreateSvc'] = self.__dict__.get('CreateSvc',
445 handle.CreateSvc)
446
447 from GaudiPython import AppMgr as GaudiAppMgr
448
449 # Likely the first (or at least the first important) place if we're
450 # running in compatibility mode where gaudimodule will be loaded. And
451 # even if not, still ok. Remove the GaudiPython exit handlers as to
452 # prevent them from clobbering Athena ones.
453 # Don't remove exit handlers for GaudiConfig2, or we can get spurious
454 # errors on exit.
455 import atexit
456 handler = None
457 if hasattr(atexit, '_exithandlers'):
458 for handler in atexit._exithandlers[:]:
459 if hasattr(handler[0], '__module__') and handler[0].__module__:
460 if 'audiPython' in handler[0].__module__: # removes GaudiPython handlers
461 #print ("removed ", handler[0].__module__)
462 atexit._exithandlers.remove( handler )
463 del handler, atexit
464
465 def _setattr( self, n, v ):
466 if n == 'CreateSvc':
467 self.__dict__[n] = v
468 return
469 if n == 'Dlls':
470 return
471 return super( GaudiAppMgr, self ).__setattr__( n, v )
472 GaudiAppMgr_old_setattr = GaudiAppMgr.__setattr__
473 GaudiAppMgr.__setattr__ = _setattr
474 del _setattr
475
476 def _getattr( self, n ):
477 if n == 'CreateSvc':
478 return self.__dict__[n]
479 return super( GaudiAppMgr, self ).__getattr__( n )
480 GaudiAppMgr_old_getattr = GaudiAppMgr.__getattr__
481 GaudiAppMgr.__getattr__ = _getattr
482 del _getattr
483
484 # public tools (they're less likely to be instantiated early, and
485 # thus rely on job options load order)
486 self.toolSvc().setup()
487
488 # new-style services (also sets up AuditorSvc)
489 self.serviceMgr().setup()
490
491 # setup top-level job seq
492 master_seq = self.__build_master_sequence()
493 master_seq.setup()
494
495 # tell self about the algs
496 handle.TopAlg = [ master_seq.getFullName() ]
497
498 # setup output streams, and tell self about them
499 streams = self.__dict__[ '_streams' ]
500 streams.setup()
501 handle.OutStream = list(map( lambda x: x.getFullName(), streams.getChildren() ))
502
503 # synchronize 'Dlls'
504 # note: we synchronize in the opposite direction wrt CreateSvc
505 super(AppMgr,self).__setattr__('Dlls', handle.Dlls)
506
507 # synchronize 'CreateSvc'
508 svcMgr = self.serviceMgr()
509 _createSvc = handle.__dict__['CreateSvc']
510 if len(_createSvc) > 0 and \
511 _createSvc[0] != svcMgr.ToolSvc.getFullName():
512 _createSvc = [ svcMgr.ToolSvc.getFullName() ] + _createSvc
513
514 if 'CreateSvc' in self.__dict__:
515 del self.__dict__['CreateSvc']
516 handle.__dict__['CreateSvc'] = [ s for s in _createSvc ]
517
518 # reinstall old __?etattr__
519 del handle.__dict__['CreateSvc']
520 GaudiAppMgr.__getattr__ = GaudiAppMgr_old_getattr
521 GaudiAppMgr.__setattr__ = GaudiAppMgr_old_setattr
522
523 # only now allow CreateSvc, so that there are no ordering problems
524 Logging.log.debug( 'Updating (C++) "CreateSvc" property...' )
525 handle.CreateSvc = _createSvc
526 Logging.log.debug( 'Updating (C++) "CreateSvc" property... [ok]' )
527
528 # if requested, dump the current state of the configuration to an ASCII file
529 if self._opts and self._opts.config_dump_file:
530 import AthenaCommon.ConfigurationShelve as cs
531 cs.saveToAscii(self._opts.config_dump_file)
532
533 return
534
535 # redefines to take into acount setup of Configurables
536 def initialize( self ):
537 # Touch these types early, before dictionaries are loaded,
538 # to prevent spurious error messages from ROOT.
539 # See ATLASRECTS-3486.
540 from os import environ
541 environ['CLING_STANDARD_PCH'] = 'none' #See bug ROOT-10789
542 import cppyy
543 getattr(cppyy.gbl, 'vector<bool>')
544 getattr(cppyy.gbl, 'vector<float>')
545 getattr(cppyy.gbl, 'vector<unsigned short>')
546 getattr(cppyy.gbl, 'vector<short>')
547 getattr(cppyy.gbl, 'vector<unsigned long>')
548 getattr(cppyy.gbl, 'vector<ULong64_t>')
549 getattr(cppyy.gbl, 'map<string,string>')
550
551 # build configuration
552 self.setup()
553
554 # create C++-side AppMgr
555 from AthenaCommon.ConcurrencyFlags import jobproperties as jp
556 try:
557 # Set threaded flag to release the python GIL when we're in C++
558 is_threaded = jp.ConcurrencyFlags.NumThreads() > 0
559 self.getHandle()._appmgr.initialize.__release_gil__ = is_threaded
560 sc = self.getHandle().initialize()
561 if sc.isFailure():
562 self._exitstate = ExitCodes.INI_ALG_FAILURE
563 except Exception:
564 self._exitstate = ExitCodes.INI_ALG_EXCEPTION
565 raise
566 return sc
567
568 def reinitialize( self ):
569 # since we're going to run python again, may have to re-enable to profiler
570 if self._opts and self._opts.profile_python:
571 import cProfile
572 cProfile._athena_python_profiler.enable()
573
574 # first, rebuild configuration
575 self.setup()
576
577 # ApplicationMgr::reinitialize does not reinit algorithms ...
578 for name in self.getHandle().TopAlg:
579 try:
580 parts = name.split('/')
581 algname = len(parts) == 2 and parts[1] or parts[0]
582 sc = self.algorithm( algname )._ialg.reinitialize()
583 if sc.isFailure() and not self._exitstate:
584 return sc
585 except AttributeError:
586 pass
587
588 # normal reinitialize kicks services, tools left out ...
589 return self.getHandle().reinitialize()
590
591 # redefine run to improve interface
592 def run( self, nEvt = None ):
593 # initialize as appropriate
594 if self.state() in ( AthAppMgr.State.OFFLINE,
595 AthAppMgr.State.CONFIGURED, ):
596 Logging.log.debug( 'Initializing application manager' )
597 sc = self.initialize()
598 else:
599 Logging.log.debug( 'Re-initializing application manager' )
600 sc = self.reinitialize()
601
602 if sc.isFailure():
603 return sc
604
605 sc = self.start()
606 if sc.isFailure():
607 return sc
608
609 # determine number of events
610 if nEvt is None:
611 nEvt = self.EvtMax # late, as sequences may have changed it
612
613 from AthenaCommon.Debugging import DbgStage
614 if DbgStage.value == "exec":
615 from .Debugging import hookDebugger
616 hookDebugger()
617
618 # actual run (FIXME: capture beginRun() exceptions and failures, which is
619 # not currently supported by IEventProcessor interface)
620 from AthenaCommon.ConcurrencyFlags import jobproperties as jp
621 try:
622 # Set threaded flag to release the GIL on execution
623 executeRunMethod = self.getHandle()._evtpro.executeRun
624 executeRunMethod.__release_gil__ = jp.ConcurrencyFlags.NumThreads() > 0
625 sc = executeRunMethod(nEvt)
626 if sc.isFailure() and not self._exitstate:
627 self._exitstate = ExitCodes.EXE_ALG_FAILURE # likely, no guarantee
628 except Exception:
629 self._exitstate = ExitCodes.EXE_ALG_EXCEPTION # idem
630 raise
631
632 sc = self.stop()
633 return sc
634
635 def start( self ):
636 import GaudiPython
637 sc = GaudiPython.SUCCESS
638 if self.State.INITIALIZED == self.getHandle().FSMState():
639 Logging.log.debug( 'Starting application manager' )
640 sc = self.getHandle().start()
641 return sc
642
643 def stop( self ):
644 import GaudiPython
645 sc = GaudiPython.SUCCESS
646 if self.State.RUNNING == self.getHandle().FSMState():
647 Logging.log.debug( 'Stopping application manager' )
648 sc = self.getHandle().stop()
649 return sc
650
651 # forward call to underlying C++/app
652 def finalize( self ):
653 #stop theApp if not already done
654 sc = theApp.stop()
655 if sc.isFailure() and not self._exitstate:
656 self._exitstate = ExitCodes.FIN_ALG_FAILURE
657 try:
658 if not self._cppApp:
659 raise RuntimeError("C++ application not instantiated : Nothing to finalize !")
660 # Set threaded flag to release the GIL when finalizing in the c++
661 from AthenaCommon.ConcurrencyFlags import jobproperties as jp
662 finalizeMethod = self.getHandle()._appmgr.finalize
663 finalizeMethod.__release_gil__ = jp.ConcurrencyFlags.NumThreads() > 0
664 sc = finalizeMethod()
665 if sc.isFailure():
666 self._exitstate = ExitCodes.FIN_ALG_FAILURE
667 except Exception:
668 self._exitstate = ExitCodes.FIN_ALG_EXCEPTION
669 raise
670 return sc
671
672 # convenience functions to move around events
673 def curEvent( self ):
674 try:
675 return self._evtSeek.curEvent()
676 except AttributeError:
677 raise TypeError( '%s does not support IEventSeek' % theApp.EventLoop )
678
679 def seekEvent( self, n ):
680 try:
681 sc = self._evtSeek.seek( n )
682 # prevents any unchecked statuscode leftover
683 if not sc.isSuccess():
684 return sc
685 sc = self.nextEvent()
686 # prevents any unchecked statuscode leftover
687 if not sc.isSuccess():
688 return sc
689 return sc
690 except AttributeError:
691 raise TypeError( '%s does not support IEventSeek' % theApp.EventLoop )
692
693 def seek( self, n ):
694 try:
695 sc = self._evtSeek.seek( n )
696 # prevents any unchecked statuscode leftover
697 if not sc.isSuccess():
698 return sc
699 return sc
700 except AttributeError:
701 raise TypeError( '%s does not support IEventSeek' % theApp.EventLoop )
702
703 def nextEvent( self, nEvt = None ):
704 #start theApp if not already done
705 sc = theApp.start()
706 if sc.isFailure() and not self._exitstate:
707 self._exitstate = ExitCodes.INI_ALG_FAILURE
708
709 if nEvt is None:
710 nEvt = self.curEvent() + 1
711
712 try:
713 sc = self.getHandle()._evtpro.nextEvent( nEvt )
714 if sc.isFailure() and not self._exitstate:
715 self._exitstate = ExitCodes.EXE_ALG_FAILURE
716 except Exception:
717 self._exitstate = ExitCodes.EXE_ALG_EXCEPTION
718 raise
719
720 return sc
721
722 def size( self ):
723 try:
724 return self._evtSize.size()
725 except AttributeError:
726 raise TypeError( '%s does not support ICollectionSize' % theApp.EventLoop )
727
728 def replacePFC(self):
729 """ if we have MP version of EventLoopMgr
730 replace PoolFileCatalog.xml by MP version"""
731 if (self.EventLoop == 'AthMpEventLoopMgr/EventLoopMgr'):
732 if os.path.exists("MP_PoolFileCatalog.xml"):
733 Logging.log.info ("replacing PoolFileCataloG.xml by MP version")
734 import shutil
735 shutil.copy2("MP_PoolFileCatalog.xml", "PoolFileCatalog.xml")
736
737 def exit( self, code = None ):
738 """Terminate AppMgr and exit python"""
739 try:
740 if self.state() > AthAppMgr.State.CONFIGURED:
741 sc1 = self.finalize()
742 self.replacePFC() #only for AthenaMP -> replace pfc by mp version
743 sc2 = self.getHandle()._appmgr.terminate()
744 if ( sc1.isFailure() or sc2.isFailure() ) and not self._exitstate:
745 self._exitstate = ExitCodes.FIN_ALG_FAILURE
746 except Exception:
747 if not self._exitstate:
748 self._exitstate = ExitCodes.FIN_ALG_EXCEPTION
749 import traceback
750 traceback.print_exc() # no re-raise to allow sys.exit next
751
752 if self._opts.profile_python:
753 from AthenaCommon.Debugging import dumpPythonProfile
754 dumpPythonProfile(self._opts.profile_python)
755
756 if code is None:
757 code = self._exitstate
758
759 # In interactive mode, where this functions is called within an atexit handler,
760 # we cannot call sys.exit as this raises SystemExit, which is not allowed in
761 # exit handlers. Unfortunately, this also means we cannot set an exit code.
762 # See also: https://bugs.python.org/issue27035
763 # https://github.com/python/cpython/issues/103512
764 if not os.environ.get('PYTHONINSPECT', ''):
765 Logging.log.info( 'leaving with code %d: "%s"', code, ExitCodes.what( code ) )
766 sys.exit( code )
767
768
769
770theApp = AthAppMgr(
771 outputLevel = Logging.AthenaLogger.mapLevelLoggingToGaudi( Logging.log.getEffectiveLevel() )
772 )
773
774ServiceMgr = theApp.serviceMgr()
775ServiceMgr += theApp.toolSvc()
776ToolSvc = ServiceMgr.ToolSvc
777
778# convenience customization to deal with "Auditors" property
779def iadd( self, config ):
780 super( GaudiCommonSvcConf.AuditorSvc, self ).__iadd__( config )
781
782 if isinstance( config, Configurable.ConfigurableAuditor ):
783 if not config.getName() in self.Auditors and \
784 not config.getFullName() in self.Auditors:
785 self.Auditors += [ config.getFullName() ]
786
787 return self
788
789GaudiCommonSvcConf.AuditorSvc.__iadd__ =iadd
790del iadd
791
792
793def _delattr( self, attr ):
794 try:
795 c = getattr( self, attr )
796
797 try:
798 self.Auditors.remove( c.getFullName() )
799 except ValueError:
800 pass
801
802 try:
803 self.Auditors.remove( c.getName() )
804 except ValueError:
805 pass
806
807 except AttributeError:
808 pass
809
810 super( GaudiCommonSvcConf.AuditorSvc, self ).__delattr__( attr )
811
812GaudiCommonSvcConf.AuditorSvc.__delattr__ = _delattr
813del _delattr
814
815
816# AuditorSvc globals
817ServiceMgr += GaudiCommonSvcConf.AuditorSvc()
818theAuditorSvc = ServiceMgr.AuditorSvc
819
820
821
837athMasterSeq = AlgSequence.AthSequencer( "AthMasterSeq" )
838athCondSeq = AlgSequence.AthSequencer( "AthCondSeq" )
839athAlgSeq = AlgSequence.AthSequencer( "AthAlgSeq" )
840athOutSeq = AlgSequence.AthSequencer( "AthOutSeq" )
841athBeginSeq = AlgSequence.AthSequencer( "AthBeginSeq" )
842athEndSeq = AlgSequence.AthSequencer( "AthEndSeq" )
STL class.
sequence of Gaudi algorithms, to replace the generated configurable
__getattribute__(self, name)
Definition AppMgr.py:181
nextEvent(self, nEvt=None)
Definition AppMgr.py:703
return self._cppApp.service(name) _cppApp
Definition AppMgr.py:186
getHandle(self, selfOptions={})
Definition AppMgr.py:345
__init__(self, name="ApplicationMgr", **kw)
Definition AppMgr.py:118
setOutputLevel(self, outputLevel)
Definition AppMgr.py:286
__setattr__(self, name, value)
Definition AppMgr.py:159
setup(self, recursive=False)
Definition AppMgr.py:390
addSequence(self, seq)
Definition AppMgr.py:296
exit(self, code=None)
Definition AppMgr.py:737
removeOutputStream(self, stream)
Definition AppMgr.py:317
__build_master_sequence(self)
Definition AppMgr.py:191
service(self, name)
Definition AppMgr.py:278
addOutputStream(self, stream)
Definition AppMgr.py:303
toolSvc(self, name='ToolSvc')
Definition AppMgr.py:321
algorithm(self, name)
Definition AppMgr.py:272
removeSequence(self, seq)
Definition AppMgr.py:300
getOutputStream(self, stream)
Definition AppMgr.py:307
associator for services -----------------------------------------------—
Definition AppMgr.py:64
T * get(TKey *tobj)
get a TObject* from a TKey* (why can't a TObject be a TKey?)
Definition hcg.cxx:130
std::string algorithm
Definition hcg.cxx:85
_delattr(self, attr)
Definition AppMgr.py:793
iadd(self, tool)
associator for public tools -------------------------------------------—
Definition AppMgr.py:29
Definition run.py:1
void initialize()
MsgStream & msg
Definition testRead.cxx:32