2 from __future__
import print_function
9 from shutil
import copy, rmtree
10 from collections
import defaultdict
14 import FWCore.ParameterSet.Types
16 OUTFILE_TREE =
"calltree"
17 OUTFILE_FILES =
"callfiles"
20 WRAP_SCRIPTS = [
"cmsDriver.py" ]
22 os.path.dirname(os.__file__),
23 FWCore.ParameterSet.Types.__file__,
26 os.environ[
"CMSSW_BASE"] +
"/python/", os.environ[
"CMSSW_RELEASE_BASE"] +
"/python/",
27 os.environ[
"CMSSW_BASE"] +
"/cfipython/", os.environ[
"CMSSW_RELEASE_BASE"] +
"/cfipython/"]
32 cwd = os.path.abspath(os.getcwd())
33 wf = re.match(
".*/(\d+\.\d+)_", cwd)
35 PREFIXINFO.append(
"wf")
36 PREFIXINFO.append(wf.groups()[0])
37 online = re.match(
"(.*/)?(.*)_dqm_sourceclient-live_cfg\.py", argv[0])
39 PREFIXINFO.append(
"online")
40 PREFIXINFO.append(online.groups()[1])
41 step = re.match(
"(step\d+)_.*\.py", argv[0])
43 PREFIXINFO.append(step.groups()[0])
44 processing = re.match(
"step\d+_.*(RECO|ALCA|HARVEST).*\.py", argv[0])
46 PREFIXINFO.append(processing.groups()[0])
48 PREFIXINFO.append(argv[0])
51 bindir = tempfile.mkdtemp()
52 print(
"+Setting up in ", bindir)
53 for s
in WRAP_SCRIPTS:
54 os.symlink(ARGV0, bindir +
"/" + s)
55 os.symlink(ARGV0, bindir +
"/cmsRun")
56 os.environ[
"PATH"] = bindir +
":" + os.environ[
"PATH"]
57 os.environ[
"CMSSWCALLTREE"] = bindir +
"/" + OUTFILE_TREE
58 os.environ[
"CMSSWCALLFILES"] = bindir +
"/" + OUTFILE_FILES
59 os.environ[
"CMSSWCALLBASE"] = os.path.abspath(os.getcwd()) +
"/"
60 with open(os.environ[
"CMSSWCALLTREE"],
"w")
as f:
62 with open(os.environ[
"CMSSWCALLFILES"],
"w")
as f:
69 print(
"+Cleaning up ", tmpdir)
70 copy(os.environ[
"CMSSWCALLTREE"],
".")
71 copy(os.environ[
"CMSSWCALLFILES"],
".")
77 if not "CMSSWCALLTREE" in os.environ:
86 filename = os.path.abspath(filename)
87 for pfx
in STRIPPATHS:
88 if filename.startswith(pfx):
89 filename = filename[len(pfx):]
95 file_path = os.path.join(entry, progname)
96 if os.path.isfile(file_path):
98 if not os.path.isfile(file_path):
99 print(
"+Cannot find program (%s) in modified $PATH (%s)." % (progname, path))
101 print(
"+Found %s as %s in %s." % (progname, file_path, path))
105 progname =
", ".
join(PREFIXINFO)
106 print(
"+Done running %s, writing output..." % progname)
109 filename, funcname = func
110 return "%s::%s" % (
formatfile(filename), funcname)
121 if len(parents) == 1:
122 func =
next(iter(parents))
135 path.append(
format(func) +
"+")
136 parents = callgraph[func]
139 print(seen, path, parents, func)
140 raise Exception(
'Call path too deep, aborting')
143 with open(os.environ[
"CMSSWCALLFILES"],
"a")
as outfile:
146 with open(os.environ[
"CMSSWCALLTREE"],
"a")
as outfile:
148 for func
in callgraph.keys():
149 print(
"%s: %s 1" % (progname,
";".
join(reversed(callpath(func)))), file=outfile)
151 for func
in callgraph.keys():
152 for pfunc
in callgraph[func]:
157 callgraph = defaultdict(
lambda: set())
159 def nop_trace(frame, why, arg):
162 def tracefunc(frame, why, arg):
166 filename = code.co_filename
168 for d
in IGNORE_DIRS:
169 if filename.startswith(d):
170 sys.settrace(nop_trace)
171 return wait_for_return
173 funcname = code.co_name
174 code = frame.f_back.f_code
175 p_filename = code.co_filename
176 p_funcname = code.co_name
179 callgraph[(filename, funcname)].
add((p_filename, p_funcname))
182 def wait_for_return(frame, why, arg):
184 sys.settrace(tracefunc)
185 return wait_for_return
188 progname = prog_argv[0]
193 with open(file_path)
as fp:
194 code = compile(fp.read(), progname,
'exec')
197 '__file__': progname,
198 '__name__':
'__main__',
204 atexit.register(
lambda:
writeoutput(callgraph, files))
207 old_execvpe = os.execvpe
208 def exec_hook(*args):
211 os.execvpe = exec_hook
214 sys.settrace(tracefunc)
216 exec code
in globals, globals
220 except OSError
as err:
221 print(
"+Cannot run file %r because: %s" % (sys.argv[0], err))
229 print(
"Usage: %s <some cmssw commandline>" % (sys.argv[0]))
230 print(
" The given programs will be executed, instrumenting calls to %s and cmsRun." % (
", ".
join(WRAP_SCRIPTS)))
231 print(
" cmsRun will not actually run cmssw, but all the Python code will be executed and instrumentd. The results are written to the files `%s` and `%s` in the same directory." % (OUTFILE_FILES, OUTFILE_TREE))
233 print(
" The callgraph output file can be processed with Brendan Gregg's FlameGraph tool.")
235 print(
" The callgraph output lists edges pointing from each function to the one calling it.")
238 print(
" %s runTheMatrix.py -l 1000 --ibeos" % sys.argv[0])
239 print(
"%s cmsRun rpc_dqm_sourceclient-live_cfg.py" % sys.argv[0])
242 print(
"+Running cmsswfiletrace...")
245 for s
in WRAP_SCRIPTS:
246 if sys.argv[0].endswith(s):
247 print(
"+Wrapping %s..." % s)
249 tmppath = os.path.dirname(sys.argv[0])
251 lambda s:
not s.startswith(tmppath),
252 os.environ[
"PATH"].
split(
":")
254 STRIPPATHS.append(os.environ[
"CMSSWCALLBASE"])
257 if sys.argv[0].endswith(
'cmsRun'):
258 print(
"+Wrapping cmsRun...")
260 STRIPPATHS.append(os.environ[
"CMSSWCALLBASE"])
263 if len(sys.argv) <= 1:
267 print(
"+Running command with tracing %s..." % sys.argv[1:])
271 if __name__ ==
'__main__':