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
72// This is to make sure that if a device has sporadic / timer inputs
73// it gets sorted after one which does not, in case there is no other
74// dependencies between the two.
76{
77 auto checkSporadic = [](InputSpec const& input) {
78 return input.lifetime == Lifetime::Sporadic;
79 };
80 bool isBWithSporadicInput = std::find_if(b.inputs.begin(), b.inputs.end(), checkSporadic) != b.inputs.end();
81 bool isAWithSporadicInput = std::find_if(a.inputs.begin(), a.inputs.end(), checkSporadic) != a.inputs.end();
82 // If neither has sporadic inputs, we return false and sort as usual
83 if (!isAWithSporadicInput && !isBWithSporadicInput) {
84 return false;
85 }
86 // If both have sporadic inputs, we return false and sort as usual.
87 if (isAWithSporadicInput && isBWithSporadicInput) {
88 return false;
89 }
90 // If a has sporadic inputs
91 if (isAWithSporadicInput && isBWithSporadicInput) {
92 return false;
93 }
94
95 // We have a with sporadic inputs. We sort it later, unless there was already some actual
96 // dependency between A and B.
97 if (isAWithSporadicInput) {
98 bool hasDependency = dataDeps(b, a);
99 return !hasDependency;
100 }
101
102 // b is has sporadic inputs and a does not. We are fine as it is.
103 return false;
104}
105
107{
108 O2_SIGNPOST_ID_GENERATE(sid, topology);
109 O2_SIGNPOST_START(topology, sid, "expendableDataDeps", "Checking if %s depends on %s", a.name.c_str(), b.name.c_str());
110 if (a.name.find("internal-dpl-injected-dummy-sink") != std::string::npos &&
111 b.name.find("internal-dpl-injected-dummy-sink") != std::string::npos) {
112 O2_SIGNPOST_END(topology, sid, "expendableDataDeps", "false. Dummy sink never depends on itself.");
113 return false;
114 }
115 // We never put anything behind the dummy sink.
116 if (b.name.find("internal-dpl-injected-dummy-sink") != std::string::npos) {
117 O2_SIGNPOST_END(topology, sid, "expendableDataDeps", "false. %s is dummy sink and it nothing can depend on it.", b.name.c_str());
118 return false;
119 }
120 if (a.name.find("internal-dpl-injected-dummy-sink") != std::string::npos) {
121 O2_SIGNPOST_END(topology, sid, "expendableDataDeps", "true. %s is dummy sink and it nothing can depend on it.", a.name.c_str());
122 return true;
123 }
125 if (dataDeps(a, b)) {
126 O2_SIGNPOST_END(topology, sid, "expendableDataDeps", "true. %s has a data dependency on %s", a.name.c_str(), b.name.c_str());
127 return true;
128 }
129 // If we are here we do not have any data dependency,
130 // however we still consider a dependent on b if
131 // a has the "expendable" label and b does not.
132 auto checkExpendable = [](DataProcessorLabel const& label) {
133 if (label.value == "expendable") {
134 return true;
135 }
136 return false;
137 };
138 // A task marked as expendable or resilient can be put after an expendable task
139 auto checkResilient = [](DataProcessorLabel const& label) {
140 if (label.value == "resilient") {
141 return true;
142 }
143 return false;
144 };
145
146 bool isBExpendable = std::find_if(b.labels.begin(), b.labels.end(), checkExpendable) != b.labels.end();
147 bool isAExpendable = std::find_if(a.labels.begin(), a.labels.end(), checkExpendable) != a.labels.end();
148 bool bResilient = std::find_if(b.labels.begin(), b.labels.end(), checkResilient) != b.labels.end();
149
150 // If none is expendable. We simply return false and sort as usual.
151 if (!isAExpendable && !isBExpendable) {
152 bool sporadic = sporadicDataDeps(a, b);
153 if (sporadic) {
154 O2_SIGNPOST_END(topology, sid, "expendableDataDeps", "false. Neither %s nor %s are expendable. However the former has sporadic inputs so we sort it after.",
155 a.name.c_str(), b.name.c_str());
156 return true;
157 }
158 O2_SIGNPOST_END(topology, sid, "expendableDataDeps", "false. Neither %s nor %s are expendable. No dependency beyond data deps.",
159 a.name.c_str(), b.name.c_str());
160 return false;
161 }
162 // If both are expendable. We return false and sort as usual.
163 if (isAExpendable && isBExpendable) {
164 bool sporadic = sporadicDataDeps(a, b);
165 if (sporadic) {
166 O2_SIGNPOST_END(topology, sid, "expendableDataDeps", "false. Both %s and %s are expendable. However the former has sporadic inputs, so we sort it after.",
167 a.name.c_str(), b.name.c_str());
168 return true;
169 }
170 O2_SIGNPOST_END(topology, sid, "expendableDataDeps", "false. Both %s and %s are expendable. No dependency.",
171 a.name.c_str(), b.name.c_str());
172 return false;
173 }
174
175 // If a is expendable but b is resilient, we can keep the same order.
176 if (isAExpendable && bResilient) {
177 bool sporadic = sporadicDataDeps(a, b);
178 if (sporadic) {
179 O2_SIGNPOST_END(topology, sid, "expendableDataDeps", "false. %s is expendable but %s is resilient, however the former also has sporadic inputs, so we sort it after.",
180 a.name.c_str(), b.name.c_str());
181 return true;
182 }
183 O2_SIGNPOST_END(topology, sid, "expendableDataDeps", "false. %s is expendable but %s is resilient. No need to do do anything.",
184 a.name.c_str(), b.name.c_str());
185 return false;
186 }
187 // If a is expendable we consider it as if there was a dependency from a to b,
188 // however we still need to check if there is not one already from b to a.
189 if (isAExpendable) {
190 bool hasDependency = dataDeps(b, a);
191 O2_SIGNPOST_END(topology, sid, "expendableDataDeps", "%s is expendable. %s from %s to %s => %s.",
192 a.name.c_str(), hasDependency ? "There is however an inverse dependency" : "No inverse dependency", b.name.c_str(), a.name.c_str(),
193 !hasDependency ? "true" : "false");
194 if (!hasDependency) {
195 O2_SIGNPOST_END(topology, sid, "expendableDataDeps", "%s is expendable. There is however an inverse dependecy from %s to %s => true.",
196 a.name.c_str(), b.name.c_str(), a.name.c_str());
197 return true;
198 }
199 bool sporadic = sporadicDataDeps(a, b);
200 if (sporadic) {
201 O2_SIGNPOST_END(topology, sid, "expendableDataDeps", "%s is expendable. No inverse dependency from %s to %s. However the former has an occasioanl input => true.",
202 a.name.c_str(), b.name.c_str(), a.name.c_str());
203 }
204 O2_SIGNPOST_END(topology, sid, "expendableDataDeps", "%s is expendable. No inverse dependency from %s to %s => false.",
205 a.name.c_str(), b.name.c_str(), a.name.c_str());
206 return false;
207 }
208 // b is expendable and a is not. We are fine with no dependency.
209 bool sporadic = sporadicDataDeps(a, b);
210 if (sporadic) {
211 O2_SIGNPOST_END(topology, sid, "expendableDataDeps", "false. %s is expendable but %s is not. However the former has an sporadic input => true.",
212 b.name.c_str(), a.name.c_str());
213 return true;
214 }
215 // b is expendable and a is not. We are fine with no dependency.
216 O2_SIGNPOST_END(topology, sid, "expendableDataDeps", "false. %s is expendable but %s is not. No need to add an unneeded dependency.",
217 b.name.c_str(), a.name.c_str());
218
219 return false;
220};
221
228
230{
231 return [](DataProcessorSpec const& dependent, DataProcessorSpec const& ancestor) {
232 O2_SIGNPOST_ID_GENERATE(sid, topology);
233 O2_SIGNPOST_START(topology, sid, "alwaysDependent", "Checking if %s depends on %s", dependent.name.c_str(), ancestor.name.c_str());
234 if (dependent.name == ancestor.name) {
235 O2_SIGNPOST_END(topology, sid, "alwaysDependent", "false. %s and %s are the same.", dependent.name.c_str(), ancestor.name.c_str());
236 return false;
237 }
238 if (ancestor.name.find("internal-dpl-injected-dummy-sink") != std::string::npos) {
239 O2_SIGNPOST_END(topology, sid, "alwaysDependent", "false. Nothing can depend on %s by policy.", ancestor.name.c_str());
240 return false;
241 }
242 // We never put anything behind the dummy sink.
243 if (dependent.name.find("internal-dpl-injected-dummy-sink") != std::string::npos) {
244 O2_SIGNPOST_END(topology, sid, "alwaysDependent", "true. %s is always last.", ancestor.name.c_str());
245 return true;
246 }
247 const std::regex matcher(".*output-proxy.*");
248 // Check if regex applies
249 std::cmatch m;
250 bool isAncestorOutputProxy = std::regex_match(ancestor.name.data(), m, matcher);
251 // For now dependent is always an output proxy.
252 assert(std::regex_match(dependent.name.data(), m, matcher));
253 bool isAncestorExpendable = std::find_if(ancestor.labels.begin(), ancestor.labels.end(), [](DataProcessorLabel const& label) {
254 return label.value == "expendable";
255 }) != ancestor.labels.end();
256
257 bool isDependentResilient = std::find_if(dependent.labels.begin(), dependent.labels.end(), [](DataProcessorLabel const& label) {
258 return label.value == "resilient";
259 }) != dependent.labels.end();
260 bool isAncestorResilient = std::find_if(ancestor.labels.begin(), ancestor.labels.end(), [](DataProcessorLabel const& label) {
261 return label.value == "resilient";
262 }) != ancestor.labels.end();
263
264 if (!isDependentResilient && isAncestorExpendable) {
265 O2_SIGNPOST_END(topology, sid, "alwaysDependent", "false. Ancestor %s is expendable while %s is non-resilient output proxy (dependent).",
266 ancestor.name.c_str(), dependent.name.c_str());
267 return false;
268 }
269
270 if (isAncestorOutputProxy || (!isDependentResilient && isAncestorResilient)) {
271 bool hasDependency = dataDeps(dependent, ancestor);
272 O2_SIGNPOST_END(topology, sid, "alwaysDependent", "%s. Dependent %s %s a dependency on ancestor %s.",
273 hasDependency ? "true" : "false", dependent.name.c_str(), hasDependency ? "has" : "has not", ancestor.name.c_str());
274 return hasDependency;
275 }
276 O2_SIGNPOST_END(topology, sid, "alwaysDependent", "true by default. Ancestor %s is not an output proxy.", ancestor.name.c_str());
277 return true;
278 };
279}
280
287
288} // namespace o2::framework
#define O2_DECLARE_DYNAMIC_LOG(name)
Definition Signpost.h:483
#define O2_SIGNPOST_END(log, id, name, format,...)
Definition Signpost.h:591
#define O2_SIGNPOST_ID_GENERATE(name, log)
Definition Signpost.h:500
#define O2_SIGNPOST_START(log, id, name, format,...)
Definition Signpost.h:585
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 sporadicDataDeps(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