CMS 3D CMS Logo

Functions
cmsswConfigtrace Namespace Reference

Functions

def addprefixinfo (argv)
 
def auto_inspect ()
 
def cleanupenv (tmpdir)
 
def collect_trace (thing, name, graph, parent)
 
def convertToUnscheduled (proc)
 
def flatten (args)
 
def help ()
 
def main ()
 
def new_items_ (self)
 
def searchinpath (progname, path)
 
def serve_main ()
 
def setupenv ()
 
def trace_command (argv)
 
def trace_location
 
def trace_python (prog_argv, path)
 
def writeoutput (graph)
 

Function Documentation

def cmsswConfigtrace.addprefixinfo (   argv)
  1. Launch and keep track of all the processes.

Definition at line 261 of file cmsswConfigtrace.py.

Referenced by main().

261 def addprefixinfo(argv):
262  cwd = os.path.abspath(os.getcwd())
263  wf = re.match(".*/(\d+\.\d+)_", cwd)
264  if wf:
265  PREFIXINFO.append("wf")
266  PREFIXINFO.append(wf.groups()[0])
267  online = re.match("(.*/)?(.*)_dqm_sourceclient-live_cfg\.py", argv[0])
268  if online:
269  PREFIXINFO.append("online")
270  PREFIXINFO.append(online.groups()[1])
271  step = re.match("(step\d+)_.*\.py", argv[0])
272  if step:
273  PREFIXINFO.append(step.groups()[0])
274  processing = re.match("step\d+_.*(RECO|ALCA|HARVEST).*\.py", argv[0])
275  if processing:
276  PREFIXINFO.append(processing.groups()[0])
277  if not PREFIXINFO:
278  PREFIXINFO.append(argv[0])
279 
def cmsswConfigtrace.auto_inspect ( )

Definition at line 37 of file cmsswConfigtrace.py.

References any(), and genParticles_cff.map.

Referenced by trace_location().

38  # stolen from FWCore.GuiBrowsers.EnablePSetHistory, but needs more black-list
39  stack = inspect.stack()
40  i = 0
41  while i < len(stack) and len(stack[i])>=2 and any(map(lambda p: p in stack[i][1], IGNORE_PACKAGES)):
42  i += 1
43  res = stack[i: ]
44  j = 0
45  # for the other end we only use cmsRun (instead of IGNORE_PACKAGES) to avoid
46  # cutting traces in the middle that enter and leave IGNORE_PACKAGES
47  while j < len(res) and not 'cmsRun' in res[j][1]:
48  j += 1
49  res = res[:j]
50  if len(res)>=1 and len(res[0])>=3:
51  return res
52  else:
53  return [("unknown","unknown","unknown")]
54 
bool any(const std::vector< T > &v, const T &what)
Definition: ECalSD.cc:37
def cmsswConfigtrace.cleanupenv (   tmpdir)

Definition at line 291 of file cmsswConfigtrace.py.

References popcon2dropbox.copy(), edm.print(), and cmsPerfRegress.rmtree().

Referenced by trace_command().

291 def cleanupenv(tmpdir):
292  print("+Cleaning up ", tmpdir)
293  copy(os.environ["CMSSWCALLTREE"], ".")
294  rmtree(tmpdir)
295 
296 
def copy(args, dbName)
S & print(S &os, JobReport::InputFile const &f)
Definition: JobReport.cc:66
def cleanupenv(tmpdir)
def cmsswConfigtrace.collect_trace (   thing,
  name,
  graph,
  parent 
)
  1. The logic to collect, process, and save the information from the process.

Definition at line 142 of file cmsswConfigtrace.py.

References list(), and edm.print().

Referenced by trace_python().

142 def collect_trace(thing, name, graph, parent):
143  # thing is what to look at, graph is the output list (of child, parent tuple pairs)
144  # thing could be pretty much anything.
145  classname = thing.__class__.__name__
146  if hasattr(thing, '_trace_events'):
147  events = list(getattr(thing, '_trace_events'))
148  getattr(thing, '_trace_events')[:] = [] # erase events so we can't end up in cycles
149  for action, loc, extra in events:
150  entry = (action, classname, loc)
151  graph.append((entry, parent, name))
152 
153  # items shall be a list of tuples (type, object) of the immediate children of the thing.
154  items = []
155  if hasattr(extra, 'items_'): # for cms.Process
156  items += extra.items_()
157  if hasattr(extra, '_seq'): # for sequences and similar
158  seq = getattr(extra, '_seq')
159  if seq:
160  items += [('seqitem', x) for x in getattr(seq, '_collection')]
161  if hasattr(extra, '_tasks'): # same
162  items += [('task', x) for x in getattr(extra, '_tasks')]
163  if hasattr(extra, '_collection'): # for cms.Task
164  items += [('subtask', x) for x in getattr(extra, '_collection')]
165  if hasattr(extra, '_operand'): # for _SeqenceNegation etc.
166  items += [('operand', getattr(extra, '_operand'))]
167  if isinstance(extra, dict): # stuff that we track explicitly^
168  for key, value in extra.items():
169  if isinstance(value, list):
170  items += [(key, x) for x in value]
171  else:
172  items += [(key, value)]
173 
174  for name, child in items:
175  collect_trace(child, name, graph, entry)
176 
177  else:
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,))
181 
182 
def collect_trace(thing, name, graph, parent)
S & print(S &os, JobReport::InputFile const &f)
Definition: JobReport.cc:66
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
def cmsswConfigtrace.convertToUnscheduled (   proc)

Definition at line 110 of file cmsswConfigtrace.py.

References edm.print().

Referenced by ConfigBuilder.ConfigBuilder.prepare().

111  print("+ Blocking convertToUnscheduled to not mess up the process.")
112  # we could continue tracing, but the later manipulations don't make much sense and take forever.
113  raise Exception("Aborting in convertToUnscheduled.")
114  return proc
115 FWCore.ParameterSet.Utilities.convertToUnscheduled = convertToUnscheduled
116 
117 # lifted from EnablePSetHistory, we don't need all of that stuff.
S & print(S &os, JobReport::InputFile const &f)
Definition: JobReport.cc:66
def convertToUnscheduled(proc)
def cmsswConfigtrace.flatten (   args)

Definition at line 71 of file cmsswConfigtrace.py.

References list(), and trace_location().

71 def flatten(*args):
72  # that was surprisingly hard...
73  return [x for x in args if not isinstance(x, list)] + sum(
74  [flatten(*x) for x in args if isinstance(x, list)], [])
75 
def cmsswConfigtrace.help ( )

Definition at line 348 of file cmsswConfigtrace.py.

References edm.print().

Referenced by main().

348 def help():
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])
354  print("Examples:")
355  print(" %s runTheMatrix.py -l 1000 --ibeos" % sys.argv[0])
356 
S & print(S &os, JobReport::InputFile const &f)
Definition: JobReport.cc:66
def cmsswConfigtrace.main ( )

Definition at line 357 of file cmsswConfigtrace.py.

References addprefixinfo(), help(), edm.print(), trace_command(), and trace_python().

357 def main():
358  print("+Running cmsswConfigtrace...")
359  global ARGV0
360  ARGV0 = sys.argv[0]
361  if sys.argv[0].endswith('cmsRun'):
362  print("+Wrapping cmsRun...")
363  addprefixinfo(sys.argv[1:])
364  STRIPPATHS.append(os.environ["CMSSWCALLBASE"])
365  trace_python(sys.argv[1:], ["."])
366  return
367  if len(sys.argv) <= 1:
368  help()
369  return
370  # else
371  print("+Running command with tracing %s..." % sys.argv[1:])
372  trace_command(sys.argv[1:])
373 
S & print(S &os, JobReport::InputFile const &f)
Definition: JobReport.cc:66
def trace_python(prog_argv, path)
def cmsswConfigtrace.new_items_ (   self)

Definition at line 118 of file cmsswConfigtrace.py.

118 def new_items_(self):
119  items = []
120  if self.source:
121  items += [("source", self.source)]
122  if self.looper:
123  items += [("looper", self.looper)]
124  #items += self.moduleItems_()
125  items += self.outputModules.items()
126  #items += self.sequences.items() # TODO: we don't need sequences that are not paths?
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()
133  #items += self.psets.items()
134  #items += self.vpsets.items()
135  if self.schedule:
136  items += [("schedule", self.schedule)]
137  return tuple(items)
138 Process.items_=new_items_
139 
def cmsswConfigtrace.searchinpath (   progname,
  path 
)

Definition at line 335 of file cmsswConfigtrace.py.

References edm.print().

Referenced by trace_python().

335 def searchinpath(progname, path):
336  # Search $PATH. There seems to be no pre-made function for this.
337  for entry in path:
338  file_path = os.path.join(entry, progname)
339  if os.path.isfile(file_path):
340  break
341  if not os.path.isfile(file_path):
342  print("+Cannot find program (%s) in modified $PATH (%s)." % (progname, path))
343  sys.exit(1)
344  print("+Found %s as %s in %s." % (progname, file_path, path))
345  return file_path
346 
347 
S & print(S &os, JobReport::InputFile const &f)
Definition: JobReport.cc:66
def searchinpath(progname, path)
def cmsswConfigtrace.serve_main ( )
  1. The web-based GUI.

Definition at line 376 of file cmsswConfigtrace.py.

References mps_setup.append, PhysicsTools.escape(), ALCARECOTkAlBeamHalo_cff.filter, jets_cff.func, createfilelist.int, join(), edm.print(), python.rootplot.root2matplotlib.replace(), and str.

377  # we use STRIPPATHS as a search path to find code files.
378  STRIPPATHS.append(os.path.abspath(os.getcwd()) + "/")
379 
380  import SimpleHTTPServer
381  import SocketServer
382  import urllib
383 
384  conn = sqlite3.connect(OUTFILE_TREE)
385 
386  def escape(s):
387  return str(s).replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;").replace('"', "&quot;")
388 
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))
395 
396  def formatplace(filename, line):
397  MAXLEN = 80
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)
400 
401  def index():
402  out = [escape('goto to /<filename> for info about a file')]
403 
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)))
408  out.append("<ul>")
409  for wf in wfs:
410  out.append('<li>' + " ".join(wfs[wf]) + "</li>")
411  out.append("</ul>")
412 
413  out.append("<ul>")
414  for f in conn.execute("SELECT name FROM file ORDER BY name;"):
415  name = escape(f[0])
416  out.append('<li><a href="/%s">%s</a></li>' % (name, name))
417  out.append("</ul>")
418 
419  return "\n".join(out)
420 
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 = ?
428  ORDER BY file.name;
429  """, (source, ))
430  out = ["Files used by workflow %s: <ul>" % formatsource(source)]
431  for f in cur:
432  name = escape(f[0])
433  out.append('<li><a href="/%s">%s</a></li>' % (name, name))
434  out.append("</ul>")
435  return "\n".join(out)
436 
437  def showfile(filename):
438  out = []
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>')
441 
442  lines = None
443  for d in STRIPPATHS:
444  try:
445  with open(d + filename) as f:
446  lines = f.readlines()
447  out.append("Read %s" % f.name)
448  break
449  except:
450  pass
451 
452  if lines:
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)
461 
462  out.append('<pre class="prettyprint linenums">')
463  for i, l in enumerate(lines):
464  # put the text into data-tag here and move it later, to not mess up syntax HL
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))
467  out.append('</pre>')
468 
469  out.append("""<script type="text/javascript">
470  PR.prettyPrint();
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>');
475  };
476  document.querySelectorAll("li > em").forEach(function(e) {
477  e.innerText = e.getAttribute("data-tag");
478  e.onclick = clickfunc;
479  })
480 
481  n = 1*window.location.hash.replace("#", "");
482  if (n > 0) {
483  li = document.querySelectorAll("li")[n-1];
484  li.style = "background: #ee7";
485  li.scrollIntoView();
486  }
487  </script>""")
488 
489  else:
490  out.append("Could not find %s" % filename)
491 
492  return "\n".join(out)
493 
494 
495  def showinfo(filename, line):
496  line = int(line)
497  out = []
498  def queryandoutput(startfrom, to, directiontext):
499  # we format in the side of the relation to query for here...
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?
505  FROM relation
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 = ?
511  LIMIT 1000; """
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:
515  out.append(
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>")
519 
520  queryandoutput("place", "usedby", "is used as")
521  queryandoutput("usedby", "place", "uses")
522 
523  return "\n".join(out)
524 
525  def showwhy(id):
526  id = int(id)
527  # this (WHERE before recursion) will optimize better than the view.
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
532  WHERE trace.id = ?
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,))
537  out = []
538  out.append("Full stack trace:<ul>")
539  for name, line in cur:
540  out.append('<li>%s</li>' % formatplace(name, line))
541  out.append("</ul>")
542  return "\n".join(out)
543 
544  ROUTES = [
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),
550  ]
551 
552  def do_GET(self):
553  try:
554  res = None
555  for pattern, func in ROUTES:
556  m = pattern.match(self.path)
557  if m:
558  res = func(*m.groups())
559  break
560 
561  if res:
562  self.send_response(200, "Here you go")
563  self.send_header("Content-Type", "text/html; charset=utf-8")
564  self.end_headers()
565  self.wfile.write("""<html><style>
566  body {
567  font-family: sans;
568  }
569  em {
570  cursor: pointer;
571  padding: 0 2px;
572  margin: 1 2px;
573  background: #999;
574  }
575  em.ALCA {background: #ee9; }
576  em.RECO {background: #9e9; }
577  em.HARVEST {background: #99e; }
578  em.online {background: #e99; }
579  </style><body>""")
580  self.wfile.write(res)
581  self.wfile.write("</body></html>")
582  self.wfile.close()
583  else:
584  self.send_response(400, "Something went wrong")
585  except:
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")
589  self.end_headers()
590  self.wfile.write(trace)
591  self.wfile.close()
592 
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()
598 
static std::string escape(const std::string &in)
Definition: MVATrainer.cc:403
def replace(string, replacements)
S & print(S &os, JobReport::InputFile const &f)
Definition: JobReport.cc:66
static std::string join(char **cmd)
Definition: RemoteFile.cc:18
#define str(s)
def cmsswConfigtrace.setupenv ( )

Definition at line 280 of file cmsswConfigtrace.py.

References edm.print().

Referenced by trace_command().

280 def setupenv():
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:
288  pass
289  return bindir
290 
S & print(S &os, JobReport::InputFile const &f)
Definition: JobReport.cc:66
def cmsswConfigtrace.trace_command (   argv)

Definition at line 297 of file cmsswConfigtrace.py.

References cleanupenv(), and setupenv().

Referenced by main().

297 def trace_command(argv):
298  tmpdir = None
299  if not "CMSSWCALLTREE" in os.environ:
300  tmpdir = setupenv()
301 
302  subprocess.call(argv)
303 
304  if tmpdir:
305  cleanupenv(tmpdir)
306 
def cleanupenv(tmpdir)
def cmsswConfigtrace.trace_location (   thing,
  name,
  extra = lambda thing,
  args,
  kwargs 
)

Definition at line 55 of file cmsswConfigtrace.py.

References mps_setup.append, and auto_inspect().

Referenced by flatten().

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)
59  where = auto_inspect()
60  #print("Called %s::%s at %s" % (thing.__name__, name, where[0][1:3]))
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)
64  else:
65  # this bypasses setattr checks
66  self.__dict__["_trace_events"] = [ event ]
67 
68  return retval
69  setattr(thing, name, trace_location_hook)
70 
def cmsswConfigtrace.trace_python (   prog_argv,
  path 
)

Definition at line 307 of file cmsswConfigtrace.py.

References collect_trace(), edm.print(), searchinpath(), and writeoutput().

Referenced by main().

307 def trace_python(prog_argv, path):
308  graph = []
309  sys.argv = prog_argv
310  progname = prog_argv[0]
311  file_path = searchinpath(progname, path)
312  try:
313  with open(file_path) as fp:
314  code = compile(fp.read(), progname, 'exec')
315  globals = {}
316  try:
317  exec code in globals, globals
318  except:
319  print(traceback.format_exc())
320  finally:
321  # reporting is only possible if the config was executed successfully.
322  # we still do it in case of an exception, which can happen after convertToUnscheduled()
323  print("+Collecting trace information from %s..." % globals["process"])
324  collect_trace(globals["process"], 'cmsrun', graph, ('cmsRun', '', ((progname, 0),)))
325  writeoutput(graph)
326 
327  except OSError as err:
328  print("+Cannot run file %r because: %s" % (sys.argv[0], err))
329  sys.exit(1)
330  except SystemExit:
331  pass
332  # this is not necessarily reached at all.
333  sys.exit(0)
334 
def collect_trace(thing, name, graph, parent)
def writeoutput(graph)
S & print(S &os, JobReport::InputFile const &f)
Definition: JobReport.cc:66
def searchinpath(progname, path)
def trace_python(prog_argv, path)
def cmsswConfigtrace.writeoutput (   graph)

Definition at line 183 of file cmsswConfigtrace.py.

References cmsswFiletrace.formatfile(), join(), and edm.print().

Referenced by trace_python().

183 def writeoutput(graph):
184  progname = " ".join(PREFIXINFO)
185  print("+Done running %s, writing output..." % progname)
186 
187  def formatfile(filename):
188  filename = os.path.abspath(filename)
189  for pfx in STRIPPATHS:
190  if filename.startswith(pfx):
191  filename = filename[len(pfx):]
192  return filename
193 
194  files = set()
195  for child, parent, relation in graph:
196  files.add(child[2][0][0])
197  files.add(parent[2][0][0])
198 
199  conn = sqlite3.connect(os.environ["CMSSWCALLTREE"])
200  cur = conn.cursor()
201  cur.executescript("""
202  CREATE TABLE IF NOT EXISTS file(id INTEGER PRIMARY KEY,
203  name TEXT, UNIQUE(name)
204  );
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)
211  );
212  CREATE TABLE IF NOT EXISTS relation(id INTEGER PRIMARY KEY,
213  place INTEGER,
214  place_type TEXT,
215  usedby INTEGER,
216  usedby_type TEXT,
217  relation TEXT,
218  source TEXT,
219  FOREIGN KEY(place) REFERENCES trace(id),
220  FOREIGN KEY(usedby) REFERENCES trace(id)
221  );
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;
234  """)
235  cur.executemany("INSERT OR IGNORE INTO file(name) VALUES (?);",
236  ((formatfile(f),) for f in files))
237  def inserttrace(loc):
238  parent = 0
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))
242  for row in cur:
243  parent = row[0]
244  return parent
245 
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),
254  relation, progname
255  ))
256  conn.commit()
257  conn.close()
258 
def writeoutput(graph)
S & print(S &os, JobReport::InputFile const &f)
Definition: JobReport.cc:66
static std::string join(char **cmd)
Definition: RemoteFile.cc:18
def formatfile(filename)