ATLAS Offline Software
Loading...
Searching...
No Matches
Debugging.py
Go to the documentation of this file.
1# Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
2
3
8
9__doc__ = """py-module to hold a few tools and utilities to help debugging
10configurables and/or Athena application.
11"""
12
13import io
14
16 """Class to hold the stage at which the user asked to hook the debugger
17 """
18 value = None
19 allowed_values = ( "conf", "init", "exec", "fini" )
20 pass # class DbgStage
21
23 """debugging helper, hooks debugger to running interpreter process
24 gdb can be overridden via $ATLAS_DEBUGGER
25 """
26 import os
27 debugger = os.environ.get('ATLAS_DEBUGGER', 'gdb')
28
29 pid = os.spawnvp(os.P_NOWAIT,
30 debugger, [debugger, '-q', 'python', str(os.getpid())])
31
32 # give debugger some time to attach to the python process
33 import time
34 time.sleep( 1 )
35
36 # verify the process' existence (will raise OSError if failed)
37 os.waitpid( pid, os.WNOHANG )
38 os.kill( pid, 0 )
39 return
40
41def hookStrace(out=None):
42 """Same than for hookDebugger: spawn strace and attach to the running
43 interpreter process
44 """
45 import os
46 if out is None: out = 'athena.strace.log.%i' % os.getpid()
47 if isinstance(out, io.IOBase):
48 out = out.name
49 elif not isinstance(out,str):
50 raise TypeError('argument 0 needs to be either a file or a filename')
51
52 pid = os.spawnvp(os.P_NOWAIT,
53 'strace', ['strace',
54 '-f', # follow children
55 '-p', str(os.getpid()),
56 '-o', out])
57
58 # give strace some time to attach to the python process
59 import time
60 time.sleep( 1 )
61
62 # verify the process' existence (will raise OSError if failed)
63 os.waitpid( pid, os.WNOHANG )
64 os.kill( pid, 0 )
65 return
66
67
69 """On kernels with Yama enabled, ptrace may not work by default on processes
70which are not decendants of the tracing process. Among other things, that
71causes the way we attach the debugger to fail. However, we can disable this
72on a per-process basis. Do that here.
73
74See https://www.kernel.org/doc/Documentation/security/Yama.txt and prctl(2).
75"""
76
77 # First test to see if ptrace restrictions are enabled.
78 import os
79 # Return if this kernel does not support ptrace restrictions.
80 if not os.path.exists ('/proc/sys/kernel/yama/ptrace_scope'): return
81
82 # Return if ptrace restrictions are disabled.
83 with open('/proc/sys/kernel/yama/ptrace_scope') as f:
84 if f.readline().strip() == '0':
85 return
86
87 # Use prctl to try to enable ptrace.
88 from ctypes import CDLL
89 libc = CDLL("libc.so.6")
90 # Args are PTRACE_SET_PTRACER (4HYama) and
91 # PR_SET_PTRACER_ANY ((unsigned long)-1).
92 libc.prctl (0x59616d61, 0xffffffffffffffff)
93
94 return
95
96
97def dumpPythonProfile(filename):
98 """Save python profile data of the default athena profiler instance
99 into filename (.txt or .pkl format).
100 """
101 from AthenaCommon.Logging import log
102 import cProfile
103 import pstats
104
105 profiler = cProfile._athena_python_profiler
106 profiler.disable()
107 if filename.endswith(".txt"):
108 stats = pstats.Stats(profiler, stream=open(filename, 'w'))
109 stats.strip_dirs().sort_stats("time").print_stats()
110 log.info("Python profile summary stored in %s", filename)
111 else:
112 profiler.dump_stats(filename)
113 log.info("Python profile stored in %s", filename)
114
115
116def traceExecution(script, level):
117 """Run script with the given trace level"""
118 import sys
119 import trace
120 ignore_dirs = []
121 ignore_mods = []
122
123 # exclude system and root libraries
124 if level > 0:
125 ignore_dirs = [x for x in sys.path if x.find("ROOT")!=-1]
126 ignore_dirs.append(sys.prefix)
127 if level > 1:
128 ignore_mods += ['_db', '__init__', '_configurables', 'GaudiHandles', 'six']
129 if level > 2:
130 ignore_mods += [
131 # Legacy stuff we pull in b/c PythonAlgorithms and such still derive from old-style configurables
132 'Configurable','Configurables','PropertyProxy','DataHandle','ConfigurableDb',
133 'ConfigurableMeta', 'CfgMgr',
134 # Internals of the ComponentAccumulator
135 'ComponentAccumulator','Logging','AthConfigFlags','AllConfigFlags','Deduplication',
136 'semantics','AccumulatorCache','DebuggingContext','AtlasSemantics','ComponentFactory',
137 'LegacySupport','ItemListSemantics'
138 ]
139
140 # taken from cpython/Lib/trace.py
141 tracer = trace.Trace(ignoredirs=ignore_dirs, ignoremods=ignore_mods)
142
143 with io.open_code(script) as f:
144 code = compile(f.read(), script, 'exec')
145 tracer.run(code)
traceExecution(script, level)
Definition Debugging.py:116
dumpPythonProfile(filename)
Definition Debugging.py:97
hookStrace(out=None)
Definition Debugging.py:41