Belle II Software  release-05-02-19
DataFlowVisualization.cc
1 /**************************************************************************
2  * BASF2 (Belle Analysis Framework 2) *
3  * Copyright(C) 2013 Belle II Collaboration *
4  * *
5  * Author: The Belle II Collaboration *
6  * Contributors: Christian Pulvermacher *
7  * *
8  * This software is provided "as is" without any warranty. *
9  **************************************************************************/
10 
11 //first to avoid _XOPEN_SOURCE warnings
12 #include <framework/core/Module.h>
13 #include <framework/core/Path.h>
14 #include <framework/core/ModuleManager.h>
15 
16 #include <framework/core/DataFlowVisualization.h>
17 #include <framework/datastore/DataStore.h>
18 
19 #include <fstream>
20 
21 using namespace Belle2;
22 
23 
24 namespace {
25  const std::string unknownfillcolor = "gray82";
26 }
27 
29  m_map(dependencyMap)
30 {
31  m_fillcolor[DependencyMap::c_Input] = "cornflowerblue";
34 
35  m_arrowcolor[DependencyMap::c_Input] = "cornflowerblue";
38 }
39 
40 void DataFlowVisualization::visualizePath(const std::string& filename, const Path& path)
41 {
42  std::ofstream file(filename.c_str());
43  file << "digraph allModules {\n";
44  file << " rankdir=LR;\n"; //left -> right
45  file << " compound=true;\n"; //allow edges to subgraphs
46 
47  //for steering file data flow graph, we may get multiple definitions of each node
48  //graphviz merges these into the last one, so we'll go through module list in reverse (all boxes should be coloured as outputs)
49  const bool steeringFileFlow = true;
50  for (const ModulePtr& mod : path.buildModulePathList())
51  generateModulePlot(file, *mod, steeringFileFlow);
52 
53  plotPath(file, path);
54 
55  //add nodes
56  for (const std::string& name : m_allOutputs) {
57  file << " \"" << name << "\" [shape=box,style=filled,fillcolor=" << m_fillcolor[DependencyMap::c_Output] << "];\n";
58  }
59  for (const std::string& name : m_allInputs) {
60  if (m_allOutputs.count(name) == 0)
61  file << " \"" << name << "\" [shape=box,style=filled,fillcolor=" << m_fillcolor[DependencyMap::c_Input] << "];\n";
62  }
63  for (const std::string& name : m_unknownArrays) {
64  if (m_allOutputs.count(name) == 0 && m_allInputs.count(name) == 0)
65  file << " \"" << name << "\" [shape=box,style=filled,fillcolor=" << unknownfillcolor << "];\n";
66  }
67 
68  file << "}\n\n";
69 
70  B2INFO("Data flow diagram created. You can use 'dot dataflow.dot -Tps -o dataflow.ps' to create a PostScript file from it.");
71 }
72 
73 void DataFlowVisualization::plotPath(std::ofstream& file, const Path& path, const std::string& pathName)
74 {
75  //graph name must begin with cluster for fancy graphics!
76  const std::string graphname = pathName.empty() ? "clusterMain" : ("cluster" + pathName);
77  file << " subgraph \"" << graphname << "\" {\n";
78  if (pathName.empty()) {
79  file << " rank=min;\n";
80  } else {
81  file << " rank=same;\n";
82  }
83  file << " style=solid;\n";
84  file << " color=grey;\n";
85  file << " \"" << graphname << "_inv\" [shape=point,style=invis];\n";
86  std::string lastModule("");
87  //connect modules in right order...
88  for (const ModulePtr& mod : path.getModules()) {
89  const std::string& module = DependencyMap::getModuleID(*mod);
90  file << " \"" << module << "\";\n";
91  if (!lastModule.empty()) {
92  file << " \"" << lastModule << "\" -> \"" << module << "\" [color=black];\n";
93  }
94  if (mod->hasCondition()) {
95  for (const auto& condition : mod->getAllConditions()) {
96  const std::string& conditionName = condition.getString();
97  plotPath(file, *condition.getPath(), conditionName);
98  file << " \"" << module << "\" -> \"cluster" << conditionName << "_inv\" " <<
99  "[color=grey,lhead=\"cluster" << conditionName << "\",label=\"" << conditionName << "\",fontcolor=grey];\n";
100  }
101  }
102 
103  lastModule = module;
104  }
105  file << " }\n";
106 }
107 
108 void DataFlowVisualization::generateModulePlot(std::ofstream& file, const Module& mod, bool steeringFileFlow)
109 {
110  const std::string& name = DependencyMap::getModuleID(mod);
111  const std::string& label = mod.getName();
112  if (!steeringFileFlow)
113  file << "digraph \"" << name << "\" {\n";
114  file << " " << name << " [label=\"" << label << "\"];\n";
115 
116  const auto foundInfoIter = m_map->getModuleInfoMap().find(name);
117  if (foundInfoIter != m_map->getModuleInfoMap().end()) {
118  const DependencyMap::ModuleInfo& moduleInfo = foundInfoIter->second;
119  for (int i = 0; i < DependencyMap::c_NEntryTypes; i++) {
120  const std::set<std::string>& entries = moduleInfo.entries[i];
121  const std::set<std::string>& relations = moduleInfo.relations[i];
122  const std::string fillcolor = m_fillcolor[i];
123  const std::string arrowcolor = m_arrowcolor[i];
124 
125  for (const std::string& dsentry : entries) {
126  if (!steeringFileFlow)
127  file << " \"" << dsentry << "\" [shape=box,style=filled,fillcolor=" << fillcolor << "];\n";
128  if (i == DependencyMap::c_Output) {
129  m_allOutputs.insert(dsentry);
130  file << " \"" << name << "\" -> \"" << dsentry << "\" [color=" << arrowcolor << "];\n";
131  } else {
132  m_allInputs.insert(dsentry);
133  file << " \"" << dsentry << "\" -> \"" << name << "\" [color=" << arrowcolor << "];\n";
134  }
135  }
136 
137  for (const std::string& relname : relations) {
138  size_t pos = relname.rfind("To");
139  if (pos == std::string::npos or pos != relname.find("To")) {
140  B2WARNING("generateModulePlot(): couldn't split relation name!");
141  //Searching for parts in input/output lists might be helpful...
142  continue;
143  }
144 
145  const std::string from = relname.substr(0, pos);
146  const std::string to = relname.substr(pos + 2);
147 
148  //any connected arrays that are neither input nor output?
149  if (checkArrayUnknown(from, moduleInfo)) {
150  if (!steeringFileFlow)
151  file << " \"" << from << "\" [shape=box,style=filled,fillcolor=" << unknownfillcolor << "];\n";
152  }
153  if (checkArrayUnknown(to, moduleInfo)) {
154  if (!steeringFileFlow)
155  file << " \"" << to << "\" [shape=box,style=filled,fillcolor=" << unknownfillcolor << "];\n";
156  }
157 
158  file << " \"" << from << "\" -> \"" << to << "\" [color=" << arrowcolor << ",style=dashed];\n";
159  }
160  }
161  }
162  if (!steeringFileFlow)
163  file << "}\n\n";
164 }
165 
166 
168 {
169  // construct given module and gearbox
170  std::shared_ptr<Module> modulePtr = ModuleManager::Instance().registerModule(module);
171  std::shared_ptr<Module> gearboxPtr = ModuleManager::Instance().registerModule("Gearbox");
172 
173  // call initialize() method
174  //may throw some ERRORs, but that's OK.
175  // TODO:(ignore missing inputs)
176  gearboxPtr->initialize();
178  modulePtr->initialize();
179 
180  // create plot
181  const std::string filename = module + ".dot";
182  DataFlowVisualization v(&DataStore::Instance().getDependencyMap());
183  std::ofstream file(filename.c_str());
184  v.generateModulePlot(file, *modulePtr, false);
185 
186  //clean up to avoid problems with ~TROOT
187  modulePtr->terminate();
188  gearboxPtr->terminate();
189 }
190 
191 bool DataFlowVisualization::checkArrayUnknown(const std::string& name, const DependencyMap::ModuleInfo& info)
192 {
193  for (const auto& entry : info.entries) {
194  if (entry.count(name) != 0)
195  return false; //found
196  }
197 
198  //not found
199  m_unknownArrays.insert(name);
200  return true;
201 }
Belle2::ModuleManager::registerModule
std::shared_ptr< Module > registerModule(const std::string &moduleName, std::string sharedLibPath="") noexcept(false)
Creates an instance of a module and registers it to the ModuleManager.
Definition: ModuleManager.cc:84
Belle2::Module::terminate
virtual void terminate()
This method is called at the end of the event processing.
Definition: Module.h:178
Belle2::DataStore::getDependencyMap
DependencyMap & getDependencyMap()
Return map of depedencies between modules.
Definition: DataStore.h:512
Belle2::ModuleManager::Instance
static ModuleManager & Instance()
Exception is thrown if the requested module could not be created by the ModuleManager.
Definition: ModuleManager.cc:28
Belle2::DataStore::Instance
static DataStore & Instance()
Instance of singleton Store.
Definition: DataStore.cc:54
Belle2::DependencyMap
Collect information about the dependencies between modules.
Definition: DependencyMap.h:22
Belle2::DataFlowVisualization::executeModuleAndCreateIOPlot
static void executeModuleAndCreateIOPlot(const std::string &module)
Create independent I/O graph for a single module (without requiring a steering file).
Definition: DataFlowVisualization.cc:167
Belle2::DataFlowVisualization::visualizePath
void visualizePath(const std::string &filename, const Path &path)
Create graphs with datastore inputs/outputs of each module in path.
Definition: DataFlowVisualization.cc:40
Belle2::DependencyMap::c_Output
@ c_Output
registered output.
Definition: DependencyMap.h:28
Belle2::DataFlowVisualization::m_arrowcolor
std::string m_arrowcolor[DependencyMap::c_NEntryTypes]
arrow colors.
Definition: DataFlowVisualization.h:69
Belle2::DataFlowVisualization::DataFlowVisualization
DataFlowVisualization(const DependencyMap *dependencyMap)
Constructor.
Definition: DataFlowVisualization.cc:28
Belle2::DependencyMap::setModule
void setModule(const Module &mod)
Set the current module (for getCurrentModuleInfo())
Definition: DependencyMap.h:53
Belle2::Module
Base class for Modules.
Definition: Module.h:74
Belle2::DataFlowVisualization::m_map
const DependencyMap * m_map
Stores information on inputs/outputs of each module, as obtained by require()/createEntry();.
Definition: DataFlowVisualization.h:62
Belle2::DataFlowVisualization::m_unknownArrays
std::set< std::string > m_unknownArrays
set of array only being used in relations, for steering file visualisation.
Definition: DataFlowVisualization.h:66
Belle2::DataFlowVisualization::m_fillcolor
std::string m_fillcolor[DependencyMap::c_NEntryTypes]
fill colors.
Definition: DataFlowVisualization.h:68
Belle2::DataFlowVisualization::generateModulePlot
void generateModulePlot(std::ofstream &file, const Module &mod, bool steeringFileFlow=false)
Create I/O graph for a single module (written to file).
Definition: DataFlowVisualization.cc:108
Belle2
Abstract base class for different kinds of events.
Definition: MillepedeAlgorithm.h:19
Belle2::ModulePtr
std::shared_ptr< Module > ModulePtr
Defines a pointer to a module object as a boost shared pointer.
Definition: Module.h:42
Belle2::DependencyMap::c_NEntryTypes
@ c_NEntryTypes
size of this enum.
Definition: DependencyMap.h:30
Belle2::DataFlowVisualization::m_allOutputs
std::set< std::string > m_allOutputs
set of all outputs, for steering file visualisation.
Definition: DataFlowVisualization.h:65
Belle2::DependencyMap::getModuleID
static std::string getModuleID(const Module &mod)
Return unique ID for given module.
Definition: DependencyMap.cc:9
Belle2::Path
Implements a path consisting of Module and/or Path objects.
Definition: Path.h:40
Belle2::DependencyMap::c_Input
@ c_Input
required input.
Definition: DependencyMap.h:26
Belle2::DataFlowVisualization
class to visualize data flow between modules.
Definition: DataFlowVisualization.h:34
Belle2::DataFlowVisualization::checkArrayUnknown
bool checkArrayUnknown(const std::string &name, const DependencyMap::ModuleInfo &info)
If the given array name isn't found in any of info's fields, it is added to m_unknownArrays (and true...
Definition: DataFlowVisualization.cc:191
Belle2::Module::initialize
virtual void initialize()
Initialize the Module.
Definition: Module.h:111
Belle2::DependencyMap::getModuleInfoMap
const std::map< std::string, ModuleInfo > & getModuleInfoMap() const
return information on inputs/outputs of each module, as obtained by requireInput()/optionalInput()/re...
Definition: DependencyMap.h:59
Belle2::DependencyMap::c_OptionalInput
@ c_OptionalInput
optional input.
Definition: DependencyMap.h:27
Belle2::DataFlowVisualization::m_allInputs
std::set< std::string > m_allInputs
set of all inputs (including optionals), for steering file visualisation.
Definition: DataFlowVisualization.h:64
Belle2::DataFlowVisualization::plotPath
static void plotPath(std::ofstream &file, const Path &path, const std::string &pathName="")
Create a subgraph for the given Path (including conditional paths).
Definition: DataFlowVisualization.cc:73
Belle2::DependencyMap::ModuleInfo::relations
std::set< std::string > relations[c_NEntryTypes]
relations between them.
Definition: DependencyMap.h:36
Belle2::DependencyMap::ModuleInfo
Stores information on inputs/outputs of a module, as obtained by requireInput()/optionalInput()/regis...
Definition: DependencyMap.h:34
Belle2::DependencyMap::ModuleInfo::entries
std::set< std::string > entries[c_NEntryTypes]
objects/arrays.
Definition: DependencyMap.h:35