ttg 1.0.0
Template Task Graph (TTG): flowgraph-based programming model for high-performance distributed-memory algorithms
Loading...
Searching...
No Matches
edge.h
Go to the documentation of this file.
1// SPDX-License-Identifier: BSD-3-Clause
2#ifndef TTG_EDGE_H
3#define TTG_EDGE_H
4
5#include <iostream>
6#include <memory>
7#include <vector>
8
9#include "ttg/base/terminal.h"
10#include "ttg/terminal.h"
11#include "ttg/util/diagnose.h"
12#include "ttg/util/print.h"
13#include "ttg/util/trace.h"
14
15namespace ttg {
16
25 template <typename keyT, typename valueT>
26 class Edge {
27 private:
28 // An EdgeImpl represents a single edge that most usually will
29 // connect a single output terminal with a single
30 // input terminal. However, we had to relax this constraint in
31 // order to easily accommodate connecting an input/output edge to
32 // an operation that to the outside looked like a single op but
33 // internally was implemented as multiple operations. Thus, the
34 // input/output edge has to connect to multiple terminals.
35 // Permitting multiple end points makes this much easier to
36 // compose, easier to implement, and likely more efficient at
37 // runtime. This is why outs/ins are vectors rather than pointers
38 // to a single terminal.
39 struct EdgeImpl {
40 std::string name;
41 bool is_pull_edge = false;
42 std::vector<TerminalBase *> outs; // In<keyT, valueT> or In<keyT, const valueT>
43 std::vector<Out<keyT, valueT> *> ins;
44
46
47 EdgeImpl() : name(""), outs(), ins() {}
48
49 EdgeImpl(const std::string &name) : name(name), outs(), ins() {}
50
51 EdgeImpl(const std::string &name, bool is_pull, ttg::detail::ContainerWrapper<keyT, valueT> &c)
52 : name(name), is_pull_edge(is_pull), container(c), outs(), ins() {
53 static_assert(!meta::is_void_v<keyT>, "Void keys are not supported with pull terminals.");
54 }
55
56 void set_in(Out<keyT, valueT> *in) {
57 if (ins.size()) {
58 trace("Edge: ", name, " : has multiple inputs");
59 }
60 in->is_pull_terminal = is_pull_edge;
61 ins.push_back(in);
62 try_to_connect_new_in(in);
63 }
64
65 void set_out(TerminalBase *out) {
66 if (outs.size()) {
67 trace("Edge: ", name, " : has multiple outputs");
68 }
69 out->is_pull_terminal = is_pull_edge;
70 static_cast<In<keyT, valueT> *>(out)->container = container;
71 outs.push_back(out);
72 try_to_connect_new_out(out);
73 }
74
75 void try_to_connect_new_in(Out<keyT, valueT> *in) const {
76 for (auto out : outs)
77 if (in && out) in->connect(out);
78 }
79
80 void try_to_connect_new_out(TerminalBase *out) const {
81 assert(out->get_type() != TerminalBase::Type::Write); // out must be an In<>
82 if (out->is_pull_terminal) {
83 out->connect_pull_nopred(out);
84 } else {
85 for (auto in : ins)
86 if (in && out) in->connect(out);
87 }
88 }
89
90 ~EdgeImpl() {
91 if (diagnose() && ((ins.size() == 0 && outs.size() != 0) || (ins.size() != 0 && outs.size() == 0)) &&
92 !is_pull_edge) {
93 print_error("Edge: destroying edge pimpl ('", name,
94 "') with either in or out not assigned --- graph may be incomplete");
95 }
96 }
97 };
98
99 // We have a vector here to accommodate fusing multiple edges together
100 // when connecting them all to a single terminal.
101 mutable std::vector<std::shared_ptr<EdgeImpl>> p; // Need shallow copy semantics
102
103 public:
105 typedef keyT key_type;
106 typedef valueT value_type;
107 static_assert(std::is_same_v<keyT, std::decay_t<keyT>>, "Edge<keyT,valueT> assumes keyT is a non-decayable type");
108 static_assert(std::is_same_v<valueT, std::decay_t<valueT>>,
109 "Edge<keyT,valueT> assumes valueT is a non-decayable type");
110
111 Edge(const std::string name = "anonymous edge") : p(1) { p[0] = std::make_shared<EdgeImpl>(name); }
112
113 Edge(const std::string name, bool is_pull, ttg::detail::ContainerWrapper<keyT, valueT> c) : p(1) {
114 p[0] = std::make_shared<EdgeImpl>(name, is_pull, c);
115 }
116
118 template <typename... valuesT, typename = std::enable_if_t<(std::is_same_v<valuesT, valueT> && ...)>>
119 Edge(const Edge<keyT, valuesT> &...edges) : p(0) {
120 std::vector<Edge<keyT, valueT>> v = {edges...};
121 // Do not allow fusing of push and pull terminals
122 if (!std::all_of(v.begin(), v.end(), [](Edge<keyT, valueT> e) { return !e.is_pull_edge(); }))
123 throw std::runtime_error("Edge: fusing push and pull terminals is not supported.");
124
125 for (auto &edge : v) {
126 p.insert(p.end(), edge.p.begin(), edge.p.end());
127 }
128 }
129
132 Edge<keyT, valueT> edge() const { return *this; }
133
135 bool live() const {
136 bool result = false;
137 for (const auto &edge : p) {
138 if (!edge->ins.empty()) return true;
139 }
140 return result;
141 }
142
143 bool is_pull_edge() const { return p.at(0)->is_pull_edge; }
144
146 void set_in(Out<keyT, valueT> *in) const {
147 for (auto &edge : p) edge->set_in(in);
148 }
149
151 void set_out(TerminalBase *out) const {
152 for (auto &edge : p) edge->set_out(out);
153 }
154
157 template <typename Key = keyT, typename Value = valueT>
158 std::enable_if_t<ttg::meta::is_all_void_v<Key, Value>> fire() const {
159 for (auto &&e : p)
160 for (auto &&out : e->outs) {
161 out->get_tt()->invoke();
162 }
163 }
164 };
165
166 // Make type of tuple of edges from type of tuple of terminals
167 template <typename termsT>
169 template <typename... termsT>
170 struct terminals_to_edges<std::tuple<termsT...>> {
171 typedef std::tuple<typename termsT::edge_type...> type;
172 };
173
174 // Make type of tuple of output terminals from type of tuple of edges
175 template <typename edgesT>
177 template <typename... edgesT>
178 struct edges_to_output_terminals<std::tuple<edgesT...>> {
179 typedef std::tuple<typename edgesT::output_terminal_type...> type;
180 };
181
182 template<typename edgesT>
184
185 template<typename... edgesT>
186 struct edges_to_output_value_types<std::tuple<edgesT...>> {
187 typedef std::tuple<typename edgesT::value_type...> type;
188 };
189
190 namespace detail {
191 template <typename keyT, typename valuesT>
193
194 template <typename keyT, typename... valuesT>
195 struct edges_tuple<keyT, std::tuple<valuesT...>> {
196 using type = std::tuple<ttg::Edge<keyT, valuesT>...>;
197 };
198
199 template <typename keyT, typename valuesT>
201 } // namespace detail
202
203} // namespace ttg
204
205#endif // TTG_EDGE_H
Edge is used to connect In and Out terminals.
Definition edge.h:26
Edge< keyT, valueT > edge() const
Definition edge.h:132
void set_in(Out< keyT, valueT > *in) const
Sets the output terminal that goes into this Edge.
Definition edge.h:146
std::enable_if_t< ttg::meta::is_all_void_v< Key, Value > > fire() const
Definition edge.h:158
valueT value_type
Definition edge.h:106
Edge(const std::string name="anonymous edge")
Definition edge.h:111
bool live() const
probes if this is already has at least one input received on the input terminal
Definition edge.h:135
Edge(const std::string name, bool is_pull, ttg::detail::ContainerWrapper< keyT, valueT > c)
Definition edge.h:113
keyT key_type
Definition edge.h:105
Edge(const Edge< keyT, valuesT > &...edges)
Edge carrying a tuple of values.
Definition edge.h:119
bool is_pull_edge() const
Definition edge.h:143
Out< keyT, valueT > output_terminal_type
Definition edge.h:104
void set_out(TerminalBase *out) const
Sets the input terminal that this Edge goes into.
Definition edge.h:151
void connect(TerminalBase *in) override
Definition terminal.h:450
bool is_pull_terminal
Definition terminal.h:16
Type get_type() const
Returns the terminal type.
Definition terminal.h:105
void connect_pull_nopred(TerminalBase *p)
Definition terminal.h:114
@ Write
can only be written to
STL namespace.
typename edges_tuple< keyT, valuesT >::type edges_tuple_t
Definition edge.h:200
constexpr auto get(typelist< T, RestOfTs... >)
Definition typelist.h:102
top-level TTG namespace contains runtime-neutral functionality
Definition keymap.h:9
bool diagnose()
Definition diagnose.h:13
void print_error(const T &t, const Ts &... ts)
atomically prints to std::cerr a sequence of items (separated by ttg::print_separator) followed by st...
Definition print.h:139
void trace(const T &t, const Ts &... ts)
Definition trace.h:44
auto edges(inedgesT &&...args)
Make a tuple of Edges to pass to.
Definition func.h:148
std::tuple< ttg::Edge< keyT, valuesT >... > type
Definition edge.h:196
std::tuple< typename edgesT::output_terminal_type... > type
Definition edge.h:179
std::tuple< typename edgesT::value_type... > type
Definition edge.h:187
std::tuple< typename termsT::edge_type... > type
Definition edge.h:171