gtbbexecutor.hpp
3.48 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html.
//
// Copyright (C) 2020 Intel Corporation
#ifndef OPENCV_GAPI_TBB_EXECUTOR_HPP
#define OPENCV_GAPI_TBB_EXECUTOR_HPP
#if !defined(GAPI_STANDALONE)
#include <opencv2/cvconfig.h>
#endif
#ifdef HAVE_TBB
#include <tbb/tbb.h>
#include <tbb/task.h>
#if TBB_INTERFACE_VERSION < 12000
// TODO: TBB task API has been deprecated and removed in 12000
#include <atomic>
#include <vector>
#include <functional>
#include <iosfwd>
#include <tbb/concurrent_priority_queue.h>
#include <tbb/task_arena.h>
#include <opencv2/gapi/util/variant.hpp>
namespace cv { namespace gimpl { namespace parallel {
// simple wrapper to allow copies of std::atomic
template<typename count_t>
struct atomic_copyable_wrapper {
std::atomic<count_t> value;
atomic_copyable_wrapper(count_t val) : value(val) {}
atomic_copyable_wrapper(atomic_copyable_wrapper const& lhs) : value (lhs.value.load(std::memory_order_relaxed)) {}
atomic_copyable_wrapper& operator=(count_t val) {
value.store(val, std::memory_order_relaxed);
return *this;
}
count_t fetch_sub(count_t val) {
return value.fetch_sub(val);
}
count_t fetch_add(count_t val) {
return value.fetch_add(val);
}
};
struct async_tag {};
constexpr async_tag async;
// Class describing a piece of work in the node in the tasks graph.
// Most of the fields are set only once during graph compilation and never changes.
// (However at the moment they can not be made const due to two phase initialization
// of the tile_node objects)
// FIXME: refactor the code to make the const?
struct tile_node {
// place in totally ordered queue of tasks to execute. Inverse to priority, i.e.
// lower index means higher priority
size_t total_order_index = 0;
// FIXME: use templates here instead of std::function
struct sync_task_body {
std::function<void()> body;
};
struct async_task_body {
std::function<void(std::function<void()>&& callback, size_t total_order_index)> body;
};
util::variant<sync_task_body, async_task_body> task_body;
// number of dependencies according to a dependency graph (i.e. number of "input" edges).
size_t dependencies = 0;
// number of unsatisfied dependencies. When drops to zero task is ready for execution.
// Initially equal to "dependencies"
atomic_copyable_wrapper<size_t> dependency_count = 0;
std::vector<tile_node*> dependants;
tile_node(decltype(sync_task_body::body)&& f) : task_body(sync_task_body{std::move(f)}) {};
tile_node(async_tag, decltype(async_task_body::body)&& f) : task_body(async_task_body{std::move(f)}) {};
};
std::ostream& operator<<(std::ostream& o, tile_node const& n);
struct tile_node_indirect_priority_comparator {
bool operator()(tile_node const * lhs, tile_node const * rhs) const {
return lhs->total_order_index > rhs->total_order_index;
}
};
using prio_items_queue_t = tbb::concurrent_priority_queue<tile_node*, tile_node_indirect_priority_comparator>;
void execute(prio_items_queue_t& q);
void execute(prio_items_queue_t& q, tbb::task_arena& arena);
}}} // namespace cv::gimpl::parallel
#endif // TBB_INTERFACE_VERSION
#endif // HAVE_TBB
#endif // OPENCV_GAPI_TBB_EXECUTOR_HPP