Project
Loading...
Searching...
No Matches
TopologyPolicy.cxx
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
13#include "Framework/Signpost.h"
14#include <string>
15#include <regex>
16
18
19namespace o2::framework
20{
21
29
31{
32 return [](DataProcessorSpec const& spec) {
33 return true;
34 };
35}
36
38{
39 return [name](DataProcessorSpec const& spec) {
40 return spec.name == name;
41 };
42}
43
45{
46 return [re](DataProcessorSpec const& spec) -> bool {
47 const std::regex matcher(re);
48 // Check if regex applies
49 std::cmatch m;
50 return std::regex_match(spec.name.data(), m, matcher);
51 };
52}
53
57{
58 for (size_t ii = 0; ii < a.inputs.size(); ++ii) {
59 for (size_t oi = 0; oi < b.outputs.size(); ++oi) {
60 try {
61 if (DataSpecUtils::match(a.inputs[ii], b.outputs[oi])) {
62 return true;
63 }
64 } catch (...) {
65 continue;
66 }
67 }
68 }
69 return false;
70}
71
73{
74 O2_SIGNPOST_ID_GENERATE(sid, topology);
75 O2_SIGNPOST_START(topology, sid, "expendableDataDeps", "Checking if %s depends on %s", a.name.c_str(), b.name.c_str());
76 if (a.name.find("internal-dpl-injected-dummy-sink") != std::string::npos &&
77 b.name.find("internal-dpl-injected-dummy-sink") != std::string::npos) {
78 O2_SIGNPOST_END(topology, sid, "expendableDataDeps", "false. Dummy sink never depends on itself.");
79 return false;
80 }
81 // We never put anything behind the dummy sink.
82 if (b.name.find("internal-dpl-injected-dummy-sink") != std::string::npos) {
83 O2_SIGNPOST_END(topology, sid, "expendableDataDeps", "false. %s is dummy sink and it nothing can depend on it.", b.name.c_str());
84 return false;
85 }
86 if (a.name.find("internal-dpl-injected-dummy-sink") != std::string::npos) {
87 O2_SIGNPOST_END(topology, sid, "expendableDataDeps", "true. %s is dummy sink and it nothing can depend on it.", a.name.c_str());
88 return true;
89 }
91 if (dataDeps(a, b)) {
92 O2_SIGNPOST_END(topology, sid, "expendableDataDeps", "true. %s has a data dependency on %s", a.name.c_str(), b.name.c_str());
93 return true;
94 }
95 // If we are here we do not have any data dependency,
96 // however we strill consider a dependent on b if
97 // a has the "expendable" label and b does not.
98 auto checkExpendable = [](DataProcessorLabel const& label) {
99 if (label.value == "expendable") {
100 return true;
101 }
102 return false;
103 };
104 // A task marked as expendable or resilient can be put after an expendable task
105 auto checkResilient = [](DataProcessorLabel const& label) {
106 if (label.value == "resilient") {
107 return true;
108 }
109 return false;
110 };
111 bool isBExpendable = std::find_if(b.labels.begin(), b.labels.end(), checkExpendable) != b.labels.end();
112 bool isAExpendable = std::find_if(a.labels.begin(), a.labels.end(), checkExpendable) != a.labels.end();
113 bool bResilient = std::find_if(b.labels.begin(), b.labels.end(), checkResilient) != b.labels.end();
114
115 // If none is expendable. We simply return false and sort as usual.
116 if (!isAExpendable && !isBExpendable) {
117 O2_SIGNPOST_END(topology, sid, "expendableDataDeps", "false. Neither %s nor %s are expendable. No dependency beyond data deps.",
118 a.name.c_str(), b.name.c_str());
119 return false;
120 }
121 // If both are expendable. We return false and sort as usual.
122 if (isAExpendable && isBExpendable) {
123 O2_SIGNPOST_END(topology, sid, "expendableDataDeps", "false. Both %s and %s are expendable. No dependency.",
124 a.name.c_str(), b.name.c_str());
125 return false;
126 }
127
128 // If b is expendable but b is resilient, we can keep the same order.
129 if (isAExpendable && bResilient) {
130 O2_SIGNPOST_END(topology, sid, "expendableDataDeps", "false. %s is expendable but %s is resilient, no need to add an unneeded dependency",
131 a.name.c_str(), b.name.c_str());
132 return false;
133 }
134 // If a is expendable we consider it as if there was a dependency from a to b,
135 // however we still need to check if there is not one already from b to a.
136 if (isAExpendable) {
137 bool hasDependency = dataDeps(b, a);
138 O2_SIGNPOST_END(topology, sid, "expendableDataDeps", "%s is expendable. %s from %s to %s => %s.",
139 a.name.c_str(), hasDependency ? "There is however an inverse dependency" : "No inverse dependency", b.name.c_str(), a.name.c_str(),
140 !hasDependency ? "true" : "false");
141 return !hasDependency;
142 }
143 // b is expendable and a is not. We are fine with no dependency.
144 O2_SIGNPOST_END(topology, sid, "expendableDataDeps", "false. %s is expendable but %s is not. No need to add an unneeded dependency.",
145 b.name.c_str(), a.name.c_str());
146 return false;
147};
148
155
157{
158 return [](DataProcessorSpec const& dependent, DataProcessorSpec const& ancestor) {
159 O2_SIGNPOST_ID_GENERATE(sid, topology);
160 O2_SIGNPOST_START(topology, sid, "alwaysDependent", "Checking if %s depends on %s", dependent.name.c_str(), ancestor.name.c_str());
161 if (dependent.name == ancestor.name) {
162 O2_SIGNPOST_END(topology, sid, "alwaysDependent", "false. %s and %s are the same.", dependent.name.c_str(), ancestor.name.c_str());
163 return false;
164 }
165 if (ancestor.name.find("internal-dpl-injected-dummy-sink") != std::string::npos) {
166 O2_SIGNPOST_END(topology, sid, "alwaysDependent", "false. Nothing can depend on %s by policy.", ancestor.name.c_str());
167 return false;
168 }
169 // We never put anything behind the dummy sink.
170 if (dependent.name.find("internal-dpl-injected-dummy-sink") != std::string::npos) {
171 O2_SIGNPOST_END(topology, sid, "alwaysDependent", "true. %s is always last.", ancestor.name.c_str());
172 return true;
173 }
174 const std::regex matcher(".*output-proxy.*");
175 // Check if regex applies
176 std::cmatch m;
177 bool isAncestorOutputProxy = std::regex_match(ancestor.name.data(), m, matcher);
178 // For now dependent is always an output proxy.
179 assert(std::regex_match(dependent.name.data(), m, matcher));
180 bool isAncestorExpendable = std::find_if(ancestor.labels.begin(), ancestor.labels.end(), [](DataProcessorLabel const& label) {
181 return label.value == "expendable";
182 }) != ancestor.labels.end();
183
184 bool isDependentResilient = std::find_if(dependent.labels.begin(), dependent.labels.end(), [](DataProcessorLabel const& label) {
185 return label.value == "resilient";
186 }) != dependent.labels.end();
187 bool isAncestorResilient = std::find_if(ancestor.labels.begin(), ancestor.labels.end(), [](DataProcessorLabel const& label) {
188 return label.value == "resilient";
189 }) != ancestor.labels.end();
190
191 if (!isDependentResilient && isAncestorExpendable) {
192 O2_SIGNPOST_END(topology, sid, "alwaysDependent", "false. Ancestor %s is expendable while %s is non-resilient output proxy (dependent).",
193 ancestor.name.c_str(), dependent.name.c_str());
194 return false;
195 }
196
197 if (isAncestorOutputProxy || (!isDependentResilient && isAncestorResilient)) {
198 bool hasDependency = dataDeps(dependent, ancestor);
199 O2_SIGNPOST_END(topology, sid, "alwaysDependent", "%s. Dependent %s %s a dependency on ancestor %s.",
200 hasDependency ? "true" : "false", dependent.name.c_str(), hasDependency ? "has" : "has not", ancestor.name.c_str());
201 return hasDependency;
202 }
203 O2_SIGNPOST_END(topology, sid, "alwaysDependent", "true by default. Ancestor %s is not an output proxy.", ancestor.name.c_str());
204 return true;
205 };
206}
207
214
215} // namespace o2::framework
#define O2_DECLARE_DYNAMIC_LOG(name)
Definition Signpost.h:473
#define O2_SIGNPOST_END(log, id, name, format,...)
Definition Signpost.h:540
#define O2_SIGNPOST_ID_GENERATE(name, log)
Definition Signpost.h:490
#define O2_SIGNPOST_START(log, id, name, format,...)
Definition Signpost.h:534
const GLfloat * m
Definition glcorearb.h:4066
GLuint const GLchar * name
Definition glcorearb.h:781
GLboolean GLboolean GLboolean b
Definition glcorearb.h:1233
GLuint GLsizei const GLchar * label
Definition glcorearb.h:2519
GLboolean GLboolean GLboolean GLboolean a
Definition glcorearb.h:1233
Defining PrimaryVertex explicitly as messageable.
Definition TFIDInfo.h:20
bool expendableDataDeps(DataProcessorSpec const &a, DataProcessorSpec const &b)
bool dataDeps(DataProcessorSpec const &a, DataProcessorSpec const &b)
A label that can be associated to a DataProcessorSpec.
std::vector< DataProcessorLabel > labels
static bool match(InputSpec const &spec, ConcreteDataMatcher const &target)
static TopologyPolicy::DependencyChecker dataDependency()
static TopologyPolicy::DataProcessorMatcher matchByRegex(std::string const &re)
static TopologyPolicy::DataProcessorMatcher matchAll()
static TopologyPolicy::DependencyChecker alwaysDependent()
static TopologyPolicy::DataProcessorMatcher matchByName(std::string const &name)
static std::vector< TopologyPolicy > createDefaultPolicies()
std::function< bool(DataProcessorSpec const &dependent, DataProcessorSpec const &ascendant)> DependencyChecker
std::function< bool(DataProcessorSpec const &device)> DataProcessorMatcher