Hedgehog  3.1.0
A library to generate hybrid pipeline workflow systems
Loading...
Searching...
No Matches
any_groupable_abstraction.h
Go to the documentation of this file.
1// NIST-developed software is provided by NIST as a public service. You may use, copy and distribute copies of the
2// software in any medium, provided that you keep intact this entire notice. You may improve, modify and create
3// derivative works of the software or any portion of the software, and you may copy and distribute such modifications
4// or works. Modified works should carry a notice stating that you changed the software and should note the date and
5// nature of any such change. Please explicitly acknowledge the National Institute of Standards and Technology as the
6// source of the software. NIST-developed software is expressly provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND,
7// EXPRESS, IMPLIED, IN FACT OR ARISING BY OPERATION OF LAW, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF
8// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT AND DATA ACCURACY. NIST NEITHER REPRESENTS NOR
9// WARRANTS THAT THE OPERATION OF THE SOFTWARE WILL BE UNINTERRUPTED OR ERROR-FREE, OR THAT ANY DEFECTS WILL BE
10// CORRECTED. NIST DOES NOT WARRANT OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF THE SOFTWARE OR THE RESULTS
11// THEREOF, INCLUDING BUT NOT LIMITED TO THE CORRECTNESS, ACCURACY, RELIABILITY, OR USEFULNESS OF THE SOFTWARE. You
12// are solely responsible for determining the appropriateness of using and distributing the software and you assume
13// all risks associated with its use, including but not limited to the risks and costs of program errors, compliance
14// with applicable laws, damage to or loss of data, programs or equipment, and the unavailability or interruption of
15// operation. This software is not intended to be used in any situation where a failure could cause risk of injury or
16// damage to property. The software developed by NIST employees is not subject to copyright protection within the
17// United States.
18
19
20
21#ifndef HEDGEHOG_ANY_COPYABLE_ABSTRACTION_H
22#define HEDGEHOG_ANY_COPYABLE_ABSTRACTION_H
23
24#include <cstddef>
25#include <numeric>
26#include <cmath>
27#include <algorithm>
28
30
32namespace hh {
34namespace core {
36namespace abstraction {
37
40 private:
41 size_t const numberThreads_ = 0;
43 std::shared_ptr<std::set<AnyGroupableAbstraction *>> group_ = nullptr;
44
45 public:
48 explicit AnyGroupableAbstraction(size_t const numberThreads) :
51 group_(std::make_shared<std::set<AnyGroupableAbstraction *>>()) {
52 group_->insert(this);
53 }
54
56 virtual ~AnyGroupableAbstraction() = default;
57
60 [[nodiscard]] size_t numberThreads() const { return numberThreads_; }
61
64 [[nodiscard]] bool isInGroup() const { return numberThreads_ != 1; }
65
68 [[nodiscard]] std::string nodeId() const {
69 if (auto thisAsNode = dynamic_cast<NodeAbstraction const *>(this)) {
70 return thisAsNode->id();
71 } else {
72 throw std::runtime_error("A group representative should be a NodeAbstraction.");
73 };
74 }
75
78 [[nodiscard]] std::shared_ptr<std::set<AnyGroupableAbstraction *>> const &group() const {
79 return group_;
80 }
81
84 [[nodiscard]] std::shared_ptr<std::set<NodeAbstraction *>> groupAsNodes() const {
85 auto ret = std::make_shared<std::set<NodeAbstraction *>>();
86 for (auto copyable : *group_) {
87 if (auto node = dynamic_cast<NodeAbstraction *>(copyable)) { ret->insert(node); }
88 }
89 return ret;
90 }
91
95
99 [[nodiscard]] std::string groupRepresentativeId() const {
100 if (auto representativeAsNode = dynamic_cast<NodeAbstraction const *>(groupRepresentative_)) {
101 return representativeAsNode->id();
102 } else {
103 throw std::runtime_error("A group representative should be a NodeAbstraction.");
104 };
105 }
106
110
113 void group(std::shared_ptr<std::set<AnyGroupableAbstraction *>> const &group) { group_ = group; }
114
118 [[nodiscard]] size_t numberActiveThreadInGroup() const {
119 size_t count = 0;
120 if (dynamic_cast<TaskNodeAbstraction const *>(this)) {
121 count = (size_t) std::count_if(
122 this->group_->cbegin(), this->group_->cend(),
123 [](auto nodeInGroup) {
124 if (auto taskGroup = dynamic_cast<TaskNodeAbstraction const *>(nodeInGroup)) {
125 return taskGroup->isActive();
126 } else {
127 throw std::runtime_error("All the nodes in a group should be of the same type: the representative is a "
128 "TaskNodeAbstraction, but not the nodes in its group.");
129 }
130 }
131 );
132 };
133
134 return count;
135 }
136
140 [[nodiscard]] std::pair<std::chrono::nanoseconds, std::chrono::nanoseconds> minmaxWaitDurationGroup() const {
141 std::pair<std::chrono::nanoseconds, std::chrono::nanoseconds> minMax =
142 {std::chrono::nanoseconds::zero(), std::chrono::nanoseconds::zero()};
143
144 if (dynamic_cast<TaskNodeAbstraction const *>(this)) {
145 auto minMaxElem = std::minmax_element(
146 this->group_->cbegin(), this->group_->cend(),
147 [](auto lhs, auto rhs) {
148 auto lhsAsTask = dynamic_cast<TaskNodeAbstraction const *>(lhs);
149 auto rhsAsTask = dynamic_cast<TaskNodeAbstraction const *>(rhs);
150 if (lhsAsTask && rhsAsTask) {
151 return lhsAsTask->waitDuration() < rhsAsTask->waitDuration();
152 } else {
153 throw std::runtime_error("All the nodes in a group should be of the same type, the representative is of"
154 " type TaskNodeAbstraction but not the nodes in its group.");
155 }
156 }
157 );
158
159 auto minTask = dynamic_cast<TaskNodeAbstraction *>(*minMaxElem.first);
160 auto maxTask = dynamic_cast<TaskNodeAbstraction *>(*minMaxElem.second);
161 if (minTask && maxTask) {
162 minMax = {minTask->waitDuration(), maxTask->waitDuration()};
163 } else {
164 throw std::runtime_error("All the nodes in a group should be of the same type, the representative is of"
165 " type TaskNodeAbstraction but not the nodes in its group.");
166 }
167 }
168
169 return minMax;
170 }
171
175 [[nodiscard]] std::pair<std::chrono::nanoseconds, std::chrono::nanoseconds> meanSDWaitDurationGroup() const {
176 std::pair<std::chrono::nanoseconds, std::chrono::nanoseconds> meanSD =
177 {std::chrono::nanoseconds::zero(), std::chrono::nanoseconds::zero()};
178 if (dynamic_cast<TaskNodeAbstraction const *>(this)) {
179 std::chrono::nanoseconds
180 sum = std::chrono::nanoseconds::zero(),
181 mean = std::chrono::nanoseconds::zero();
182 double
183 sd = 0;
184
185 for (auto taskInGroup : *this->group_) {
186 auto task = dynamic_cast<TaskNodeAbstraction *>(taskInGroup);
187 if (task) {
188 sum += task->waitDuration();
189 } else {
190 throw std::runtime_error("All nodes in a group should be of the same type, the representative derives from "
191 "TaskNodeAbstraction but not the group members.");
192 }
193 }
194 mean = sum / (this->group_->size());
195
196 for (auto taskInGroup : *this->group_) {
197 auto task = dynamic_cast<TaskNodeAbstraction *>(taskInGroup);
198 if (task) {
199 auto diff = (double) (task->waitDuration().count() - mean.count());
200 sd += diff * diff;
201 } else {
202 throw std::runtime_error("All nodes in a group should be of the same type, the representative derives from "
203 "TaskNodeAbstraction but not the group members.");
204 }
205 }
206 meanSD = {
207 mean,
208 std::chrono::nanoseconds((int64_t) std::sqrt(sd / (double) this->group_->size()))};
209 }
210 return meanSD;
211 }
212
215 [[nodiscard]] std::pair<std::chrono::nanoseconds, std::chrono::nanoseconds> minmaxExecutionDurationGroup() const {
216 auto groupAsNode = this->groupAsNodes();
217 auto minMaxElem = std::minmax_element(
218 groupAsNode->cbegin(), groupAsNode->cend(),
219 [](auto lhs, auto rhs) {
220 return lhs->executionDuration() < rhs->executionDuration();
221 }
222 );
223 return {(*minMaxElem.first)->executionDuration(),
224 (*minMaxElem.second)->executionDuration()};
225 }
226
229 [[nodiscard]] std::pair<std::chrono::nanoseconds, std::chrono::nanoseconds> meanSDExecutionDurationGroup() const {
230 auto groupAsNode = groupAsNodes();
231 std::pair<std::chrono::nanoseconds, std::chrono::nanoseconds> meanSD =
232 {std::chrono::nanoseconds::zero(), std::chrono::nanoseconds::zero()};
233
234 std::chrono::nanoseconds
235 sum = std::chrono::nanoseconds::zero(),
236 mean = std::chrono::nanoseconds::zero();
237 double
238 sd = 0;
239
240 for (auto taskInGroup : *groupAsNode) {
241 sum += taskInGroup->executionDuration();
242 }
243 mean = sum / (groupAsNode->size());
244
245 for (auto taskInGroup : *groupAsNode) {
246 sd += (double) (taskInGroup->executionDuration().count() - mean.count()) *
247 (double) (taskInGroup->executionDuration().count() - mean.count());
248 }
249
250 meanSD = {mean, std::chrono::nanoseconds((int64_t) std::sqrt(sd / (double) groupAsNode->size()))};
251
252 return meanSD;
253 }
254
258 [[nodiscard]] std::pair<std::chrono::nanoseconds, std::chrono::nanoseconds> minmaxExecTimePerElementGroup() const {
259 std::pair<std::chrono::nanoseconds, std::chrono::nanoseconds> minMax =
260 {std::chrono::nanoseconds::zero(), std::chrono::nanoseconds::zero()};
261
262 if (dynamic_cast<TaskNodeAbstraction const *>(this)) {
263 auto minMaxElem = std::minmax_element(
264 this->group_->cbegin(), this->group_->cend(),
265 [](auto lhs, auto rhs) {
266 auto lhsAsTask = dynamic_cast<TaskNodeAbstraction const *>(lhs);
267 auto rhsAsTask = dynamic_cast<TaskNodeAbstraction const *>(rhs);
268 if (lhsAsTask && rhsAsTask) {
269 return lhsAsTask->perElementExecutionDuration() < rhsAsTask->perElementExecutionDuration();
270 } else {
271 throw std::runtime_error("All the nodes in a group should be of the same type, the representative is of"
272 " type TaskNodeAbstraction but not the group members.");
273 }
274 }
275 );
276
277 auto minTask = dynamic_cast<TaskNodeAbstraction *>(*minMaxElem.first);
278 auto maxTask = dynamic_cast<TaskNodeAbstraction *>(*minMaxElem.second);
279 if (minTask && maxTask) {
280 minMax = {minTask->perElementExecutionDuration(), maxTask->perElementExecutionDuration()};
281 } else {
282 throw std::runtime_error("All the nodes in a group should be of the same type, the representative is of"
283 " type TaskNodeAbstraction but not the group members.");
284 }
285 }
286 return minMax;
287 }
288
292 [[nodiscard]] std::pair<std::chrono::nanoseconds, std::chrono::nanoseconds> meanSDExecTimePerElementGroup() const {
293 std::pair<std::chrono::nanoseconds, std::chrono::nanoseconds> meanSD =
294 {std::chrono::nanoseconds::zero(), std::chrono::nanoseconds::zero()};
295 if (dynamic_cast<TaskNodeAbstraction const *>(this)) {
296 std::chrono::nanoseconds
297 sum = std::chrono::nanoseconds::zero(),
298 mean = std::chrono::nanoseconds::zero();
299 double
300 sd = 0;
301
302 for (auto taskInGroup : *this->group_) {
303 auto task = dynamic_cast<TaskNodeAbstraction *>(taskInGroup);
304 if (task) {
305 sum += task->perElementExecutionDuration();
306 } else {
307 throw std::runtime_error("All the nodes in a group should be of the same type, the representative is of"
308 " type TaskNodeAbstraction but not the group members.");
309 }
310 }
311 mean = sum / (this->group_->size());
312
313 for (auto taskInGroup : *this->group_) {
314 auto task = dynamic_cast<TaskNodeAbstraction *>(taskInGroup);
315 if (task) {
316 auto diff = (double) (task->perElementExecutionDuration().count() - mean.count());
317 sd += diff * diff;
318 } else {
319 throw std::runtime_error("All the nodes in a group should be of the same type, the representative is of"
320 " type TaskNodeAbstraction but not the group members.");
321 }
322 }
323 meanSD = {mean, std::chrono::nanoseconds((int64_t) std::sqrt(sd / (double) this->group_->size()))};
324 }
325 return meanSD;
326 }
327
331 [[nodiscard]] std::pair<std::chrono::nanoseconds, std::chrono::nanoseconds> minmaxMemoryWaitTimeGroup() const {
332 std::pair<std::chrono::nanoseconds, std::chrono::nanoseconds> minMax =
333 {std::chrono::nanoseconds::zero(), std::chrono::nanoseconds::zero()};
334 if (dynamic_cast<TaskNodeAbstraction const *>(this)) {
335 auto minMaxElem = std::minmax_element(
336 this->group_->cbegin(), this->group_->cend(),
337 [](auto lhs, auto rhs) {
338 auto lhsAsTask = dynamic_cast<TaskNodeAbstraction const *>(lhs);
339 auto rhsAsTask = dynamic_cast<TaskNodeAbstraction const *>(rhs);
340 if (lhsAsTask && rhsAsTask) {
341 return lhsAsTask->memoryWaitDuration() < rhsAsTask->memoryWaitDuration();
342 } else {
343 throw std::runtime_error("All the nodes in a group should be of the same type, the representative is of"
344 " type TaskNodeAbstraction but not the nodes in the group.");
345 }
346 }
347 );
348 auto minTask = dynamic_cast<TaskNodeAbstraction *>(*minMaxElem.first);
349 auto maxTask = dynamic_cast<TaskNodeAbstraction *>(*minMaxElem.second);
350 if (minTask && maxTask) {
351 minMax = {minTask->memoryWaitDuration(), maxTask->memoryWaitDuration()};
352 } else {
353 throw std::runtime_error("All the nodes in a group should be of the same type, the representative is of"
354 " type TaskNodeAbstraction but not the nodes in the group.");
355 }
356 }
357 return minMax;
358 }
359
363 [[nodiscard]] std::pair<std::chrono::nanoseconds, std::chrono::nanoseconds> meanSDMemoryWaitTimePerElementGroup() const {
364 std::pair<std::chrono::nanoseconds, std::chrono::nanoseconds> meanSD =
365 {std::chrono::nanoseconds::zero(), std::chrono::nanoseconds::zero()};
366 if (dynamic_cast<TaskNodeAbstraction const *>(this)) {
367 std::chrono::nanoseconds
368 sum = std::chrono::nanoseconds::zero(),
369 mean = std::chrono::nanoseconds::zero();
370 double
371 sd = 0;
372
373 for (auto taskInGroup : *this->group_) {
374 auto task = dynamic_cast<TaskNodeAbstraction *>(taskInGroup);
375 if (task) {
376 sum += task->memoryWaitDuration();
377 } else {
378 throw std::runtime_error("All the nodes in a group should be of the same type, the representative is of"
379 " type TaskNodeAbstraction but not the group members.");
380 }
381 }
382 mean = sum / (this->group_->size());
383
384 for (auto taskInGroup : *this->group_) {
385 auto task = dynamic_cast<TaskNodeAbstraction *>(taskInGroup);
386 if (task) {
387 auto diff = (double) (task->memoryWaitDuration().count() - mean.count());
388 sd += diff * diff;
389 } else {
390 throw std::runtime_error("All the nodes in a group should be of the same type, the representative is of"
391 " type TaskNodeAbstraction but not the group members.");
392 }
393 }
394 meanSD = {mean, std::chrono::nanoseconds((int64_t) std::sqrt(sd / (double) this->group_->size()))};
395 }
396 return meanSD;
397 }
398
402 [[nodiscard]] std::pair<size_t, size_t> minmaxNumberElementsReceivedGroup() const {
403 std::pair<size_t, size_t> minMax = {0, 0};
404
405 if (dynamic_cast<TaskNodeAbstraction const *>(this)) {
406 auto minMaxElem = std::minmax_element(
407 this->group_->cbegin(), this->group_->cend(),
408 [](auto lhs, auto rhs) {
409 auto lhsAsTask = dynamic_cast<TaskNodeAbstraction const *>(lhs);
410 auto rhsAsTask = dynamic_cast<TaskNodeAbstraction const *>(rhs);
411 if (lhsAsTask && rhsAsTask) {
412 return lhsAsTask->numberReceivedElements() < rhsAsTask->numberReceivedElements();
413 } else {
414 throw std::runtime_error("All the nodes in a group should be of the same type, the representative is of"
415 " type TaskNodeAbstraction but not the nodes in the group.");
416 }
417 }
418 );
419 auto minTask = dynamic_cast<TaskNodeAbstraction *>(*minMaxElem.first);
420 auto maxTask = dynamic_cast<TaskNodeAbstraction *>(*minMaxElem.second);
421 if (minTask && maxTask) {
422 minMax = {minTask->numberReceivedElements(), maxTask->numberReceivedElements()};
423 } else {
424 throw std::runtime_error("All the nodes in a group should be of the same type, the representative is of"
425 " type TaskNodeAbstraction but not the nodes in the group.");
426 }
427 }
428
429 return minMax;
430 }
431
435 [[nodiscard]] std::pair<double, double> meanSDNumberElementsReceivedGroup() const {
436 std::pair<double, double> meanSD = {0, 0};
437 if (dynamic_cast<TaskNodeAbstraction const *>(this)) {
438 size_t sum = 0;
439 double mean = 0, sd = 0;
440
441 for (auto taskInGroup : *this->group_) {
442 auto task = dynamic_cast<TaskNodeAbstraction *>(taskInGroup);
443 if (task) {
444 sum += task->numberReceivedElements();
445 } else {
446 throw std::runtime_error("All the nodes in a group should be of the same type, the representative is of"
447 " type TaskNodeAbstraction but not the nodes in the group.");
448 }
449 }
450 mean = (double) sum / (double) (this->group_->size());
451
452 for (auto taskInGroup : *this->group_) {
453 auto task = dynamic_cast<TaskNodeAbstraction *>(taskInGroup);
454 if (task) {
455 auto diff = (double) task->numberReceivedElements() - mean;
456 sd += diff * diff;
457 } else {
458 throw std::runtime_error("All the nodes in a group should be of the same type, the representative is of"
459 " type TaskNodeAbstraction but not the nodes in the group.");
460 }
461 }
462
463 meanSD = {mean, std::sqrt(sd / (double) this->group_->size())};
464 }
465 return meanSD;
466 }
467
469 virtual void createGroup(std::map<NodeAbstraction *, std::vector<NodeAbstraction *>> &) = 0;
470};
471}
472}
473}
474#endif //HEDGEHOG_ANY_COPYABLE_ABSTRACTION_H
Hedgehog main namespace.
Abstraction for cores/nodes that can form groups.
std::shared_ptr< std::set< AnyGroupableAbstraction * > > group_
Node's group.
std::pair< std::chrono::nanoseconds, std::chrono::nanoseconds > meanSDMemoryWaitTimePerElementGroup() const
Accessor to the mean / standard deviation wait time duration of the nodes in the group.
void group(std::shared_ptr< std::set< AnyGroupableAbstraction * > > const &group)
Group setter.
std::pair< std::chrono::nanoseconds, std::chrono::nanoseconds > meanSDExecutionDurationGroup() const
Accessor to the mean / standard deviation execution duration of the nodes in the group.
std::pair< double, double > meanSDNumberElementsReceivedGroup() const
Accessor to the mean / standard deviation number of elements received in the group.
std::string groupRepresentativeId() const
Group id representative accessor.
std::shared_ptr< std::set< AnyGroupableAbstraction * > > const & group() const
Group of cores accessor.
virtual void createGroup(std::map< NodeAbstraction *, std::vector< NodeAbstraction * > > &)=0
Create a group to insert in the map.
std::string nodeId() const
Accessor to the node id (redirection to NodeAbstraction::nodeId)
std::pair< std::chrono::nanoseconds, std::chrono::nanoseconds > minmaxWaitDurationGroup() const
Accessor to the min / max wait duration of the nodes in the group.
bool isInGroup() const
Test if a group is needed.
std::pair< std::chrono::nanoseconds, std::chrono::nanoseconds > minmaxMemoryWaitTimeGroup() const
Accessor to the min / max wait time duration of the nodes in the group.
size_t numberActiveThreadInGroup() const
Accessor to the number of nodes alive in the group.
std::pair< std::chrono::nanoseconds, std::chrono::nanoseconds > minmaxExecTimePerElementGroup() const
Accessor to the min / max execution per elements duration of the nodes in the group.
std::pair< std::chrono::nanoseconds, std::chrono::nanoseconds > meanSDWaitDurationGroup() const
Accessor to the mean / standard deviation wait duration of the nodes in the group.
AnyGroupableAbstraction(size_t const numberThreads)
Constructor using the number of threads.
std::shared_ptr< std::set< NodeAbstraction * > > groupAsNodes() const
Create a set of the NodeAbstraction constituting the group.
void groupRepresentative(AnyGroupableAbstraction *groupRepresentative)
Group representative setter.
AnyGroupableAbstraction * groupRepresentative() const
Group representative accessor.
std::pair< size_t, size_t > minmaxNumberElementsReceivedGroup() const
Accessor to the min / max number of elements received in the group.
std::pair< std::chrono::nanoseconds, std::chrono::nanoseconds > meanSDExecTimePerElementGroup() const
Accessor to the mean / standard deviation execution per elements duration of the nodes in the group.
AnyGroupableAbstraction * groupRepresentative_
Group representative.
std::pair< std::chrono::nanoseconds, std::chrono::nanoseconds > minmaxExecutionDurationGroup() const
Accessor to the min / max execution duration of the nodes in the group.
size_t numberThreads() const
Accessor to the number of threads.
virtual ~AnyGroupableAbstraction()=default
Default destructor.
Task core abstraction used to define some method for task-like behaving cores like CoreExecutionPipel...
std::chrono::nanoseconds const & memoryWaitDuration() const
Accessor to the duration the node was in a memory wait state.
std::chrono::nanoseconds perElementExecutionDuration() const
Accessor to the duration the average duration of processing an input data.
std::chrono::nanoseconds const & waitDuration() const
Accessor to the duration the node was in a wait state.
size_t numberReceivedElements() const
Accessor to the number of received elements.