CMS 3D CMS Logo

cmsswSequenceInfo.py
Go to the documentation of this file.
1 #!/usr/bin/env python3
2 import os
3 import re
4 import time
5 import shutil
6 import sqlite3
7 import tempfile
8 import functools
9 import subprocess
10 from collections import namedtuple
11 from collections import defaultdict
12 from multiprocessing.pool import ThreadPool
13 
14 Sequence = namedtuple("Sequence", ["seqname", "step", "era", "scenario", "mc", "data", "fast"])
15 
16 # We use two global thread pools, to avoid submitting from one Pool into itself.
17 tp = ThreadPool()
18 stp = ThreadPool()
19 
20 # SQLiteDB to write results to.
21 # Set later from commandline args.
22 DBFILE = None
23 
24 # This file will actually be opened, though the content does not matter. Only to make CMSSW start up at all.
25 INFILE = "/store/data/Run2018A/EGamma/RAW/v1/000/315/489/00000/004D960A-EA4C-E811-A908-FA163ED1F481.root"
26 
27 # Modules that will be loaded but do not come from the DQM Sequence.
28 BLACKLIST='^(TriggerResults|.*_step|DQMoutput|siPixelDigis)$'
29 
30 # Set later from commandline args
31 RELEVANTSTEPS = []
32 
33 @functools.lru_cache(maxsize=None)
34 def inspectsequence(seq):
35  sep = ":"
36  if not seq.seqname:
37  sep = ""
38  otherstep = ""
39  if seq.step not in ("HARVESTING", "ALCAHARVEST"):
40  # cmsDriver refuses to run some steps on their own, so we add this to them
41  # only loading a single module that we can blacklist later
42  otherstep = "RAW2DIGI:siPixelDigis,"
43 
44  wd = tempfile.mkdtemp()
45 
46  # Provide a fake GDB to prevent it from running if cmsRun crashes. It would not hurt to have it run but it takes forever.
47  with open(wd + "/gdb", "w"):
48  pass
49  os.chmod(wd + "/gdb", 0o700)
50  env = os.environ.copy()
51  env["PATH"] = wd + ":" + env["PATH"]
52 
53  # run cmsdriver
54  driverargs = [
55  "cmsDriver.py",
56  "step3",
57  "--conditions", "auto:run2_data", # conditions is mandatory, but should not affect the result.
58  "-s", otherstep+seq.step+sep+seq.seqname, # running only DQM seems to be not possible, so also load a single module for RAW2DIGI
59  "--process", "DUMMY",
60  "--mc" if seq.mc else "", "--data" if seq.data else "", "--fast" if seq.fast else "", # random switches
61  "--era" if seq.era else "", seq.era, # era is important as it trigger e.g. switching phase0/pahse1/phase2
62  "--eventcontent", "DQM", "--scenario" if seq.scenario else "", seq.scenario, # sceanario should affect which DQMOffline_*_cff.py is loaded
63  "--datatier", "DQMIO", # more random switches,
64  "--customise_commands", 'process.Tracer = cms.Service("Tracer")', # the tracer will tell us which modules actually run
65  "--filein", INFILE, "-n", "0", # load an input file, but do not process any events -- it would fail anyways.
66  "--python_filename", "cmssw_cfg.py", "--no_exec"
67  ]
68  # filter out empty args
69  driverargs = [x for x in driverargs if x]
70  subprocess.check_call(driverargs, cwd=wd, stdout=2) # 2: STDERR
71 
72  # run cmsRun to get module list
73  proc = subprocess.Popen(["cmsRun", "cmssw_cfg.py"], stderr=subprocess.STDOUT, stdout=subprocess.PIPE, cwd=wd, env=env)
74  tracedump, _ = proc.communicate()
75  # for HARVESTING, the code in endJob makes most jobs crash. But that is fine,
76  # we have the data we need by then.
77  if proc.returncode and seq.step not in ("HARVESTING", "ALCAHARVEST"):
78  raise Exception("cmsRun failed for cmsDriver command %s" % driverargs)
79 
80  lines = tracedump.splitlines()
81  labelre = re.compile(b"[+]+ starting: constructing module with label '(\w+)'")
82  blacklistre = re.compile(BLACKLIST)
83  modules = []
84  for line in lines:
85  m = labelre.match(line)
86  if m:
87  label = m.group(1).decode()
88  if blacklistre.match(label):
89  continue
90  modules.append(label)
91 
92  modules = set(modules)
93 
94  # run edmConfigDump to get module config
95  configdump = subprocess.check_output(["edmConfigDump", "cmssw_cfg.py"], cwd=wd)
96  lines = configdump.splitlines()
97  modulere = re.compile(b'process[.](.*) = cms.ED.*\("(.*)",')
98 
99  # collect the config blocks out of the config dump.
100  modclass = dict()
101  modconfig = dict()
102  inconfig = None
103  for line in lines:
104  if inconfig:
105  modconfig[inconfig] += b'\n' + line
106  if line == b')':
107  inconfig = None
108  continue
109 
110  m = modulere.match(line)
111  if m:
112  label = m.group(1).decode()
113  plugin = m.group(2).decode()
114  if label in modules:
115  modclass[label] = plugin
116  modconfig[label] = line
117  inconfig = label
118 
119  # run edmPluginHelp to get module properties
120  plugininfo = tp.map(getplugininfo, modclass.values())
121 
122  # clean up the temp dir in the end.
123  shutil.rmtree(wd)
124 
125  return modconfig, modclass, dict(plugininfo)
126 
127 # using a cache here to avoid running the (rather slow) edmPluginHelp multiple
128 # times for the same module (e.g. across different wf).
129 @functools.lru_cache(maxsize=None)
130 def getplugininfo(pluginname):
131  plugindump = subprocess.check_output(["edmPluginHelp", "-p", pluginname])
132  line = plugindump.splitlines()[0].decode()
133  # we care only about the edm base class for now.
134  pluginre = re.compile(".* " + pluginname + ".*[(]((\w+)::)?(\w+)[)]")
135  m = pluginre.match(line)
136  if not m:
137  # this should never happen, but sometimes the Tracer does report things that are not actually plugins.
138  return (pluginname, ("", ""))
139  else:
140  return (pluginname, (m.group(2), m.group(3)))
141 
142 def formatsequenceinfo(modconfig, modclass, plugininfo, showlabel, showclass, showtype, showconfig):
143  # printing for command-line use.
144  out = []
145  for label in modclass.keys():
146  row = []
147  if showlabel:
148  row.append(label)
149  if showclass:
150  row.append(modclass[label])
151  if showtype:
152  row.append("::".join(plugininfo[modclass[label]]))
153  if showconfig:
154  row.append(modconfig[label].decode())
155  out.append(tuple(row))
156  for row in sorted(set(out)):
157  print("\t".join(row))
158 
159 # DB schema for the HTML based browser. The Sequence members are kept variable
160 # to make adding new fields easy.
161 SEQFIELDS = ",".join(Sequence._fields)
162 SEQPLACEHOLDER = ",".join(["?" for f in Sequence._fields])
163 DBSCHEMA = f"""
164  CREATE TABLE IF NOT EXISTS plugin(classname, edmfamily, edmbase);
165  CREATE UNIQUE INDEX IF NOT EXISTS plugins ON plugin(classname);
166  CREATE TABLE IF NOT EXISTS module(id INTEGER PRIMARY KEY, classname, instancename, variation, config);
167  CREATE UNIQUE INDEX IF NOT EXISTS modules ON module(instancename, variation);
168  CREATE UNIQUE INDEX IF NOT EXISTS configs ON module(config);
169  CREATE TABLE IF NOT EXISTS sequence(id INTEGER PRIMARY KEY, {SEQFIELDS});
170  CREATE UNIQUE INDEX IF NOT EXISTS squences ON sequence({SEQFIELDS});
171  CREATE TABLE IF NOT EXISTS workflow(wfid, sequenceid);
172  CREATE UNIQUE INDEX IF NOT EXISTS wrokflows ON workflow(sequenceid, wfid);
173  CREATE TABLE IF NOT EXISTS sequencemodule(moduleid, sequenceid);
174 """
175 
176 def storesequenceinfo(seq, modconfig, modclass, plugininfo):
177  with sqlite3.connect(DBFILE) as db:
178  cur = db.cursor()
179  cur.executescript(DBSCHEMA)
180  # first, check if we already have that one. Ideally we'd check before doing all the work, but then the lru cache will take care of that on a different level.
181  seqid = list(cur.execute(f"SELECT id FROM sequence WHERE ({SEQFIELDS}) = ({SEQPLACEHOLDER});", (seq)))
182  if seqid:
183  return
184 
185  cur.execute("BEGIN;")
186  # dump everything into a temp table first...
187  cur.execute("CREATE TEMP TABLE newmodules(instancename, classname, config);")
188  cur.executemany("INSERT INTO newmodules VALUES (?, ?, ?)", ((label, modclass[label], modconfig[label]) for label in modconfig))
189  # ... then deduplicate and version the configs in plain SQL.
190  cur.execute("""
191  INSERT OR IGNORE INTO module(classname, instancename, variation, config)
192  SELECT classname, instancename,
193  (SELECT count(*) FROM module AS existing WHERE existing.instancename = newmodules.instancename),
194  config FROM newmodules;
195  """)
196 
197  # the plugin base is rather easy.
198  cur.executemany("INSERT OR IGNORE INTO plugin VALUES (?, ?, ?);", ((plugin, edm[0], edm[1]) for plugin, edm in plugininfo.items()))
199  # for the sequence we first insert, then query for the ID, then insert the modules into the relation table.
200  cur.execute(f"INSERT OR FAIL INTO sequence({SEQFIELDS}) VALUES({SEQPLACEHOLDER});", (seq))
201  seqid = list(cur.execute(f"SELECT id FROM sequence WHERE ({SEQFIELDS}) = ({SEQPLACEHOLDER});", (seq)))
202  seqid = seqid[0][0]
203  cur.executemany("INSERT INTO sequencemodule SELECT id, ? FROM module WHERE config = ?;", ((seqid, modconfig[label]) for label in modconfig))
204  cur.execute("COMMIT;")
205 
206 def storeworkflows(seqs):
207  with sqlite3.connect(DBFILE) as db:
208  cur = db.cursor()
209  cur.execute("BEGIN;")
210  cur.executescript(DBSCHEMA)
211  pairs = [[wf] + list(seq) for wf, seqlist in seqs.items() for seq in seqlist]
212  cur.executemany(f"INSERT OR IGNORE INTO workflow SELECT ?, (SELECT id FROM sequence WHERE ({SEQFIELDS}) = ({SEQPLACEHOLDER}));", pairs)
213  cur.execute("COMMIT;")
214 
215 def inspectworkflows(wfnumber):
216  # here, we run runTheMatrix and then parse the cmsDriver command lines.
217  # Not very complicated, but a bit of work.
218 
219  # Collect the workflow number where we detected each sequence here, so we can
220  # put this data into the DB later.
221  sequences = defaultdict(list)
222 
223  if wfnumber:
224  stepdump = subprocess.check_output(["runTheMatrix.py", "-l", str(wfnumber), "-ne"])
225  else:
226  stepdump = subprocess.check_output(["runTheMatrix.py", "-ne"])
227 
228  lines = stepdump.splitlines()
229  workflow = ""
230  workflowre = re.compile(b"^([0-9]+.[0-9]+) ")
231  for line in lines:
232  # if it is a workflow header: save the number.
233  m = workflowre.match(line)
234  if m:
235  workflow = m.group(1).decode()
236  continue
237 
238  # else, we only care about cmsDriver commands.
239  if not b'cmsDriver.py' in line: continue
240 
241  args = list(reversed(line.decode().split(" ")))
242  step = ""
243  scenario = ""
244  era = ""
245  mc = False
246  data = False
247  fast = False
248  while args:
249  item = args.pop()
250  if item == '-s':
251  step = args.pop()
252  if item == '--scenario':
253  scenario = args.pop()
254  if item == '--era':
255  era = args.pop()
256  if item == '--data':
257  data = True
258  if item == '--mc':
259  mc = True
260  if item == '--fast':
261  fast = True
262  steps = step.split(",")
263  for step in steps:
264  s = step.split(":")[0]
265  if s in RELEVANTSTEPS:
266  # Special case for the default sequence, which is noted as "STEP", not "STEP:".
267  if ":" in step:
268  seqs = step.split(":")[1]
269  for seq in seqs.split("+"):
270  sequences[workflow].append(Sequence(seq, s, era, scenario, mc, data, fast))
271  else:
272  sequences[workflow].append(Sequence("", s, era, scenario, mc, data, fast))
273  return sequences
274 
275 def processseqs(seqs):
276  # launch one map_async per element to get finer grain tasks
277  tasks = [stp.map_async(lambda seq: (seq, inspectsequence(seq)), [seq]) for seq in seqs]
278 
279  # then watch te progress and write to DB as results become available.
280  # That way all the DB access is single-threaded but in parallel with the analysis.
281  while tasks:
282  time.sleep(1)
283  running = []
284  done = []
285  for t in tasks:
286  if t.ready():
287  done.append(t)
288  else:
289  running.append(t)
290  for t in done:
291  if not t.successful():
292  print("Task failed.")
293  for it in t.get(): # should only be one
294  seq, res = it
295  storesequenceinfo(seq, *res)
296  tasks = running
297 
298 
299 # A small HTML UI built around http.server. No dependencies!
300 def serve():
301  import traceback
302  import http.server
303 
304  db = sqlite3.connect(DBFILE)
305 
306  def formatseq(seq):
307  return (seq.step + ":" + seq.seqname + " " + seq.era + " " + seq.scenario
308  + (" --mc" if seq.mc else "") + (" --data" if seq.data else "")
309  + (" --fast" if seq.fast else ""))
310 
311  def index():
312  out = []
313  cur = db.cursor()
314  out.append("<H2>Sequences</H2><ul>")
315  out.append("""<p> A sequence name, given as <em>STEP:@sequencename</em> here, does not uniquely identify a sequence.
316  The modules on the sequence might depend on other cmsDriver options, such as Era, Scenario, Data vs. MC, etc.
317  This tool lists parameter combinations that were observed. However, sequences with identical contents are grouped
318  on this page. The default sequence, used when no explicit sequence is apssed to cmsDriver, is noted as <em>STEP:</em>.</p>""")
319  rows = cur.execute(f"SELECT seqname, step, count(*) FROM sequence GROUP BY seqname, step ORDER BY seqname, step;")
320  for row in rows:
321  seqname, step, count = row
322  out.append(f' <li>')
323  out += showseq(step, seqname)
324  out.append(f' </li>')
325  out.append("</ul>")
326 
327  out.append("<H2>Modules</H2><ul>")
328  rows = cur.execute(f"SELECT classname, edmfamily, edmbase FROM plugin ORDER BY edmfamily, edmbase, classname")
329  for row in rows:
330  classname, edmfamily, edmbase = row
331  if not edmfamily: edmfamily = "<em>legacy</em>"
332  out.append(f' <li>{edmfamily}::{edmbase} <a href="/plugin/{classname}/">{classname}</a></li>')
333  out.append("</ul>")
334  return out
335 
336  def showseq(step, seqname):
337  # display set of sequences sharing a name, also used on the index page.
338  out = []
339  cur = db.cursor()
340  out.append(f' <a href="/seq/{step}:{seqname}/">{step}:{seqname}</a>')
341  # this is much more complicated than it should be since we don't keep
342  # track which sequences have equal contents in the DB. So the deduplication
343  # has to happen in Python code.
344  rows = cur.execute(f"SELECT {SEQFIELDS}, moduleid, id FROM sequence INNER JOIN sequencemodule ON sequenceid = id WHERE seqname = ? and step = ?;", (seqname, step))
345 
346  seqs = defaultdict(list)
347  ids = dict()
348  for row in rows:
349  seq = Sequence(*row[:-2])
350  seqs[seq].append(row[-2])
351  ids[seq] = row[-1]
352 
353  variations = defaultdict(list)
354  for seq, mods in seqs.items():
355  variations[tuple(sorted(mods))].append(seq)
356 
357  out.append(" <ul>")
358  for mods, seqs in variations.items():
359  count = len(mods)
360  out.append(f' <li>({count} modules):')
361  for seq in seqs:
362  seqid = ids[seq]
363  out.append(f'<br><a href="/seqid/{seqid}">' + formatseq(seq) + '</a>')
364  # This query in a loop is rather slow, but this got complictated enough, so YOLO.
365  rows = cur.execute("SELECT wfid FROM workflow WHERE sequenceid = ?;", (seqid,))
366  out.append(f'<em>Used on workflows: ' + ", ".join(wfid for wfid, in rows) + "</em>")
367  out.append(' </li>')
368  out.append(" </ul>")
369  return out
370 
371  def showseqid(seqid):
372  # display a single, unique sequence.
373  seqid = int(seqid)
374  out = []
375  cur = db.cursor()
376  rows = cur.execute(f"SELECT {SEQFIELDS} FROM sequence WHERE id = ?;", (seqid,))
377  seq = formatseq(Sequence(*list(rows)[0]))
378  out.append(f"<h2>Modules on {seq}:</h2><ul>")
379  rows = cur.execute("SELECT wfid FROM workflow WHERE sequenceid = ?;", (seqid,))
380  out.append("<p><em>Used on workflows: " + ", ".join(wfid for wfid, in rows) + "</em></p>")
381  rows = cur.execute("""
382  SELECT classname, instancename, variation, moduleid
383  FROM sequencemodule INNER JOIN module ON moduleid = module.id
384  WHERE sequenceid = ?;""", (seqid,))
385  for row in rows:
386  classname, instancename, variation, moduleid = row
387  out.append(f'<li>{instancename} ' + (f'<sub>{variation}</sub>' if variation else '') + f' : <a href="/plugin/{classname}/">{classname}</a></li>')
388  out.append("</ul>")
389 
390  return out
391 
392  def showclass(classname):
393  # display all known instances of a class and where they are used.
394  # this suffers a bit from the fact that fully identifying a sequence is
395  # rather hard, we just show step/name here.
396  out = []
397  out.append(f"<h2>Plugin {classname}</h2>")
398  cur = db.cursor()
399  # First, info about the class iself.
400  rows = cur.execute("SELECT edmfamily, edmbase FROM plugin WHERE classname = ?;", (classname,))
401  edmfamily, edmbase = list(rows)[0]
402  islegcay = not edmfamily
403  if islegcay: edmfamily = "<em>legacy</em>"
404  out.append(f"<p>{classname} is a <b>{edmfamily}::{edmbase}</b>.</p>")
405  out.append("""<p>A module with a given label can have different configuration depending on options such as Era,
406  Scenario, Data vs. MC etc. If multiple configurations for the same name were found, they are listed separately
407  here and denoted using subscripts.</p>""")
408  if (edmbase != "EDProducer" and not (islegcay and edmbase == "EDAnalyzer")) or (islegcay and edmbase == "EDProducer"):
409  out.append(f"<p>This is not a DQM module.</p>")
410 
411  # then, its instances.
412  rows = cur.execute("""
413  SELECT module.id, instancename, variation, sequenceid, step, seqname
414  FROM module INNER JOIN sequencemodule ON moduleid = module.id INNER JOIN sequence ON sequence.id == sequenceid
415  WHERE classname = ? ORDER BY instancename, variation, step, seqname;""", (classname,))
416  out.append("<ul>")
417  seqsformod = defaultdict(list)
418  liformod = dict()
419  for row in rows:
420  id, instancename, variation, sequenceid, step, seqname = row
421  liformod[id] = f'<a href="/config/{id}">{instancename}' + (f"<sub>{variation}</sub>" if variation else '') + "</a>"
422  seqsformod[id].append((sequenceid, f"{step}:{seqname}"))
423  for id, li in liformod.items():
424  out.append("<li>" + li + ' Used here: ' + ", ".join(f'<a href="/seqid/{seqid}">{name}</a>' for seqid, name in seqsformod[id]) + '.</li>')
425  out.append("</ul>")
426  return out
427 
428  def showconfig(modid):
429  # finally, just dump the config of a specific module. Useful to do "diff" on it.
430  modid = int(modid)
431  out = []
432  cur = db.cursor()
433  rows = cur.execute(f"SELECT config FROM module WHERE id = ?;", (modid,))
434  config = list(rows)[0][0]
435  out.append("<pre>")
436  out.append(config.decode())
437  out.append("</pre>")
438  return out
439 
440  ROUTES = [
441  (re.compile('/$'), index),
442  (re.compile('/seq/(\w+):([@\w]*)/$'), showseq),
443  (re.compile('/seqid/(\d+)$'), showseqid),
444  (re.compile('/config/(\d+)$'), showconfig),
445  (re.compile('/plugin/(.*)/$'), showclass),
446  ]
447 
448  # the server boilerplate.
449  class Handler(http.server.SimpleHTTPRequestHandler):
450  def do_GET(self):
451  try:
452  res = None
453  for pattern, func in ROUTES:
454  m = pattern.match(self.path)
455  if m:
456  res = "\n".join(func(*m.groups())).encode("utf8")
457  break
458 
459  if res:
460  self.send_response(200, "Here you go")
461  self.send_header("Content-Type", "text/html; charset=utf-8")
462  self.end_headers()
463  self.wfile.write(b"""<html><style>
464  body {
465  font-family: sans;
466  }
467  </style><body>""")
468  self.wfile.write(res)
469  self.wfile.write(b"</body></html>")
470  else:
471  self.send_response(400, "Something went wrong")
472  self.send_header("Content-Type", "text/plain; charset=utf-8")
473  self.end_headers()
474  self.wfile.write(b"I don't understand this request.")
475  except:
476  trace = traceback.format_exc()
477  self.send_response(500, "Things went very wrong")
478  self.send_header("Content-Type", "text/plain; charset=utf-8")
479  self.end_headers()
480  self.wfile.write(trace.encode("utf8"))
481 
482  server_address = ('', 8000)
483  httpd = http.server.HTTPServer(server_address, Handler)
484  print("Serving at http://localhost:8000/ ...")
485  httpd.serve_forever()
486 
487 
488 if __name__ == "__main__":
489 
490  import argparse
491  parser = argparse.ArgumentParser(description='Collect information about DQM sequences.')
492  parser.add_argument("--sequence", default="", help="Name of the sequence")
493  parser.add_argument("--step", default="DQM", help="cmsDriver step that the sequence applies to")
494  parser.add_argument("--era", default="Run2_2018", help="CMSSW Era to use")
495  parser.add_argument("--scenario", default="pp", help="cmsDriver scenario")
496  parser.add_argument("--data", default=False, action="store_true", help="Pass --data to cmsDriver.")
497  parser.add_argument("--mc", default=False, action="store_true", help="Pass --mc to cmsDriver.")
498  parser.add_argument("--fast", default=False, action="store_true", help="Pass --fast to cmsDriver.")
499  parser.add_argument("--workflow", default=None, help="Ignore other options and inspect this workflow instead (implies --sqlite).")
500  parser.add_argument("--runTheMatrix", default=False, action="store_true", help="Ignore other options and inspect the full matrix instea (implies --sqlite).")
501  parser.add_argument("--steps", default="ALCA,ALCAPRODUCER,ALCAHARVEST,DQM,HARVESTING,VALIDATION", help="Which workflow steps to inspect from runTheMatrix.")
502  parser.add_argument("--sqlite", default=False, action="store_true", help="Write information to SQLite DB instead of stdout.")
503  parser.add_argument("--dbfile", default="sequences.db", help="Name of the DB file to use.")
504  parser.add_argument("--threads", default=None, type=int, help="Use a fixed number of threads (default is #cores).")
505  parser.add_argument("--limit", default=None, type=int, help="Process only this many sequences.")
506  parser.add_argument("--offset", default=None, type=int, help="Process sequences starting from this index. Used with --limit to divide the work into jobs.")
507  parser.add_argument("--showpluginlabel", default=False, action="store_true", help="Print the module label for each plugin (default).")
508  parser.add_argument("--showplugintype", default=False, action="store_true", help="Print the base class for each plugin.")
509  parser.add_argument("--showpluginclass", default=False, action="store_true", help="Print the class name for each plugin.")
510  parser.add_argument("--showpluginconfig", default=False, action="store_true", help="Print the config dump for each plugin.")
511  parser.add_argument("--serve", default=False, action="store_true", help="Ignore other options and instead serve HTML UI from SQLite DB.")
512 
513  args = parser.parse_args()
514 
515  RELEVANTSTEPS += args.steps.split(",")
516  DBFILE = args.dbfile
517 
518  if args.threads:
519  tp = ThreadPool(args.threads)
520  stp = ThreadPool(args.threads)
521 
522  if args.serve:
523  serve()
524  elif args.workflow or args.runTheMatrix:
525  # the default workflow None is a magic value for inspectworkflows.
526  seqs = inspectworkflows(args.workflow)
527  seqset = set(sum(seqs.values(), []))
528  if args.offset:
529  seqset = list(sorted(seqset))[args.offset:]
530  if args.limit:
531  seqset = list(sorted(seqset))[:args.limit]
532 
533  print("Analyzing %d seqs..." % len(seqset))
534 
535  processseqs(seqset)
536  storeworkflows(seqs)
537  else:
538  # single sequence with arguments from commandline...
539  seq = Sequence(args.sequence, args.step, args.era, args.scenario, args.mc, args.data, args.fast)
540  modconfig, modclass, plugininfo = inspectsequence(seq)
541  if args.sqlite:
542  storesequenceinfo(seq, modconfig, modclass, plugininfo)
543  else:
544  # ... and output to stdout.
545  if not (args.showpluginlabel or args.showpluginclass or args.showplugintype or args.showpluginconfig):
546  args.showpluginlabel = True
547  formatsequenceinfo(modconfig, modclass, plugininfo, args.showpluginlabel, args.showpluginclass, args.showplugintype, args.showpluginconfig)
cmsswSequenceInfo.int
int
Definition: cmsswSequenceInfo.py:504
cmsswSequenceInfo.formatsequenceinfo
def formatsequenceinfo(modconfig, modclass, plugininfo, showlabel, showclass, showtype, showconfig)
Definition: cmsswSequenceInfo.py:142
cmsswSequenceInfo.processseqs
def processseqs(seqs)
Definition: cmsswSequenceInfo.py:275
join
static std::string join(char **cmd)
Definition: RemoteFile.cc:17
cmsswSequenceInfo.serve
def serve()
Definition: cmsswSequenceInfo.py:300
cmsswSequenceInfo.getplugininfo
def getplugininfo(pluginname)
Definition: cmsswSequenceInfo.py:130
submitPVValidationJobs.split
def split(sequence, size)
Definition: submitPVValidationJobs.py:352
str
#define str(s)
Definition: TestProcessor.cc:52
print
void print(TMatrixD &m, const char *label=nullptr, bool mathematicaFormat=false)
Definition: Utilities.cc:46
Exception
mps_setup.append
append
Definition: mps_setup.py:85
cmsswSequenceInfo.inspectworkflows
def inspectworkflows(wfnumber)
Definition: cmsswSequenceInfo.py:215
TrackCollections2monitor_cff.func
func
Definition: TrackCollections2monitor_cff.py:359
writeEcalDQMStatus.write
write
Definition: writeEcalDQMStatus.py:48
edm::decode
bool decode(bool &, std::string const &)
Definition: types.cc:72
cmsswSequenceInfo.storeworkflows
def storeworkflows(seqs)
Definition: cmsswSequenceInfo.py:206
alcaDQMUpload.encode
def encode(args, files)
Definition: alcaDQMUpload.py:32
AlignmentPI::index
index
Definition: AlignmentPayloadInspectorHelper.h:46
cmsswSequenceInfo.storesequenceinfo
def storesequenceinfo(seq, modconfig, modclass, plugininfo)
Definition: cmsswSequenceInfo.py:176
cmsswSequenceInfo.inspectsequence
def inspectsequence(seq)
Definition: cmsswSequenceInfo.py:34
cmsswSequenceInfo.Sequence
Sequence
Definition: cmsswSequenceInfo.py:14