UFO 1.0.0
An Efficient Probabilistic 3D Mapping Framework That Embraces the Unknown
Loading...
Searching...
No Matches
timing.cpp
1// UFO
2#include <ufo/time/timing.hpp>
3
4// STL
5#include <cassert>
6#include <cmath>
7#include <stack>
8
9namespace ufo
10{
11//
12// Public functions
13//
14
15Timing::Timing(std::string const& tag, char const* color) : Timing(nullptr, tag, color) {}
16
17Timing::Timing(char const* tag, char const* color) : Timing(std::string(tag), color) {}
18
19Timing::Timing(std::string const& tag, std::initializer_list<Timing> init)
20 : Timing(tag, std::begin(init), std::end(init))
21{
22}
23
24Timing::Timing(char const* tag, std::initializer_list<Timing> init)
25 : Timing(std::string(tag), init)
26{
27}
28
29Timing::Timing(std::string const& tag, char const* color,
30 std::initializer_list<Timing> init)
31 : Timing(tag, color, std::begin(init), std::end(init))
32{
33}
34
35Timing::Timing(char const* tag, char const* color, std::initializer_list<Timing> init)
36 : Timing(std::string(tag), color, init)
37{
38}
39
40Timing& Timing::start()
41{
42 // TODO: Implement
43
44 // auto start = std::chrono::high_resolution_clock::now();
45
46 // lockParents();
47 // lock_.lock();
48
49 // auto id = std::this_thread::get_id();
50
51 // std::vector<Timer*> timers;
52 // timers.push_back(&threads_[id]);
53 // if (auto it = running_ids_.find(id); std::end(running_ids_) != it) {
54 // assert(!timers[0]->running());
55 // timers[0]->start_ = timer_.start_;
56 // timers[0]->current_ = timer_.current_;
57 // running_ids_.erase(it);
58 // if (running_ids_.empty()) {
59 // timer_.resetCurrent();
60 // }
61 // }
62
63 // updateMaxConcurrent();
64
65 // for (auto p = parent_; nullptr != p; p = p->parent_) {
66 // if (auto it = p->threads_.find(id); std::end(p->threads_) != it) {
67 // timers.push_back(&(it->second));
68 // continue;
69 // } else {
70 // p->running_ids_.insert(id);
71 // if (1 == p->running_ids_.size()) {
72 // timers.push_back(&(p->timer_));
73 // }
74 // p->updateMaxConcurrent();
75 // }
76 // }
77
78 // auto finish = std::chrono::high_resolution_clock::now();
79 // auto elapsed = finish - start;
80
81 // for (auto t : timers) {
82 // if (t->running()) {
83 // t->current_ -= elapsed;
84 // } else {
85 // t->start(finish);
86 // }
87 // }
88
89 // lock_.unlock();
90 // unlockParents();
91
92 return *this;
93}
94
95Timing& Timing::start(std::string const& tag)
96{
97 auto start = std::chrono::high_resolution_clock::now();
98 auto id = std::this_thread::get_id();
99
100 for (auto p = this; nullptr != p; p = p->parent_) {
101 std::lock_guard lock(p->mutex_);
102 auto [it, added] = thread_.try_emplace(id);
103 if (added) {
104 it->second.independent = false;
105 it->second.start = start;
106 it->second.extra_time = std::chrono::high_resolution_clock::duration::zero();
107 }
108 p->updateMaxConcurrent();
109 }
110
111 Timing* parent = this;
112 if (0 < thread_.count(id)) {
113 parent = findDeepest(id);
114 }
115
116 parent->lock_.lock();
117
118 auto& new_timing = parent->children_.try_emplace(tag, tag).first->second;
119 new_timing.lock_.lock();
120 new_timing.parent_ = parent;
121
122 parent->lock_.unlock();
123
124 auto& st = new_timing.thread_[id];
125 new_timing.updateMaxConcurrent();
126 new_timing.lock_.unlock();
127
128 st.independent = true;
129 st.start = start;
130 st.extra_time = std::chrono::high_resolution_clock::now() - start;
131
132 return new_timing;
133}
134
135Timing& Timing::start(std::string const& tag, char const* color)
136{
137 auto& ret = start(tag);
138 ret.color_ = color; // TODO: Should be counted in extra time
139 return ret;
140}
141
142bool Timing::stop()
143{
144 // TODO: Implement correct
145
146 auto time = std::chrono::high_resolution_clock::now();
147 auto id = std::this_thread::get_id();
148
149 lock_.lock();
150 if (0 == thread_.count(id)) {
151 lock_.unlock();
152 return false;
153 }
154
155 Timing* current = findDeepest(id);
156
157 lock_.unlock();
158
159 current->lock_.lock();
160
161 auto& st = current->thread_[id];
162 auto et = st.extra_time;
163 current->timer_.addSample(st.start + et, time);
164 current->thread_.erase(id);
165
166 Timing* parent = current->parent_;
167
168 current->lock_.unlock();
169
170 if (nullptr != parent) {
171 parent->lock_.lock();
172 auto& st = parent->thread_[id];
173 parent->lock_.unlock();
174 time -= st.extra_time + et;
175 st.extra_time = std::chrono::high_resolution_clock::now() - time;
176 }
177
178 return true;
179
180 // auto time = std::chrono::high_resolution_clock::now();
181 // return 1 == stop(time, 1);
182}
183
184std::size_t Timing::stop(std::size_t levels)
185{
186 auto time = std::chrono::high_resolution_clock::now();
187 return stop(time, levels);
188}
189
190void Timing::stopAll()
191{
192 auto time = std::chrono::high_resolution_clock::now();
193 stop(time, std::numeric_limits<std::size_t>::max());
194}
195
196Timing const& Timing::operator[](std::string const& tag) const
197{
198 std::lock_guard lock(mutex_);
199 return children_.at(tag);
200}
201
202Timing& Timing::operator[](std::string const& tag)
203{
204 std::lock_guard lock(mutex_);
205 return children_[tag];
206}
207
208void Timing::extend(Timing const& source)
209{
210 std::lock_guard lock(mutex_);
211 extendImpl(source);
212}
213
214void Timing::extend(Timing&& source)
215{
216 std::lock_guard lock(mutex_);
217 extendImpl(std::move(source));
218}
219
220void Timing::extend(std::initializer_list<Timing> ilist)
221{
222 extend(std::begin(ilist), std::end(ilist));
223}
224
225void Timing::merge(Timing const& source)
226{
227 std::lock_guard lock(mutex_);
228 mergeImpl(source);
229}
230
231void Timing::merge(Timing&& source)
232{
233 std::lock_guard lock(mutex_);
234 mergeImpl(std::move(source));
235}
236
237void Timing::merge(std::initializer_list<Timing> ilist)
238{
239 merge(std::begin(ilist), std::end(ilist));
240}
241
242std::string const& Timing::tag() const { return tag_; }
243
244std::string const& Timing::color() const { return color_; }
245
246void Timing::setColor(std::string const& color) { color_ = color; }
247
248void Timing::printSeconds(bool random_colors, bool bold, bool info,
249 int group_colors_level, int precision) const
250{
251 printSeconds("", random_colors, bold, info, group_colors_level, precision);
252}
253
254void Timing::printSeconds(std::string const& name, bool random_colors, bool bold,
255 bool info, int group_colors_level, int precision) const
256{
257 print<std::chrono::seconds::period>(name, random_colors, bold, info, group_colors_level,
258 precision);
259}
260
261void Timing::printMilliseconds(bool random_colors, bool bold, bool info,
262 int group_colors_level, int precision) const
263{
264 printMilliseconds("", random_colors, bold, info, group_colors_level, precision);
265}
266
267void Timing::printMilliseconds(std::string const& name, bool random_colors, bool bold,
268 bool info, int group_colors_level, int precision) const
269{
270 print<std::chrono::milliseconds::period>(name, random_colors, bold, info,
271 group_colors_level, precision);
272}
273
274void Timing::printMicroseconds(bool random_colors, bool bold, bool info,
275 int group_colors_level, int precision) const
276{
277 printMicroseconds("", random_colors, bold, info, group_colors_level, precision);
278}
279
280void Timing::printMicroseconds(std::string const& name, bool random_colors, bool bold,
281 bool info, int group_colors_level, int precision) const
282{
283 print<std::chrono::microseconds::period>(name, random_colors, bold, info,
284 group_colors_level, precision);
285}
286
287void Timing::printNanoseconds(bool random_colors, bool bold, bool info,
288 int group_colors_level, int precision) const
289{
290 printNanoseconds("", random_colors, bold, info, group_colors_level, precision);
291}
292
293void Timing::printNanoseconds(std::string const& name, bool random_colors, bool bold,
294 bool info, int group_colors_level, int precision) const
295{
296 print<std::chrono::nanoseconds::period>(name, random_colors, bold, info,
297 group_colors_level, precision);
298}
299
300//
301// Private functions
302//
303
304Timing::Timing(Timing* parent, std::string const& tag)
305 : lock_(mutex_, std::defer_lock), tag_(tag), color_(""), parent_(parent)
306{
307}
308
309Timing::Timing(Timing* parent, std::string const& tag, std::string const& color)
310 : lock_(mutex_, std::defer_lock), tag_(tag), color_(color), parent_(parent)
311{
312}
313
314// Timing::Timing(Timing const& other) : Timing(other,
315// std::unique_lock<Mutex>(other.mutex_))
316// {
317// }
318
319// Timing::Timing(Timing const& other, std::unique_lock<Mutex> /* rhs_lk */)
320// : timings_(other.timings_)
321// , tag_(other.tag_)
322// , color_(other.color_)
323// , started_id_(other.started_id_)
324// , has_run_concurrent_(other.has_run_concurrent_)
325// {
326// }
327
328// Timing::Timing(Timing&& other)
329// : Timing(std::move(other), std::unique_lock<Mutex>(other.mutex_))
330// {
331// }
332
333// Timing::Timing(Timing&& other, std::unique_lock<Mutex> /* rhs_lk */)
334// : timings_(std::move(other.timings_))
335// , tag_(std::move(other.tag_))
336// , color_(std::move(other.color_))
337// , started_id_(std::move(other.started_id_))
338// , has_run_concurrent_(std::move(other.has_run_concurrent_))
339// {
340// }
341
342// Timing& Timing::operator=(Timing const& rhs)
343// {
344// if (this != &rhs) {
345// std::scoped_lock lock(mutex_, rhs.mutex_);
346// timings_ = rhs.timings_;
347// tag_ = rhs.tag_;
348// color_ = rhs.color_;
349// started_id_ = rhs.started_id_;
350// has_run_concurrent_ = rhs.has_run_concurrent_;
351// }
352// return *this;
353// }
354
355// Timing& Timing::operator=(Timing&& rhs)
356// {
357// if (this != &rhs) {
358// std::scoped_lock lock(mutex_, rhs.mutex_);
359// timings_ = std::move(rhs.timings_);
360// tag_ = std::move(rhs.tag_);
361// color_ = std::move(rhs.color_);
362// started_id_ = std::move(rhs.started_id_);
363// has_run_concurrent_ = std::move(rhs.has_run_concurrent_);
364// }
365// return *this;
366// }
367
368void Timing::lockParents()
369{
370 std::stack<Timing*> parents;
371 for (auto p = parent_; nullptr != p; p = p->parent_) {
372 parents.push(p);
373 }
374
375 while (!parents.empty()) {
376 auto p = parents.top();
377 parents.pop();
378 p->lock_.lock();
379 }
380}
381
382void Timing::unlockParents()
383{
384 for (auto p = parent_; nullptr != p; p = p->parent_) {
385 p->lock_.unlock();
386 }
387}
388
389Timing* Timing::findDeepest(std::thread::id id)
390{
391 for (auto& [_, child] : children_) {
392 std::lock_guard lock(child.mutex_);
393 if (0 < child.thread_.count(id)) {
394 return child.findDeepest(id);
395 }
396 }
397
398 return this;
399}
400
401std::size_t Timing::stop(std::chrono::time_point<std::chrono::high_resolution_clock> time,
402 std::size_t levels)
403{
404 if (0 == levels) {
405 return 0;
406 }
407
408 // lockParents();
409
410 auto [stopped_levels, _] = stopRecurs(std::this_thread::get_id(), time, levels);
411
412 // unlockParents();
413
414 return stopped_levels;
415}
416
417std::pair<std::size_t, std::chrono::high_resolution_clock::duration> Timing::stopRecurs(
418 std::thread::id /* id */,
419 std::chrono::time_point<std::chrono::high_resolution_clock> /* time */,
420 std::size_t /* levels */)
421{
422 return {};
423 // std::lock_guard lock(mutex_);
424
425 // std::size_t stopped_levels{};
426 // for (auto& [_, child] : children_) {
427 // if (levels <= stopped_levels) {
428 // return {stopped_levels, {}};
429 // }
430 // if (0 < child.running_ids_.count(id) || 0 < child.start_.count(id)) {
431 // auto [sl, et] = child.stopRecurs(id, time, levels - stopped_levels);
432 // stopped_levels += sl;
433 // extra_time_[id] += et;
434 // }
435 // }
436
437 // std::chrono::high_resolution_clock::duration extra_time{};
438 // if (stopped_levels < levels) {
439 // if (auto it = running_ids_.find(id); std::end(running_ids_) != it) {
440 // ++stopped_levels;
441 // running_ids_.erase(it);
442 // if (running_ids_.empty()) {
443 // timer_.stop(time);
444 // }
445 // } else if (auto it = start_.find(id); std::end(start_) != it) {
446 // ++stopped_levels;
447 // it->second.current_ -= extra_time_[id];
448 // extra_time += extra_time_[id];
449 // extra_time_[id] = {}; // TODO: Remove?
450 // it->second.stop(time);
451 // timer_ += it->second;
452 // start_.erase(it);
453 // }
454 // }
455
456 // return {stopped_levels, extra_time};
457}
458
459void Timing::extendImpl(Timing const& /* source */)
460{
461 // TODO: Implement
462
463 // for (auto& child : children_) {
464 // if (child.tag() == source.tag()) {
465 // child.merge(source);
466 // return;
467 // }
468 // }
469
470 // source.parent_ = this;
471 // children_.push_back(source);
472}
473
474void Timing::extendImpl(Timing&& /* source */)
475{
476 // TODO: Implement
477
478 // for (auto& child : children_) {
479 // if (child.tag() == source.tag()) {
480 // child.merge(std::move(source));
481 // return;
482 // }
483 // }
484
485 // source.parent_ = this;
486 // children_.push_back(std::move(source));
487}
488
489void Timing::mergeImpl(Timing const& source)
490{
491 if (tag() != source.tag()) {
492 extendImpl(source);
493 return;
494 }
495
496 // TODO: Implement
497}
498
499void Timing::mergeImpl(Timing&& source)
500{
501 if (tag() != source.tag()) {
502 extendImpl(std::move(source));
503 return;
504 }
505
506 // TODO: Implement
507}
508
509std::vector<Timing::TimingNL> Timing::timings() const
510{
511 std::vector<TimingNL> data;
512 data.emplace_back(this, 0, 0);
513
514 int level{};
515 std::size_t i{1};
516 for (auto& [_, t] : children_) {
517 t.timingsRecurs(data, i, level);
518 ++i;
519 }
520
521 return data;
522}
523
524void Timing::timingsRecurs(std::vector<TimingNL>& data, std::size_t num, int level) const
525{
526 data.emplace_back(this, num, level);
527 std::size_t i{1};
528 for (auto& [_, t] : children_) {
529 t.timingsRecurs(data, i, level + 1);
530 ++i;
531 }
532}
533
534int Timing::maxTagLength(std::vector<TimingNL> const& timers) const
535{
536 int max{};
537 for (auto const& t : timers) {
538 max = std::max(max, 3 * t.level + static_cast<int>(t.timing->tag().length()) + 1);
539 }
540 return max;
541}
542
543void Timing::addTags(std::vector<std::pair<std::wstring, std::wstring>>& data,
544 std::vector<TimingNL> const& timers) const
545{
546 // TODO: Optimized
547
548 std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> converter;
549
550 for (std::size_t i{}; timers.size() > i; ++i) {
551 std::wstring prefix = L" ";
552 // TODO: std::wstring tag_postfix = timers[i].timing->has_run_concurrent_ ? L"² " : L"
553 // ";
554 std::wstring tag_postfix = L" ";
555
556 if (0 == timers[i].level) {
557 data.emplace_back(prefix,
558 converter.from_bytes(timers[i].timing->tag()) + tag_postfix);
559 continue;
560 }
561
562 for (int level{}; timers[i].level - 1 > level; ++level) {
563 bool found = false;
564 for (std::size_t j = i + 1; timers.size() > j; ++j) {
565 if (level == timers[j].level) {
566 found = true;
567 break;
568 } else if (level > timers[j].level) {
569 break;
570 }
571 }
572 if (found) {
573 prefix += L" "; // L"│ "
574 } else {
575 prefix += L" ";
576 }
577 }
578
579 bool found = false;
580 for (std::size_t j = i + 1; timers.size() > j; ++j) {
581 if (timers[i].level == timers[j].level) {
582 found = true;
583 break;
584 } else if (timers[i].level > timers[j].level) {
585 break;
586 }
587 }
588 if (found) {
589 prefix += L"├─ ";
590 } else {
591 prefix += L"└─ "; // L"╰─ "
592 }
593
594 data.emplace_back(prefix,
595 converter.from_bytes(timers[i].timing->tag()) + tag_postfix);
596 }
597}
598
599void Timing::addNumSamples(std::vector<std::wstring>& data,
600 std::vector<TimingNL> const& timers) const
601{
602 for (auto const& t : timers) {
603 auto nc = t.timing->numRunningThreads();
604 if (0 == nc) {
605 data.push_back(L" " + std::to_wstring(t.timing->numSamples()) + L" ");
606 } else {
607 data.push_back(L" " + std::to_wstring(t.timing->numSamples()) + L"+" +
608 std::to_wstring(nc) + L"¹ ");
609 }
610 }
611}
612
613void Timing::addNumThreads(std::vector<std::wstring>& data,
614 std::vector<TimingNL> const& timers) const
615{
616 for (auto const& t : timers) {
617 data.push_back(L" " + std::to_wstring(t.timing->numRunningThreads()) + L"/" +
618 std::to_wstring(t.timing->max_concurrent_threads_) + L" ");
619 }
620}
621
622std::size_t Timing::maxLength(std::vector<std::string> const& data) const
623{
624 std::size_t max{};
625 for (std::string const& s : data) {
626 max = std::max(max, s.length());
627 }
628 return max;
629}
630
631std::size_t Timing::maxLength(std::vector<std::wstring> const& data) const
632{
633 std::size_t max{};
634 for (std::wstring const& s : data) {
635 max = std::max(max, s.length());
636 }
637 return max;
638}
639
640std::pair<int, int> Timing::centeringPadding(std::string const& str, int max_width) const
641{
642 int left_pad = std::floor((max_width - static_cast<int>(str.length())) / 2.0);
643 int right_pad = max_width - (left_pad + static_cast<int>(str.length()));
644 return {left_pad, right_pad};
645}
646
647std::pair<int, int> Timing::centeringPadding(std::wstring const& str, int max_width) const
648{
649 int left_pad = std::floor((max_width - static_cast<int>(str.length())) / 2.0);
650 int right_pad = max_width - (left_pad + static_cast<int>(str.length()));
651 return {left_pad, right_pad};
652}
653
654int Timing::numSamples() const { return timer_.numSamples(); }
655
656void Timing::updateMaxConcurrent()
657{
658 max_concurrent_threads_ = std::max(max_concurrent_threads_, numRunningThreads());
659}
660
661std::size_t Timing::numRunningThreads() const { return thread_.size(); }
662} // namespace ufo
STL namespace.
All vision-related classes and functions.
Definition cloud.hpp:49
constexpr Vec< Geometry::dimension(), typename Geometry::value_type > max(Geometry const &g)
Returns the maximum coordinate of the minimum spanning axis-aligned bounding box of a geometry.
Definition fun.hpp:72