2 from __future__
import print_function
12 from shutil
import copy, rmtree
13 from collections
import defaultdict
18 OUTFILE_TREE =
"configtree.sqlite" 19 IGNORE_PACKAGES = [
'FWCore/ParameterSet',
'FWCore/GuiBrowsers',
'DQMOffline/Configuration/scripts',
"cmsRun"]
21 os.environ[
"CMSSW_BASE"] +
"/python/", os.environ[
"CMSSW_RELEASE_BASE"] +
"/python/",
22 os.environ[
"CMSSW_BASE"] +
"/cfipython/", os.environ[
"CMSSW_RELEASE_BASE"] +
"/cfipython/"]
33 del FWCore.ParameterSet.Mixins._Labelable.__str__
39 stack = inspect.stack()
41 while i < len(stack)
and len(stack[i])>=2
and any(
map(
lambda p: p
in stack[i][1], IGNORE_PACKAGES)):
47 while j < len(res)
and not 'cmsRun' in res[j][1]:
50 if len(res)>=1
and len(res[0])>=3:
53 return [(
"unknown",
"unknown",
"unknown")]
55 def trace_location(thing, name, extra = lambda thing, *args, **kwargs: thing):
56 old_method = getattr(thing, name)
57 def trace_location_hook(self, *args, **kwargs):
58 retval = old_method(self, *args, **kwargs)
61 event = (name, tuple(w[1:3]
for w
in where), extra(self, *args, **kwargs))
62 if hasattr(self,
"_trace_events"):
63 getattr(self,
"_trace_events").
append(event)
66 self.__dict__[
"_trace_events"] = [ event ]
69 setattr(thing, name, trace_location_hook)
73 return [x
for x
in args
if not isinstance(x, list)] + sum(
74 [
flatten(*x)
for x
in args
if isinstance(x, list)], [])
77 from FWCore.ParameterSet.Modules
import _Module, Source, ESSource, ESPrefer, ESProducer, Service, Looper
78 from FWCore.ParameterSet.Config
import Process
91 trace_location(_ModuleSequenceType,
'__init__',
lambda self, *arg: {
'args':
list(arg)})
93 trace_location(_ModuleSequenceType,
'associate',
lambda self, *tasks: {
'args':
list(tasks)})
94 trace_location(_ModuleSequenceType,
'__imul__',
lambda self, rhs: {
'rhs': rhs})
95 trace_location(_ModuleSequenceType,
'__iadd__',
lambda self, rhs: {
'rhs': rhs})
96 trace_location(_ModuleSequenceType,
'copyAndExclude',
lambda self, listOfModulesToExclude: {
'olds':
list(listOfModulesToExclude)})
97 trace_location(_ModuleSequenceType,
'replace',
lambda self, original, replacement: {
'old': original,
'new': replacement})
98 trace_location(_ModuleSequenceType,
'insert',
lambda self, index, item: {
'rhs': item})
99 trace_location(_ModuleSequenceType,
'remove',
lambda self, something: {
'old': something})
103 trace_location(Task,
'copyAndExclude',
lambda self, listOfModulesToExclude: {
'olds':
list(listOfModulesToExclude)})
109 import FWCore.ParameterSet.Utilities
111 print(
"+ Blocking convertToUnscheduled to not mess up the process.")
113 raise Exception(
"Aborting in convertToUnscheduled.")
115 FWCore.ParameterSet.Utilities.convertToUnscheduled = convertToUnscheduled
121 items += [(
"source", self.source)]
123 items += [(
"looper", self.looper)]
125 items += self.outputModules.items()
127 items += six.iteritems(self.paths)
128 items += self.endpaths.items()
129 items += self.services.items()
130 items += self.es_producers.items()
131 items += self.es_sources.items()
132 items += self.es_prefers.items()
136 items += [(
"schedule", self.schedule)]
138 Process.items_=new_items_
145 classname = thing.__class__.__name__
146 if hasattr(thing,
'_trace_events'):
147 events =
list(getattr(thing,
'_trace_events'))
148 getattr(thing,
'_trace_events')[:] = []
149 for action, loc, extra
in events:
150 entry = (action, classname, loc)
151 graph.append((entry, parent, name))
155 if hasattr(extra,
'items_'):
156 items += extra.items_()
157 if hasattr(extra,
'_seq'):
158 seq = getattr(extra,
'_seq')
160 items += [(
'seqitem', x)
for x
in getattr(seq,
'_collection')]
161 if hasattr(extra,
'_tasks'):
162 items += [(
'task', x)
for x
in getattr(extra,
'_tasks')]
163 if hasattr(extra,
'_collection'):
164 items += [(
'subtask', x)
for x
in getattr(extra,
'_collection')]
165 if hasattr(extra,
'_operand'):
166 items += [(
'operand', getattr(extra,
'_operand'))]
167 if isinstance(extra, dict):
168 for key, value
in extra.items():
169 if isinstance(value, list):
170 items += [(key, x)
for x
in value]
172 items += [(key, value)]
174 for name, child
in items:
178 if not thing
is None:
179 print(
"No _trace_events found in %s.\nMaybe turn on tracing for %s?" % (thing, classname))
180 print(
" Found in %s" % (parent,))
184 progname =
" ".
join(PREFIXINFO)
185 print(
"+Done running %s, writing output..." % progname)
188 filename = os.path.abspath(filename)
189 for pfx
in STRIPPATHS:
190 if filename.startswith(pfx):
191 filename = filename[len(pfx):]
195 for child, parent, relation
in graph:
196 files.add(child[2][0][0])
197 files.add(parent[2][0][0])
199 conn = sqlite3.connect(os.environ[
"CMSSWCALLTREE"])
201 cur.executescript(
""" 202 CREATE TABLE IF NOT EXISTS file(id INTEGER PRIMARY KEY, 203 name TEXT, UNIQUE(name) 205 CREATE TABLE IF NOT EXISTS trace(id INTEGER PRIMARY KEY, 206 parent INTEGER, -- points into same table, recursively 207 file INTEGER, line INTEGER, 208 FOREIGN KEY(parent) REFERENCES trace(id), 209 FOREIGN KEY(file) REFERENCES file(id), 210 UNIQUE(parent, file, line) 212 CREATE TABLE IF NOT EXISTS relation(id INTEGER PRIMARY KEY, 219 FOREIGN KEY(place) REFERENCES trace(id), 220 FOREIGN KEY(usedby) REFERENCES trace(id) 222 CREATE INDEX IF NOT EXISTS placeidx ON relation(place); 223 CREATE INDEX IF NOT EXISTS usedbyidx ON relation(usedby); 224 CREATE INDEX IF NOT EXISTS traceidx ON trace(file); 225 -- SQLite does not optimise that one well, but a VIEW is still nice to have... 226 CREATE VIEW IF NOT EXISTS fulltrace AS 227 WITH RECURSIVE fulltrace(level, baseid, parent, file, name, line) AS ( 228 SELECT 1 AS level, trace.id, parent, trace.file, file.name, line FROM trace 229 INNER JOIN file ON file.id = trace.file 230 UNION SELECT level+1, baseid, trace.parent, trace.file, file.name, trace.line FROM fulltrace 231 INNER JOIN trace ON trace.id = fulltrace.parent 232 INNER JOIN file ON file.id = trace.file) 233 SELECT * FROM fulltrace; 235 cur.executemany(
"INSERT OR IGNORE INTO file(name) VALUES (?);",
237 def inserttrace(loc):
239 for filename, line
in reversed(loc):
240 conn.execute(
"INSERT OR IGNORE INTO trace(parent, file, line) SELECT ?, id, ? FROM file WHERE name == ?;", (parent, line,
formatfile(filename)))
241 cur = conn.execute(
"SELECT trace.id FROM trace LEFT JOIN file ON trace.file == file.id WHERE trace.parent = ? AND file.name = ? AND trace.line = ?;", (parent,
formatfile(filename), line))
246 for child, parent, relation
in graph:
247 cevt, cclassname, cloc = child
248 pevt, pclassname, ploc = parent
249 place = inserttrace(cloc)
250 usedby = inserttrace(ploc)
251 cur.execute(
"INSERT OR IGNORE INTO relation(place, place_type, usedby, usedby_type, relation, source) VALUES (?,?,?,?,?,?);", (
252 place,
"%s::%s" % (cclassname, cevt),
253 usedby,
"%s::%s" % (pclassname, pevt),
262 cwd = os.path.abspath(os.getcwd())
263 wf = re.match(
".*/(\d+\.\d+)_", cwd)
265 PREFIXINFO.append(
"wf")
266 PREFIXINFO.append(wf.groups()[0])
267 online = re.match(
"(.*/)?(.*)_dqm_sourceclient-live_cfg\.py", argv[0])
269 PREFIXINFO.append(
"online")
270 PREFIXINFO.append(online.groups()[1])
271 step = re.match(
"(step\d+)_.*\.py", argv[0])
273 PREFIXINFO.append(step.groups()[0])
274 processing = re.match(
"step\d+_.*(RECO|ALCA|HARVEST).*\.py", argv[0])
276 PREFIXINFO.append(processing.groups()[0])
278 PREFIXINFO.append(argv[0])
281 bindir = tempfile.mkdtemp()
282 print(
"+Setting up in ", bindir)
283 os.symlink(ARGV0, bindir +
"/cmsRun")
284 os.environ[
"PATH"] = bindir +
":" + os.environ[
"PATH"]
285 os.environ[
"CMSSWCALLTREE"] = bindir +
"/" + OUTFILE_TREE
286 os.environ[
"CMSSWCALLBASE"] = os.path.abspath(os.getcwd()) +
"/" 287 with open(os.environ[
"CMSSWCALLTREE"],
"w")
as f:
292 print(
"+Cleaning up ", tmpdir)
293 copy(os.environ[
"CMSSWCALLTREE"],
".")
299 if not "CMSSWCALLTREE" in os.environ:
302 subprocess.call(argv)
310 progname = prog_argv[0]
313 with open(file_path)
as fp:
314 code = compile(fp.read(), progname,
'exec')
317 exec code
in globals, globals
319 print(traceback.format_exc())
323 print(
"+Collecting trace information from %s..." % globals[
"process"])
324 collect_trace(globals[
"process"],
'cmsrun', graph, (
'cmsRun',
'', ((progname, 0),)))
327 except OSError
as err:
328 print(
"+Cannot run file %r because: %s" % (sys.argv[0], err))
338 file_path = os.path.join(entry, progname)
339 if os.path.isfile(file_path):
341 if not os.path.isfile(file_path):
342 print(
"+Cannot find program (%s) in modified $PATH (%s)." % (progname, path))
344 print(
"+Found %s as %s in %s." % (progname, file_path, path))
349 print(
"Usage: %s <some cmssw commandline>" % (sys.argv[0]))
350 print(
" The given programs will be executed, instrumenting calls to cmsRun.")
351 print(
" cmsRun will not actually run cmssw, but all the Python code will be executed and instrumentd. The results are written to the file `%s` in the same directory." % OUTFILE_TREE)
352 print(
" The callgraph output lists edges pointing from each function to the one calling it.")
353 print(
" To view the results using a simple webpage, use\n %s serve" % sys.argv[0])
355 print(
" %s runTheMatrix.py -l 1000 --ibeos" % sys.argv[0])
358 print(
"+Running cmsswConfigtrace...")
361 if sys.argv[0].endswith(
'cmsRun'):
362 print(
"+Wrapping cmsRun...")
364 STRIPPATHS.append(os.environ[
"CMSSWCALLBASE"])
367 if len(sys.argv) <= 1:
371 print(
"+Running command with tracing %s..." % sys.argv[1:])
378 STRIPPATHS.append(os.path.abspath(os.getcwd()) +
"/")
380 import SimpleHTTPServer
384 conn = sqlite3.connect(OUTFILE_TREE)
389 def formatsource(source, formatstr = '<em class="%s">%s</em>'):
390 processings = [
"ALCA",
"RECO",
"HARVEST",
"online"]
391 info = source.split(
" ")
392 processing =
" ".
join(
filter(
lambda x: x
in processings, info))
393 source =
" ".
join(
filter(
lambda x: x
not in processings, info))
394 return formatstr % (processing,
escape(source))
396 def formatplace(filename, line):
398 shortname = filename[ :(MAXLEN-3)/2] +
"..." + filename[-(MAXLEN-3)/2: ]
if len(filename) > MAXLEN
else filename
399 return '<a href="/%s#%s" target="_blank">%s:%s</a>' % (
escape(filename), line,
escape(shortname), line)
402 out = [
escape(
'goto to /<filename> for info about a file')]
404 wfs = defaultdict(list)
405 for source, wf
in conn.execute(
""" -- some SQL hackery here to parse "source" 406 SELECT DISTINCT source, substr(source, instr(source, "wf ")+3)*1 FROM relation ORDER BY 2, 1;"""):
407 wfs[wf].
append(
'<a href="/workflow/%s">%s</a>' % (urllib.quote(source), formatsource(source)))
410 out.append(
'<li>' +
" ".
join(wfs[wf]) +
"</li>")
414 for f
in conn.execute(
"SELECT name FROM file ORDER BY name;"):
416 out.append(
'<li><a href="/%s">%s</a></li>' % (name, name))
419 return "\n".
join(out)
421 def showworkflow(source):
422 source = urllib.unquote(source)
423 cur = conn.execute(
""" 424 SELECT DISTINCT file.name FROM relation 425 INNER JOIN trace ON place = trace.id 426 INNER JOIN file ON file.id = trace.file 427 WHERE relation.source = ? 430 out = [
"Files used by workflow %s: <ul>" % formatsource(source)]
433 out.append(
'<li><a href="/%s">%s</a></li>' % (name, name))
435 return "\n".
join(out)
437 def showfile(filename):
439 out.append(
'<script src="https://rawgit.com/google/code-prettify/master/src/prettify.js"></script>')
440 out.append(
'<link rel="stylesheet" href="https://rawgit.com/google/code-prettify/master/src/prettify.css"></link>')
445 with open(d + filename)
as f:
446 lines = f.readlines()
447 out.append(
"Read %s" % f.name)
453 cur = conn.execute(
""" 454 SELECT DISTINCT trace.line, source FROM relation 455 INNER JOIN trace on relation.place = trace.id 456 INNER JOIN file ON trace.file == file.id 457 WHERE file.name == ? ORDER BY line, source;""", (filename,))
458 sourceinfo = defaultdict(list)
459 for line, source
in cur:
460 sourceinfo[line].
append(source)
462 out.append(
'<pre class="prettyprint linenums">')
463 for i, l
in enumerate(lines):
465 tags = [formatsource(source,
'<em class="%%s" data-tag="%%s" data-line="%d"></em>' % (i+1))
for source
in sourceinfo[i+1]]
466 out.append(
escape(l).rstrip() +
"".
join(tags))
469 out.append(
"""<script type="text/javascript"> 471 clickfunc = function(evt) { 472 document.querySelectorAll("li > iframe, li > br").forEach(function(e) {e.remove()}); 473 dest = "/info" + window.location.pathname + ":" + this.getAttribute("data-line"); 474 this.parentElement.insertAdjacentHTML("beforeend", '<br><iframe width="90%" height="500px" frameborder="0" src="' + dest + '"></iframe><br>'); 476 document.querySelectorAll("li > em").forEach(function(e) { 477 e.innerText = e.getAttribute("data-tag"); 478 e.onclick = clickfunc; 481 n = 1*window.location.hash.replace("#", ""); 483 li = document.querySelectorAll("li")[n-1]; 484 li.style = "background: #ee7"; 490 out.append(
"Could not find %s" % filename)
492 return "\n".
join(out)
495 def showinfo(filename, line):
498 def queryandoutput(startfrom, to, directiontext):
500 cur = conn.execute(
""" 501 SELECT place_type, -- why did we trace this line? 502 <to>file.name, <to>trace.line, -- where was it used? 503 usedby, usedby_type, relation, -- what was it used for? 504 place, source -- why did this code run? 506 INNER JOIN trace AS placetrace ON placetrace.id = relation.place 507 INNER JOIN trace AS usedbytrace ON usedbytrace.id = relation.usedby 508 INNER JOIN file AS placefile ON placefile.id = placetrace.file 509 INNER JOIN file AS usedbyfile ON usedbyfile.id = usedbytrace.file 510 WHERE <from>file.name = ? AND <from>trace.line = ? 512 .
replace(
"<from>", startfrom).
replace(
"<to>", to), (filename, line))
513 out.append(
"<p>%s %s <ul>" % (formatplace(filename, line), directiontext))
514 for place_type, pname, pline, usedby, usedby_type, relation, place, source
in cur:
516 '<li><tt>%s</tt> at %s by <tt>%s</tt> as <a href="/why/%d">%s</a> <a href="/why/%d">in</a> %s</li>' 517 % (
escape(place_type), formatplace(pname, pline),
escape(usedby_type), usedby,
escape(relation), place, formatsource(source)))
518 out.append(
"</ul></p>")
520 queryandoutput(
"place",
"usedby",
"is used as")
521 queryandoutput(
"usedby",
"place",
"uses")
523 return "\n".
join(out)
528 cur = conn.execute(
""" 529 WITH RECURSIVE fulltrace(level, baseid, parent, file, name, line) AS ( 530 SELECT 1 AS level, trace.id, parent, trace.file, file.name, line FROM trace 531 INNER JOIN file ON file.id = trace.file 533 UNION SELECT level+1, baseid, trace.parent, trace.file, file.name, trace.line FROM fulltrace 534 INNER JOIN trace ON trace.id = fulltrace.parent 535 INNER JOIN file ON file.id = trace.file) 536 SELECT name, line FROM fulltrace ORDER BY level;""", (id,))
538 out.append(
"Full stack trace:<ul>")
539 for name, line
in cur:
540 out.append(
'<li>%s</li>' % formatplace(name, line))
542 return "\n".
join(out)
545 (re.compile(
'/workflow/(.*)$'), showworkflow),
546 (re.compile(
'/info/(.*):(\d+)$'), showinfo),
547 (re.compile(
'/why/(\d+)$'), showwhy),
548 (re.compile(
'/(.+)$'), showfile),
549 (re.compile(
'/$'), index),
555 for pattern, func
in ROUTES:
556 m = pattern.match(self.path)
558 res =
func(*m.groups())
562 self.send_response(200,
"Here you go")
563 self.send_header(
"Content-Type",
"text/html; charset=utf-8")
565 self.wfile.write(
"""<html><style> 575 em.ALCA {background: #ee9; } 576 em.RECO {background: #9e9; } 577 em.HARVEST {background: #99e; } 578 em.online {background: #e99; } 580 self.wfile.write(res)
581 self.wfile.write(
"</body></html>")
584 self.send_response(400,
"Something went wrong")
586 trace = traceback.format_exc()
587 self.send_response(500,
"Things went very wrong")
588 self.send_header(
"Content-Type",
"text/plain; charset=utf-8")
590 self.wfile.write(trace)
593 Handler = SimpleHTTPServer.SimpleHTTPRequestHandler
594 Handler.do_GET = do_GET
595 httpd = SocketServer.TCPServer((
"",SERVE_PORT), Handler)
596 print(
"serving at port", SERVE_PORT)
597 httpd.serve_forever()
599 if __name__ ==
'__main__':
600 if sys.argv[1] ==
"serve":
def collect_trace(thing, name, graph, parent)
bool any(const std::vector< T > &v, const T &what)
def replace(string, replacements)
S & print(S &os, JobReport::InputFile const &f)
def searchinpath(progname, path)
def convertToUnscheduled(proc)
def trace_python(prog_argv, path)
static std::string join(char **cmd)
How EventSelector::AcceptEvent() decides whether to accept an event for output otherwise it is excluding the probing of A single or multiple positive and the trigger will pass if any such matching triggers are PASS or EXCEPTION[A criterion thatmatches no triggers at all is detected and causes a throw.] A single negative with an expectation of appropriate bit checking in the decision and the trigger will pass if any such matching triggers are FAIL or EXCEPTION A wildcarded negative criterion that matches more than one trigger in the trigger list("!*","!HLTx*"if it matches 2 triggers or more) will accept the event if all the matching triggers are FAIL.It will reject the event if any of the triggers are PASS or EXCEPTION(this matches the behavior of"!*"before the partial wildcard feature was incorporated).Triggers which are in the READY state are completely ignored.(READY should never be returned since the trigger paths have been run