CMS 3D CMS Logo

ProcessCallGraph.cc
Go to the documentation of this file.
1 /*
2  *
3  */
4 
5 #include <cassert>
6 #include <iostream>
7 #include <numeric>
8 #include <string>
9 #include <type_traits>
10 #include <vector>
11 
12 // boost optional (used by boost graph) results in some false positives with -Wmaybe-uninitialized
13 #pragma GCC diagnostic push
14 #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
15 #include <boost/graph/depth_first_search.hpp>
16 #pragma GCC diagnostic pop
17 
32 
34 
35 // adaptor to use range-based for loops with boost::graph edges(...) and vertices(...) functions
36 template <typename I>
37 struct iterator_pair_as_a_range : std::pair<I, I> {
38 public:
39  using std::pair<I, I>::pair;
40 
41  I begin() { return this->first; }
42  I end() { return this->second; }
43 };
44 
45 template <typename I>
48 }
49 
50 // FIXME
51 // - check that the Source has not already been added
53  // keep track of the Source module id
54  source_ = module.id();
55 
56  // create graph vertex for the source module
57  boost::add_vertex(graph_);
58  graph_.m_graph[module.id()] = {module, edm::EDMModuleType::kSource, true};
59 }
60 
61 // FIXME
62 // - check that the Source has already been added
63 // - check that all module ids are valid (e.g. subprocesses are not being added in
64 // the wrong order)
66  edm::ProcessContext const& context) {
67  unsigned int pid = registerProcess(context);
68 
69  // work on the full graph (for the main process) or a subgraph (for a subprocess)
70  GraphType& graph = context.isSubProcess() ? graph_.create_subgraph() : graph_.root();
71 
72  // set the graph name property to the process name
73  boost::get_property(graph, boost::graph_name) = context.processName();
74 
75  // create graph vertices associated to all modules in the process
76  unsigned int size = 0;
77  if (auto const& allModules = pathsAndConsumes.allModules(); not allModules.empty()) {
78  size = std::accumulate(
79  allModules.begin(), allModules.end(), size, [](unsigned int s, edm::ModuleDescription const* module) {
80  return std::max(s, module->id());
81  });
82  }
83  for (size_t i = 0; i < size; ++i)
84  boost::add_vertex(graph);
85 
86  // set the vertices properties (use the module id as the global index into the graph)
87  std::vector<unsigned int> modules;
88  modules.reserve(size);
89  for (edm::ModuleDescription const* module : pathsAndConsumes.allModules()) {
90  modules.push_back(module->id());
91  graph_.m_graph[module->id()] = {*module, edmModuleTypeEnum(*module), false};
92  }
93 
94  // add graph edges associated to module dependencies
95  for (edm::ModuleDescription const* consumer : pathsAndConsumes.allModules()) {
96  for (edm::ModuleDescription const* module : pathsAndConsumes.modulesWhoseProductsAreConsumedBy(consumer->id())) {
97  // module `consumer' depends on module `module'
98  boost::add_edge(consumer->id(), module->id(), graph_);
99  }
100  }
101 
102  // extract path names from the TriggerNamesService
104 
105  // extract the details of the paths and endpaths: name, modules on the path, and their dependencies
106  size = pathsAndConsumes.paths().size();
107  assert(tns.getTrigPaths().size() == size);
108  std::vector<PathType> paths;
109  paths.reserve(size);
110  for (unsigned int i = 0; i < size; ++i) {
111  std::vector<unsigned int> modules;
112  for (edm::ModuleDescription const* module : pathsAndConsumes.modulesOnPath(i)) {
113  modules.push_back(module->id());
114  // mark the modules in the Paths as scheduled
115  graph_.m_graph[module->id()].scheduled_ = true;
116  }
117  auto deps = dependencies(modules);
118  paths.emplace_back(tns.getTrigPath(i), modules, deps.first, deps.second);
119  }
120  size = pathsAndConsumes.endPaths().size();
121  std::vector<PathType> endPaths;
122  endPaths.reserve(size);
123  for (unsigned int i = 0; i < size; ++i) {
124  std::vector<unsigned int> modules;
125  for (edm::ModuleDescription const* module : pathsAndConsumes.modulesOnEndPath(i)) {
126  modules.push_back(module->id());
127  // mark the modules in the EndPaths as scheduled
128  graph_.m_graph[module->id()].scheduled_ = true;
129  }
130  auto deps = dependencies(modules);
131  endPaths.emplace_back(tns.getEndPath(i), modules, deps.first, deps.second);
132  }
133 
134  // store the description of process, modules and paths
135  process_description_.emplace_back(context.processName(), graph, modules, paths, endPaths);
136  assert(process_description_.size() == pid + 1);
137 
138  // attach a subprocess to its parent
139  if (context.isSubProcess()) {
140  unsigned int parent_pid = processId(context.parentProcessContext());
141  process_description_[parent_pid].subprocesses_.push_back(pid);
142  }
143 }
144 
145 // number of modules stored in the call graph
146 unsigned int ProcessCallGraph::size() const { return boost::num_vertices(graph_); }
147 
148 // retrieve the ModuleDescriptio associated to the given id and vertex
149 edm::ModuleDescription const& ProcessCallGraph::source() const { return graph_.m_graph[source_].module_; }
150 
151 // retrieve the ModuleDescription associated to the given id and vertex
153  return graph_.m_graph[module].module_;
154 }
155 
156 // retrieve the full information for a given module
158  return graph_.m_graph[module];
159 }
160 
161 // find the dependencies of the given module
162 std::vector<unsigned int> ProcessCallGraph::depends(unsigned int module) const {
163  std::vector<unsigned int> colors(boost::num_vertices(graph_));
164  auto colormap = boost::make_container_vertex_map(colors);
165 
166  // depht-first visit all vertices starting from the given module
167  boost::default_dfs_visitor visitor;
168  boost::depth_first_visit(graph_, module, visitor, colormap);
169 
170  // count the visited vertices (the `black' ones) in order to properly size the
171  // output vector; then fill the dependencies with the list of visited nodes
172  unsigned int size = 0;
173  for (unsigned int color : colors)
174  if (boost::black_color == color)
175  ++size;
176  std::vector<unsigned int> dependencies(size);
177  unsigned j = 0;
178  for (unsigned int i = 0; i < colors.size(); ++i)
179  if (boost::black_color == colors[i])
180  dependencies[j++] = i;
181  assert(size == j);
182 
183  return dependencies;
184 }
185 
186 // find the dependencies of all modules in the given path
187 //
188 // return two vector:
189 // - the first lists all the dependencies for the whole path
190 // - the second lists the one-after-the-last dependency index into the first vector for each module
191 std::pair<std::vector<unsigned int>, std::vector<unsigned int>> ProcessCallGraph::dependencies(
192  std::vector<unsigned int> const& path) {
193  std::vector<unsigned int> colors(boost::num_vertices(graph_));
194  auto colormap = boost::make_container_vertex_map(colors);
195 
196  // first, find and count all the path's modules' dependencies
197  boost::default_dfs_visitor visitor;
198  for (unsigned int module : path)
199  boost::depth_first_visit(graph_, module, visitor, colormap);
200 
201  unsigned int size = 0;
202  for (unsigned int color : colors)
203  if (color == 0)
204  ++size;
205 
206  // allocate the output vectors
207  std::vector<unsigned int> dependencies(size);
208  dependencies.resize(0);
209  std::vector<unsigned int> indices(path.size());
210  indices.resize(0);
211 
212  // reset the color map
213  for (unsigned int& color : colors)
214  color = 0;
215 
216  // find again all the dependencies, and record those associated to each module
217  struct record_vertices : boost::default_dfs_visitor {
218  record_vertices(std::vector<unsigned int>& vertices) : vertices_(vertices) {}
219 
220  void discover_vertex(unsigned int vertex, GraphType const& graph) { vertices_.push_back(vertex); }
221 
222  std::vector<unsigned int>& vertices_;
223  };
224  record_vertices recorder(dependencies);
225 
226  for (unsigned int module : path) {
227  // skip modules that have already been added as dependencies
228  if (colors[module] != boost::black_color)
229  boost::depth_first_visit(graph_, module, recorder, colormap);
230  indices.push_back(dependencies.size());
231  }
232 
233  return std::make_pair(dependencies, indices);
234 }
235 
236 // register a (sub)process and assigns it a "process id"
237 // if called with a duplicate process name, returns the original process id
239  static unsigned int s_id = 0;
240 
241  // registerProcess (called by preBeginJob) must be called for the parent process before its subprocess(es)
242  if (context.isSubProcess() and process_id_.find(context.parentProcessContext().processName()) == process_id_.end()) {
244  << "ProcessCallGraph::preBeginJob(): called for subprocess \"" << context.processName() << "\""
245  << " before being called for its parent process \"" << context.parentProcessContext().processName() << "\"";
246  }
247 
248  // registerProcess (called by preBeginJob) should be called once or each (sub)process
249  auto id = process_id_.find(context.processName());
250  if (id != process_id_.end()) {
252  << "ProcessCallGraph::preBeginJob(): called twice for the same "
253  << (context.isSubProcess() ? "subprocess" : "process") << " " << context.processName();
254  }
255 
256  std::tie(id, std::ignore) = process_id_.insert(std::make_pair(context.processName(), s_id++));
257  return id->second;
258 }
259 
260 // retrieve the "process id" of a process, given its ProcessContex
261 // throws an exception if the (sub)process was not registered
262 unsigned int ProcessCallGraph::processId(edm::ProcessContext const& context) const {
263  auto id = process_id_.find(context.processName());
264  if (id == process_id_.end())
266  << "ProcessCallGraph::processId(): unexpected " << (context.isSubProcess() ? "subprocess" : "process") << " "
267  << context.processName();
268  return id->second;
269 }
270 
271 // retrieve the "process id" of a process, given its ProcessContex
272 // throws an exception if the (sub)process was not registered
274  auto id = process_id_.find(processName);
275  if (id == process_id_.end())
277  << "ProcessCallGraph::processId(): unexpected (sub)process " << processName;
278  return id->second;
279 }
280 
281 // retrieve the number of processes
282 std::vector<ProcessCallGraph::ProcessType> const& ProcessCallGraph::processes() const { return process_description_; }
283 
284 // retrieve information about a process, given its "process id"
286  return process_description_.at(pid);
287 }
288 
289 // retrieve information about a process, given its ProcessContex
291  unsigned int pid = processId(context);
292  return process_description_[pid];
293 }
294 
295 // retrieve information about a process, given its ProcessContex
297  unsigned int pid = processId(processName);
298  return process_description_[pid];
299 }
edm::ProcessContext::parentProcessContext
ProcessContext const & parentProcessContext() const
Definition: ProcessContext.cc:10
ConfigurationDescriptions.h
make_range
iterator_pair_as_a_range< I > make_range(std::pair< I, I > p)
Definition: ProcessCallGraph.cc:46
bTagCombinedSVVariables_cff.indices
indices
Definition: bTagCombinedSVVariables_cff.py:67
s_id
static const edm::ProductID s_id
Definition: EventBase.cc:27
ProcessCallGraph::NodeType
Definition: ProcessCallGraph.h:29
ProcessCallGraph::ProcessCallGraph
ProcessCallGraph()
ProcessCallGraph::processes
const std::vector< ProcessType > & processes() const
Definition: ProcessCallGraph.cc:282
mps_fire.i
i
Definition: mps_fire.py:355
LogMessageMonitor_cff.modules
modules
Definition: LogMessageMonitor_cff.py:7
MessageLogger.h
colors
vector< Color_t > colors
Definition: trackSplitPlot.h:37
colors
Definition: colors.py:1
edm::ProcessContext::isSubProcess
bool isSubProcess() const
Definition: ProcessContext.h:34
ProcessCallGraph::process_description_
std::vector< ProcessType > process_description_
Definition: ProcessCallGraph.h:181
iterator_pair_as_a_range
Definition: DependencyGraph.cc:181
edm::errors::LogicError
Definition: EDMException.h:37
TriggerNamesService.h
modules
Definition: ZHLTMatchFilter.cc:17
edm::ProcessContext
Definition: ProcessContext.h:27
AlCaHLTBitMon_ParallelJobs.p
p
Definition: AlCaHLTBitMon_ParallelJobs.py:153
cms::cuda::assert
assert(be >=bs)
edm::second
U second(std::pair< T, U > const &p)
Definition: ParameterSet.cc:215
ProcessCallGraph::graph_
GraphType graph_
Definition: ProcessCallGraph.h:172
iterator_pair_as_a_range::end
I end()
Definition: ProcessCallGraph.cc:42
ProcessCallGraph::processDescription
const ProcessType & processDescription(unsigned int) const
Definition: ProcessCallGraph.cc:285
ProcessCallGraph::depends
std::vector< unsigned int > depends(unsigned int module) const
Definition: ProcessCallGraph.cc:162
ProcessCallGraph::GraphType
boost::subgraph< boost::adjacency_list< boost::vecS, boost::vecS, boost::directedS, NodeType, boost::property< boost::edge_index_t, int >, boost::property< boost::graph_name_t, std::string > >> GraphType
Definition: ProcessCallGraph.h:47
dqmdumpme.first
first
Definition: dqmdumpme.py:55
edm::ModuleDescription
Definition: ModuleDescription.h:21
ProcessCallGraph::size
unsigned int size() const
Definition: ProcessCallGraph.cc:146
edm::Exception
Definition: EDMException.h:77
ModuleDescription.h
ActivityRegistry.h
EDMException.h
ProcessCallGraph::ProcessType
Definition: ProcessCallGraph.h:78
edm::EDMModuleType::kSource
alignCSCRings.s
s
Definition: alignCSCRings.py:92
Exhume::I
const std::complex< double > I
Definition: I.h:8
Service.h
ProcessCallGraph::operator[]
const NodeType & operator[](unsigned int module) const
Definition: ProcessCallGraph.cc:157
dependencies
Definition: dependencies.py:1
ProcessCallGraph::source_
unsigned int source_
Definition: ProcessCallGraph.h:175
ProcessCallGraph::dependencies
std::pair< std::vector< unsigned int >, std::vector< unsigned int > > dependencies(std::vector< unsigned int > const &path)
Definition: ProcessCallGraph.cc:191
ParameterSetDescription.h
AlCaHLTBitMon_QueryRunRegistry.string
string
Definition: AlCaHLTBitMon_QueryRunRegistry.py:256
iterator_pair_as_a_range::begin
I begin()
Definition: ProcessCallGraph.cc:41
bphysicsOniaDQM_cfi.vertex
vertex
Definition: bphysicsOniaDQM_cfi.py:7
edm::PathsAndConsumesOfModulesBase::endPaths
std::vector< std::string > const & endPaths() const
Definition: PathsAndConsumesOfModulesBase.h:39
edm::service::TriggerNamesService::getTrigPath
std::string const & getTrigPath(size_type const i) const
Definition: TriggerNamesService.h:56
SiStripPI::max
Definition: SiStripPayloadInspectorHelper.h:169
edm::PathsAndConsumesOfModulesBase::modulesWhoseProductsAreConsumedBy
std::vector< ModuleDescription const * > const & modulesWhoseProductsAreConsumedBy(unsigned int moduleID) const
Definition: PathsAndConsumesOfModulesBase.h:63
edm::Service
Definition: Service.h:30
edm::PathsAndConsumesOfModulesBase::modulesOnPath
std::vector< ModuleDescription const * > const & modulesOnPath(unsigned int pathIndex) const
Definition: PathsAndConsumesOfModulesBase.h:45
edm::ProcessContext::processName
std::string const & processName() const
Definition: ProcessContext.h:31
module
Definition: vlib.h:198
SequenceTypes.ignore
def ignore(seq)
Definition: SequenceTypes.py:630
ProcessCallGraph::registerProcess
unsigned int registerProcess(edm::ProcessContext const &)
Definition: ProcessCallGraph.cc:238
SimL1EmulatorRepack_CalouGT_cff.processName
processName
Definition: SimL1EmulatorRepack_CalouGT_cff.py:17
edm::service::TriggerNamesService
Definition: TriggerNamesService.h:42
Registry.h
ProcessCallGraph::source
const edm::ModuleDescription & source() const
Definition: ProcessCallGraph.cc:149
edm::edmModuleTypeEnum
EDMModuleType edmModuleTypeEnum(edm::ModuleDescription const &module)
Definition: EDMModuleType.cc:10
ProcessCallGraph.h
edm::PathsAndConsumesOfModulesBase::paths
std::vector< std::string > const & paths() const
Definition: PathsAndConsumesOfModulesBase.h:38
edm::service::TriggerNamesService::getTrigPaths
Strings const & getTrigPaths() const
Definition: TriggerNamesService.h:55
edm::service::TriggerNamesService::getEndPath
std::string const & getEndPath(size_type const i) const
Definition: TriggerNamesService.h:75
edm::PathsAndConsumesOfModulesBase
Definition: PathsAndConsumesOfModulesBase.h:34
Exception
Definition: hltDiff.cc:246
Skims_PA_cff.paths
paths
Definition: Skims_PA_cff.py:18
OfflineOutput_cfi.consumer
consumer
Definition: OfflineOutput_cfi.py:3
edm::PathsAndConsumesOfModulesBase::modulesOnEndPath
std::vector< ModuleDescription const * > const & modulesOnEndPath(unsigned int endPathIndex) const
Definition: PathsAndConsumesOfModulesBase.h:49
ProcessCallGraph::process_id_
std::unordered_map< std::string, unsigned int > process_id_
Definition: ProcessCallGraph.h:178
castor_dqm_sourceclient_file_cfg.path
path
Definition: castor_dqm_sourceclient_file_cfg.py:37
ProcessCallGraph::processId
unsigned int processId(edm::ProcessContext const &) const
Definition: ProcessCallGraph.cc:262
ParameterSet.h
edmTracerLogToSimpleConfig.allModules
allModules
Definition: edmTracerLogToSimpleConfig.py:132
dqmiolumiharvest.j
j
Definition: dqmiolumiharvest.py:66
symbols.deps
deps
Definition: symbols.py:55
ProcessCallGraph::module
const edm::ModuleDescription & module(unsigned int module) const
Definition: ProcessCallGraph.cc:152
ProcessContext.h
PathsAndConsumesOfModulesBase.h
ConsumesInfo.h
edm::PathsAndConsumesOfModulesBase::allModules
std::vector< ModuleDescription const * > const & allModules() const
Definition: PathsAndConsumesOfModulesBase.h:41
ProcessCallGraph::preBeginJob
void preBeginJob(edm::PathsAndConsumesOfModulesBase const &, edm::ProcessContext const &)
Definition: ProcessCallGraph.cc:65
pwdgSkimBPark_cfi.vertices
vertices
Definition: pwdgSkimBPark_cfi.py:7
ProcessCallGraph::preSourceConstruction
void preSourceConstruction(edm::ModuleDescription const &)
Definition: ProcessCallGraph.cc:52