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