2 from __future__
import print_function
9 from shutil
import copy, rmtree
10 from collections
import defaultdict
15 import FWCore.ParameterSet.Types
17 OUTFILE_TREE =
"calltree"
18 OUTFILE_FILES =
"callfiles"
21 WRAP_SCRIPTS = [
"cmsDriver.py" ]
23 os.path.dirname(os.__file__),
24 os.path.dirname(six.__file__),
25 FWCore.ParameterSet.Types.__file__,
28 os.environ[
"CMSSW_BASE"] +
"/python/", os.environ[
"CMSSW_RELEASE_BASE"] +
"/python/",
29 os.environ[
"CMSSW_BASE"] +
"/cfipython/", os.environ[
"CMSSW_RELEASE_BASE"] +
"/cfipython/"]
34 cwd = os.path.abspath(os.getcwd())
35 wf = re.match(
".*/(\d+\.\d+)_", cwd)
37 PREFIXINFO.append(
"wf")
38 PREFIXINFO.append(wf.groups()[0])
39 online = re.match(
"(.*/)?(.*)_dqm_sourceclient-live_cfg\.py", argv[0])
41 PREFIXINFO.append(
"online")
42 PREFIXINFO.append(online.groups()[1])
43 step = re.match(
"(step\d+)_.*\.py", argv[0])
45 PREFIXINFO.append(step.groups()[0])
46 processing = re.match(
"step\d+_.*(RECO|ALCA|HARVEST).*\.py", argv[0])
48 PREFIXINFO.append(processing.groups()[0])
50 PREFIXINFO.append(argv[0])
53 bindir = tempfile.mkdtemp()
54 print(
"+Setting up in ", bindir)
55 for s
in WRAP_SCRIPTS:
56 os.symlink(ARGV0, bindir +
"/" + s)
57 os.symlink(ARGV0, bindir +
"/cmsRun")
58 os.environ[
"PATH"] = bindir +
":" + os.environ[
"PATH"]
59 os.environ[
"CMSSWCALLTREE"] = bindir +
"/" + OUTFILE_TREE
60 os.environ[
"CMSSWCALLFILES"] = bindir +
"/" + OUTFILE_FILES
61 os.environ[
"CMSSWCALLBASE"] = os.path.abspath(os.getcwd()) +
"/"
62 with open(os.environ[
"CMSSWCALLTREE"],
"w")
as f:
64 with open(os.environ[
"CMSSWCALLFILES"],
"w")
as f:
71 print(
"+Cleaning up ", tmpdir)
72 copy(os.environ[
"CMSSWCALLTREE"],
".")
73 copy(os.environ[
"CMSSWCALLFILES"],
".")
79 if not "CMSSWCALLTREE" in os.environ:
88 filename = os.path.abspath(filename)
89 for pfx
in STRIPPATHS:
90 if filename.startswith(pfx):
91 filename = filename[len(pfx):]
97 file_path = os.path.join(entry, progname)
98 if os.path.isfile(file_path):
100 if not os.path.isfile(file_path):
101 print(
"+Cannot find program (%s) in modified $PATH (%s)." % (progname, path))
103 print(
"+Found %s as %s in %s." % (progname, file_path, path))
107 progname =
", ".
join(PREFIXINFO)
108 print(
"+Done running %s, writing output..." % progname)
111 filename, funcname = func
112 return "%s::%s" % (
formatfile(filename), funcname)
123 if len(parents) == 1:
124 func =
next(iter(parents))
137 path.append(
format(func) +
"+")
138 parents = callgraph[func]
141 print(seen, path, parents, func)
142 raise Exception(
'Call path too deep, aborting')
145 with open(os.environ[
"CMSSWCALLFILES"],
"a")
as outfile:
148 with open(os.environ[
"CMSSWCALLTREE"],
"a")
as outfile:
150 for func
in callgraph.keys():
151 print(
"%s: %s 1" % (progname,
";".
join(reversed(callpath(func)))), file=outfile)
153 for func
in callgraph.keys():
154 for pfunc
in callgraph[func]:
159 callgraph = defaultdict(
lambda: set())
161 def nop_trace(frame, why, arg):
164 def tracefunc(frame, why, arg):
168 filename = code.co_filename
170 for d
in IGNORE_DIRS:
171 if filename.startswith(d):
172 sys.settrace(nop_trace)
173 return wait_for_return
175 funcname = code.co_name
176 code = frame.f_back.f_code
177 p_filename = code.co_filename
178 p_funcname = code.co_name
181 callgraph[(filename, funcname)].
add((p_filename, p_funcname))
184 def wait_for_return(frame, why, arg):
186 sys.settrace(tracefunc)
187 return wait_for_return
190 progname = prog_argv[0]
195 with open(file_path)
as fp:
196 code = compile(fp.read(), progname,
'exec')
199 '__file__': progname,
200 '__name__':
'__main__',
206 atexit.register(
lambda:
writeoutput(callgraph, files))
209 old_execvpe = os.execvpe
210 def exec_hook(*args):
213 os.execvpe = exec_hook
216 sys.settrace(tracefunc)
218 exec code
in globals, globals
222 except OSError
as err:
223 print(
"+Cannot run file %r because: %s" % (sys.argv[0], err))
231 print(
"Usage: %s <some cmssw commandline>" % (sys.argv[0]))
232 print(
" The given programs will be executed, instrumenting calls to %s and cmsRun." % (
", ".
join(WRAP_SCRIPTS)))
233 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))
235 print(
" The callgraph output file can be processed with Brendan Gregg's FlameGraph tool.")
237 print(
" The callgraph output lists edges pointing from each function to the one calling it.")
240 print(
" %s runTheMatrix.py -l 1000 --ibeos" % sys.argv[0])
241 print(
"%s cmsRun rpc_dqm_sourceclient-live_cfg.py" % sys.argv[0])
244 print(
"+Running cmsswfiletrace...")
247 for s
in WRAP_SCRIPTS:
248 if sys.argv[0].endswith(s):
249 print(
"+Wrapping %s..." % s)
251 tmppath = os.path.dirname(sys.argv[0])
253 lambda s:
not s.startswith(tmppath),
254 os.environ[
"PATH"].
split(
":")
256 STRIPPATHS.append(os.environ[
"CMSSWCALLBASE"])
259 if sys.argv[0].endswith(
'cmsRun'):
260 print(
"+Wrapping cmsRun...")
262 STRIPPATHS.append(os.environ[
"CMSSWCALLBASE"])
265 if len(sys.argv) <= 1:
269 print(
"+Running command with tracing %s..." % sys.argv[1:])
273 if __name__ ==
'__main__':