Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make Process.prune() to prune also Tasks, and add --prune option to edmConfigDump #28173

Merged
merged 4 commits into from Oct 19, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
89 changes: 76 additions & 13 deletions FWCore/ParameterSet/python/Config.py
Expand Up @@ -1057,7 +1057,7 @@ def prune(self,verbose=False,keepUnresolvedSequencePlaceholders=False):
""" Remove clutter from the process that we think is unnecessary:
tracked PSets, VPSets and unused modules and sequences. If a Schedule has been set, then Paths and EndPaths
not in the schedule will also be removed, along with an modules and sequences used only by
those removed Paths and EndPaths."""
those removed Paths and EndPaths. The keepUnresolvedSequencePlaceholders keeps also unresolved TaskPlaceholders."""
# need to update this to only prune psets not on refToPSets
# but for now, remove the delattr
# for name in self.psets_():
Expand All @@ -1069,6 +1069,8 @@ def prune(self,verbose=False,keepUnresolvedSequencePlaceholders=False):
self.resolve(keepUnresolvedSequencePlaceholders)
usedModules = set()
unneededPaths = set()
tasks = list()
tv = TaskVisitor(tasks)
if self.schedule_():
usedModules=set(self.schedule_().moduleNames())
#get rid of unused paths
Expand All @@ -1078,6 +1080,10 @@ def prune(self,verbose=False,keepUnresolvedSequencePlaceholders=False):
unneededPaths = names - schedNames
for n in unneededPaths:
delattr(self,n)
for t in self.schedule_().tasks():
tv.enter(t)
t.visit(tv)
tv.leave(t)
else:
pths = list(six.itervalues(self.paths))
pths.extend(six.itervalues(self.endpaths))
Expand All @@ -1087,23 +1093,30 @@ def prune(self,verbose=False,keepUnresolvedSequencePlaceholders=False):
unneededModules.update(self._pruneModules(self.switchProducers_(), usedModules))
unneededModules.update(self._pruneModules(self.filters_(), usedModules))
unneededModules.update(self._pruneModules(self.analyzers_(), usedModules))
#remove sequences that do not appear in remaining paths and endpaths
#remove sequences and tasks that do not appear in remaining paths and endpaths
seqs = list()
sv = SequenceVisitor(seqs)
for p in six.itervalues(self.paths):
p.visit(sv)
p.visit(tv)
for p in six.itervalues(self.endpaths):
p.visit(sv)
keepSeqSet = set(( s for s in seqs if s.hasLabel_()))
availableSeqs = set(six.itervalues(self.sequences))
unneededSeqs = availableSeqs-keepSeqSet
unneededSeqLabels = []
for s in unneededSeqs:
unneededSeqLabels.append(s.label_())
delattr(self,s.label_())
p.visit(tv)
def removeUnneeded(seqOrTasks, allSequencesOrTasks):
_keepSet = set(( s for s in seqOrTasks if s.hasLabel_()))
_availableSet = set(six.itervalues(allSequencesOrTasks))
_unneededSet = _availableSet-_keepSet
_unneededLabels = []
for s in _unneededSet:
_unneededLabels.append(s.label_())
delattr(self,s.label_())
return _unneededLabels
unneededSeqLabels = removeUnneeded(seqs, self.sequences)
unneededTaskLabels = removeUnneeded(tasks, self.tasks)
if verbose:
print("prune removed the following:")
print(" modules:"+",".join(unneededModules))
print(" tasks:"+",".join(unneededTaskLabels))
print(" sequences:"+",".join(unneededSeqLabels))
print(" paths/endpaths:"+",".join(unneededPaths))
def _pruneModules(self, d, scheduledNames):
Expand Down Expand Up @@ -2779,8 +2792,14 @@ def testPrune(self):
p.b = EDAnalyzer("YourAnalyzer")
p.c = EDAnalyzer("OurAnalyzer")
p.d = EDAnalyzer("OurAnalyzer")
p.e = EDProducer("MyProducer")
p.f = EDProducer("YourProducer")
p.g = EDProducer("TheirProducer")
p.s = Sequence(p.d)
p.path1 = Path(p.a)
p.t1 = Task(p.e)
p.t2 = Task(p.f)
p.t3 = Task(p.g, p.t1)
p.path1 = Path(p.a, p.t3)
p.path2 = Path(p.b)
self.assert_(p.schedule is None)
pths = p.paths
Expand All @@ -2796,7 +2815,13 @@ def testPrune(self):
self.assert_(hasattr(p, 'b'))
self.assert_(not hasattr(p, 'c'))
self.assert_(not hasattr(p, 'd'))
self.assert_(hasattr(p, 'e'))
self.assert_(not hasattr(p, 'f'))
self.assert_(hasattr(p, 'g'))
self.assert_(not hasattr(p, 's'))
self.assert_(hasattr(p, 't1'))
self.assert_(not hasattr(p, 't2'))
self.assert_(hasattr(p, 't3'))
self.assert_(hasattr(p, 'path1'))
self.assert_(hasattr(p, 'path2'))
# self.assert_(not hasattr(p, 'pset1'))
Expand All @@ -2810,14 +2835,23 @@ def testPrune(self):
p.c = EDAnalyzer("OurAnalyzer")
p.d = EDAnalyzer("OurAnalyzer")
p.e = EDAnalyzer("OurAnalyzer")
p.s = Sequence(p.d)
p.s2 = Sequence(p.b)
p.f = EDProducer("MyProducer")
p.g = EDProducer("YourProducer")
p.h = EDProducer("TheirProducer")
p.i = EDProducer("OurProducer")
p.t1 = Task(p.f)
p.t2 = Task(p.g)
p.t3 = Task(p.h)
p.t4 = Task(p.i)
p.s = Sequence(p.d, p.t1)
p.s2 = Sequence(p.b, p.t2)
p.s3 = Sequence(p.e)
p.path1 = Path(p.a)
p.path1 = Path(p.a, p.t3)
p.path2 = Path(p.b)
p.path3 = Path(p.b+p.s2)
p.path4 = Path(p.b+p.s3)
p.schedule = Schedule(p.path1,p.path2,p.path3)
p.schedule.associate(p.t4)
pths = p.paths
keys = pths.keys()
self.assertEqual(pths[keys[0]],p.path1)
Expand All @@ -2828,6 +2862,14 @@ def testPrune(self):
self.assert_(not hasattr(p, 'c'))
self.assert_(not hasattr(p, 'd'))
self.assert_(not hasattr(p, 'e'))
self.assert_(not hasattr(p, 'f'))
self.assert_(hasattr(p, 'g'))
self.assert_(hasattr(p, 'h'))
self.assert_(hasattr(p, 'i'))
self.assert_(not hasattr(p, 't1'))
self.assert_(hasattr(p, 't2'))
self.assert_(hasattr(p, 't3'))
self.assert_(hasattr(p, 't4'))
self.assert_(not hasattr(p, 's'))
self.assert_(hasattr(p, 's2'))
self.assert_(not hasattr(p, 's3'))
Expand Down Expand Up @@ -2856,6 +2898,27 @@ def testPrune(self):
self.assert_(hasattr(p, 's'))
self.assert_(hasattr(p, 'pth'))
self.assertEqual(p.s.dumpPython(),'cms.Sequence(cms.SequencePlaceholder("a")+process.b)\n')
#test TaskPlaceholder
p = Process("test")
p.a = EDProducer("MyProducer")
p.b = EDProducer("YourProducer")
p.s = Task(TaskPlaceholder("a"),p.b)
p.pth = Path(p.s)
p.prune()
self.assert_(hasattr(p, 'a'))
self.assert_(hasattr(p, 'b'))
self.assert_(hasattr(p, 's'))
self.assert_(hasattr(p, 'pth'))
#test unresolved SequencePlaceholder
p = Process("test")
p.b = EDProducer("YourAnalyzer")
p.s = Task(TaskPlaceholder("a"),p.b)
p.pth = Path(p.s)
p.prune(keepUnresolvedSequencePlaceholders=True)
self.assert_(hasattr(p, 'b'))
self.assert_(hasattr(p, 's'))
self.assert_(hasattr(p, 'pth'))
self.assertEqual(p.s.dumpPython(),'cms.Task(cms.TaskPlaceholder("a"), process.b)\n')
def testTaskPlaceholder(self):
p = Process("test")
p.a = EDProducer("ma")
Expand Down
3 changes: 3 additions & 0 deletions FWCore/ParameterSet/python/SequenceTypes.py
Expand Up @@ -665,6 +665,9 @@ def contains(self, mod):
if visitor.result():
return True
return visitor.result()
def tasks(self):
"""Returns the list of Tasks (that may contain other Tasks) that are associated directly to the Schedule."""
return self._tasks
def dumpPython(self, options=PrintOptions()):
pathNames = ['process.'+p.label_() for p in self]
if pathNames:
Expand Down
29 changes: 16 additions & 13 deletions FWCore/ParameterSet/scripts/edmConfigDump
@@ -1,26 +1,29 @@
#! /usr/bin/env python

from optparse import OptionParser
from __future__ import print_function
import sys
import os
import imp
import argparse

# make the behaviour of 'cmsRun file.py' and 'edmConfigDump file.py' more consistent
sys.path.append(os.getcwd())

parser = OptionParser()
parser.usage = "%prog <file> : expand this python configuration"
parser = argparse.ArgumentParser(description="Expand python configuration")
parser.add_argument("filename",
help="Python configuration file")
parser.add_argument("--prune", action="store_true",
help="Prune the configuration before printing it")
parser.add_argument("--pruneVerbose", action="store_true",
help="With --prune, be verbose on what is pruned")

(options,args) = parser.parse_args()

if len(args)!=1:
parser.print_help()
sys.exit(1)

filename = args[0]
handle = open(filename, 'r')
cfo = imp.load_source("pycfg", filename, handle)
options = parser.parse_args()
handle = open(options.filename, 'r')
cfo = imp.load_source("pycfg", options.filename, handle)
cmsProcess = cfo.process
handle.close()

print cmsProcess.dumpPython()
if options.prune:
cmsProcess.prune(options.pruneVerbose)

print(cmsProcess.dumpPython())