diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2014-07-24 19:09:06 -0400 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2014-07-24 19:09:06 -0400 |
commit | 4f12aa3d2eb3ac041af74ba2632086545e783f3d (patch) | |
tree | d33448726c7dfd8e030960cde2dcc9ebf03abc8b | |
parent | 5692d325b5c1b443fe91b126e686b314cc313976 (diff) |
Add support for backedges.
This patch adds support for explicit backedges in PGM graphs.
-rw-r--r-- | include/pgm.h | 66 | ||||
-rw-r--r-- | src/pgm.cpp | 370 |
2 files changed, 357 insertions, 79 deletions
diff --git a/include/pgm.h b/include/pgm.h index a64a4f6..676bd85 100644 --- a/include/pgm.h +++ b/include/pgm.h | |||
@@ -200,7 +200,24 @@ int pgm_init_node(node_t* node, graph_t graph, const char* name); | |||
200 | Return: 0 on success. -1 on error. | 200 | Return: 0 on success. -1 on error. |
201 | */ | 201 | */ |
202 | int pgm_init_edge(edge_t* edge, node_t producer, node_t consumer, | 202 | int pgm_init_edge(edge_t* edge, node_t producer, node_t consumer, |
203 | const char* name, const edge_attr_t* attr = &default_edge); | 203 | const char* name, const edge_attr_t* attr = &default_edge); |
204 | |||
205 | /* | ||
206 | Add an back-edge between two nodes in the same graph. It is assumed | ||
207 | that the producer will be a child of the consumer. The 'nr_skip' parameter | ||
208 | denotes how many times the consumer may execute before it starts reading | ||
209 | from the edge. For data-passing edges, contents of data buffer is undefined. | ||
210 | [out] edge: Pointer to edge | ||
211 | [in] nr_skips: Number of times consumer initially skips reading the edge | ||
212 | [in] producer: The producer node | ||
213 | [in] consumer: The consumer node | ||
214 | [in] name: Name of the edge | ||
215 | [in] attr: Edge parameters | ||
216 | Return: 0 on success. -1 on error. | ||
217 | */ | ||
218 | int pgm_init_backedge(edge_t* edge, size_t nr_skips, | ||
219 | node_t producer, node_t consumer, | ||
220 | const char* name, const edge_attr_t* attr = &default_edge); | ||
204 | 221 | ||
205 | /* | 222 | /* |
206 | Find a graph by its name. (Graph is found within the namespace | 223 | Find a graph by its name. (Graph is found within the namespace |
@@ -231,7 +248,7 @@ int pgm_find_node(node_t* node, graph_t graph, const char* name); | |||
231 | Return: 0 on success. -1 on error. | 248 | Return: 0 on success. -1 on error. |
232 | */ | 249 | */ |
233 | int pgm_find_edge(edge_t* edge, node_t producer, node_t consumer, | 250 | int pgm_find_edge(edge_t* edge, node_t producer, node_t consumer, |
234 | const char* name, edge_attr_t* attrs = NULL); | 251 | const char* name, edge_attr_t* attrs = NULL); |
235 | 252 | ||
236 | /* | 253 | /* |
237 | Find the first edge between a producer and consumer. | 254 | Find the first edge between a producer and consumer. |
@@ -243,7 +260,7 @@ int pgm_find_edge(edge_t* edge, node_t producer, node_t consumer, | |||
243 | Return: 0 on success. -1 on error. | 260 | Return: 0 on success. -1 on error. |
244 | */ | 261 | */ |
245 | int pgm_find_first_edge(edge_t* edge, node_t producer, node_t consumer, | 262 | int pgm_find_first_edge(edge_t* edge, node_t producer, node_t consumer, |
246 | edge_attr_t* attrs = NULL); | 263 | edge_attr_t* attrs = NULL); |
247 | 264 | ||
248 | /* | 265 | /* |
249 | Attach user data to a given node. | 266 | Attach user data to a given node. |
@@ -268,7 +285,7 @@ void* pgm_get_user_data(node_t node); | |||
268 | Must be >= number of successors of node. | 285 | Must be >= number of successors of node. |
269 | Return: 0 on success. -1 on error. | 286 | Return: 0 on success. -1 on error. |
270 | */ | 287 | */ |
271 | int pgm_get_successors(node_t n, node_t* successors, int len); | 288 | int pgm_get_successors(node_t n, node_t* successors, int len, int ignore_backedges = 1); |
272 | 289 | ||
273 | /* | 290 | /* |
274 | Get edge descriptors of all outbound edges of a node. | 291 | Get edge descriptors of all outbound edges of a node. |
@@ -278,7 +295,7 @@ int pgm_get_successors(node_t n, node_t* successors, int len); | |||
278 | Must be >= number of outbound-edges of node. | 295 | Must be >= number of outbound-edges of node. |
279 | Return: 0 on success. -1 on error. | 296 | Return: 0 on success. -1 on error. |
280 | */ | 297 | */ |
281 | int pgm_get_edges_out(node_t n, edge_t* edges, int len); | 298 | int pgm_get_edges_out(node_t n, edge_t* edges, int len, int ignore_backedges = 1); |
282 | 299 | ||
283 | /* | 300 | /* |
284 | Get node descriptors to all predecessors of a node. | 301 | Get node descriptors to all predecessors of a node. |
@@ -288,7 +305,7 @@ int pgm_get_edges_out(node_t n, edge_t* edges, int len); | |||
288 | Must be >= number of predecessors of node. | 305 | Must be >= number of predecessors of node. |
289 | Return: 0 on success. -1 on error. | 306 | Return: 0 on success. -1 on error. |
290 | */ | 307 | */ |
291 | int pgm_get_predecessors(node_t, node_t* predecessors, int len); | 308 | int pgm_get_predecessors(node_t, node_t* predecessors, int len, int ignore_backedges = 1); |
292 | 309 | ||
293 | /* | 310 | /* |
294 | Get edge descriptors of all inbound edges of a node. | 311 | Get edge descriptors of all inbound edges of a node. |
@@ -298,28 +315,28 @@ int pgm_get_predecessors(node_t, node_t* predecessors, int len); | |||
298 | Must be >= number of outbound-edges of node. | 315 | Must be >= number of outbound-edges of node. |
299 | Return: 0 on success. -1 on error. | 316 | Return: 0 on success. -1 on error. |
300 | */ | 317 | */ |
301 | int pgm_get_edges_in(node_t n, edge_t* edges, int len); | 318 | int pgm_get_edges_in(node_t n, edge_t* edges, int len, int ignore_backedges = 1); |
302 | 319 | ||
303 | /* | 320 | /* |
304 | Get the total number of edges connected to a node. | 321 | Get the total number of edges connected to a node. |
305 | [in] node: Node descriptor | 322 | [in] node: Node descriptor |
306 | Return: Degree of node. -1 on error. | 323 | Return: Degree of node. -1 on error. |
307 | */ | 324 | */ |
308 | int pgm_get_degree(node_t node); | 325 | int pgm_get_degree(node_t node, int ignore_backedges = 1); |
309 | 326 | ||
310 | /* | 327 | /* |
311 | Get the number of inbound edges of a node. | 328 | Get the number of inbound edges of a node. |
312 | [in] node: Node descriptor | 329 | [in] node: Node descriptor |
313 | Return: Inbound degree of edge. -1 on error. | 330 | Return: Inbound degree of edge. -1 on error. |
314 | */ | 331 | */ |
315 | int pgm_get_degree_in(node_t node); | 332 | int pgm_get_degree_in(node_t node, int ignore_backedges = 1); |
316 | 333 | ||
317 | /* | 334 | /* |
318 | Get the number of outbound edges of a node. | 335 | Get the number of outbound edges of a node. |
319 | [in] node: Node descriptor | 336 | [in] node: Node descriptor |
320 | Return: Outbound degree of node. -1 on error. | 337 | Return: Outbound degree of node. -1 on error. |
321 | */ | 338 | */ |
322 | int pgm_get_degree_out(node_t node); | 339 | int pgm_get_degree_out(node_t node, int ignore_backedges = 1); |
323 | 340 | ||
324 | /* | 341 | /* |
325 | Get the name of a node. | 342 | Get the name of a node. |
@@ -351,6 +368,20 @@ node_t pgm_get_consumer(edge_t edge); | |||
351 | int pgm_get_edge_attrs(edge_t edge, edge_attr_t* attrs); | 368 | int pgm_get_edge_attrs(edge_t edge, edge_attr_t* attrs); |
352 | 369 | ||
353 | /* | 370 | /* |
371 | Query to determine if edge was added with pgm_init_backedge(). | ||
372 | [in] backedge: Edge descriptor | ||
373 | Returns: 1 if edge was added with pgm_init_backedge(). 0 otherwise. | ||
374 | */ | ||
375 | int pgm_is_backedge(edge_t backedge); | ||
376 | |||
377 | /* | ||
378 | Get the number of skips remaining on a backedge. | ||
379 | [in] edge: Edge descriptor | ||
380 | Returns: Number of remaining skips. Beware: Returns 0 if edge is invalid. | ||
381 | */ | ||
382 | size_t pgn_get_nr_skips_remaining(edge_t backedge); | ||
383 | |||
384 | /* | ||
354 | Get the number of tokens generated by the producer per invocation. | 385 | Get the number of tokens generated by the producer per invocation. |
355 | [in] edge: Edge descriptor | 386 | [in] edge: Edge descriptor |
356 | Return: Number of tokens produced on edge. -1 on error. | 387 | Return: Number of tokens produced on edge. -1 on error. |
@@ -374,16 +405,19 @@ int pgm_get_nr_threshold(edge_t edge); | |||
374 | /* | 405 | /* |
375 | Check if a graph is a acyclic. | 406 | Check if a graph is a acyclic. |
376 | [in] graph: Graph descriptor | 407 | [in] graph: Graph descriptor |
408 | [in] ignore_explicit_backedges: Ignore edges that were added | ||
409 | with pgm_init_backedge(). | ||
377 | Return: 1 if graph is acyclic, 0 if it is not. | 410 | Return: 1 if graph is acyclic, 0 if it is not. |
378 | */ | 411 | */ |
379 | int pgm_is_dag(graph_t graph); | 412 | int pgm_is_dag(graph_t graph, int ignore_explicit_backedges = 1); |
380 | 413 | ||
381 | /* Signature of a function that weights a given edge */ | 414 | /* Signature of a function that weights a given edge */ |
382 | typedef double (*pgm_weight_func_t)(edge_t e, void* user); | 415 | typedef double (*pgm_weight_func_t)(edge_t e, void* user); |
383 | 416 | ||
384 | /* | 417 | /* |
385 | Get the length of the shortest path from any graph source to a node, | 418 | Get the length of the shortest path from any graph source to a node, |
386 | optionally weighted by user function. | 419 | optionally weighted by user function. Edges added with pgm_init_backedge() |
420 | are ignored. | ||
387 | [in] node: Node descriptor | 421 | [in] node: Node descriptor |
388 | [in] w: Edge weight function. If NULL, then default edge | 422 | [in] w: Edge weight function. If NULL, then default edge |
389 | weight of 1.0 is used. | 423 | weight of 1.0 is used. |
@@ -394,7 +428,8 @@ double pgm_get_min_depth(node_t node, pgm_weight_func_t w = NULL, void* user = N | |||
394 | 428 | ||
395 | /* | 429 | /* |
396 | Get the length of the longest path from any graph source to a node, | 430 | Get the length of the longest path from any graph source to a node, |
397 | optionally weighted by a user function. | 431 | optionally weighted by a user function. Edges added with pgm_init_backedge() |
432 | are ignored. | ||
398 | [in] node: Node descriptor | 433 | [in] node: Node descriptor |
399 | [in] w: Edge weight function. If NULL, then default edge | 434 | [in] w: Edge weight function. If NULL, then default edge |
400 | weight of 1.0 is used. | 435 | weight of 1.0 is used. |
@@ -559,6 +594,11 @@ int pgm_init_edge(edge_t* edge, node_t producer, node_t consumer, | |||
559 | unsigned int numerical_name, | 594 | unsigned int numerical_name, |
560 | const edge_attr_t* attrs = &default_edge); | 595 | const edge_attr_t* attrs = &default_edge); |
561 | 596 | ||
597 | int pgm_init_backedge(edge_t* edge, size_t nskips, | ||
598 | node_t producer, node_t consumer, | ||
599 | unsigned int numerical_name, | ||
600 | const edge_attr_t* attrs = &default_edge); | ||
601 | |||
562 | int pgm_find_edge(edge_t* edge, node_t producer, node_t consumer, | 602 | int pgm_find_edge(edge_t* edge, node_t producer, node_t consumer, |
563 | unsigned int numerical_name, | 603 | unsigned int numerical_name, |
564 | edge_attr_t* attrs = NULL); | 604 | edge_attr_t* attrs = NULL); |
diff --git a/src/pgm.cpp b/src/pgm.cpp index 55ca7b7..791f074 100644 --- a/src/pgm.cpp +++ b/src/pgm.cpp | |||
@@ -11,6 +11,8 @@ | |||
11 | #include <sys/socket.h> | 11 | #include <sys/socket.h> |
12 | #include <netdb.h> | 12 | #include <netdb.h> |
13 | 13 | ||
14 | #include <sys/syscall.h> | ||
15 | |||
14 | #include <set> | 16 | #include <set> |
15 | #include <queue> | 17 | #include <queue> |
16 | #include <string> | 18 | #include <string> |
@@ -64,6 +66,12 @@ typedef uint32_t pgm_fd_mask_t; | |||
64 | 66 | ||
65 | static __thread char errnostr_buf[80]; | 67 | static __thread char errnostr_buf[80]; |
66 | 68 | ||
69 | static inline pid_t gettid(void) | ||
70 | { | ||
71 | pid_t p = syscall(__NR_gettid); | ||
72 | return p; | ||
73 | } | ||
74 | |||
67 | // Used to report system FAILUREs. | 75 | // Used to report system FAILUREs. |
68 | #define F(fmt, ...) \ | 76 | #define F(fmt, ...) \ |
69 | do { \ | 77 | do { \ |
@@ -130,10 +138,15 @@ struct pgm_edge | |||
130 | int producer; | 138 | int producer; |
131 | int consumer; | 139 | int consumer; |
132 | 140 | ||
141 | // flag set if edge is a back-edge | ||
142 | int is_backedge; | ||
143 | |||
133 | // edge type and operations | 144 | // edge type and operations |
134 | edge_attr_t attr; | 145 | edge_attr_t attr; |
135 | struct pgm_edge_ops const* ops; | 146 | struct pgm_edge_ops const* ops; |
136 | 147 | ||
148 | // number of skipped edges | ||
149 | size_t nr_skips; | ||
137 | 150 | ||
138 | // number of accumulated tokens | 151 | // number of accumulated tokens |
139 | // (used by signaled edges) | 152 | // (used by signaled edges) |
@@ -205,9 +218,15 @@ struct pgm_node | |||
205 | 218 | ||
206 | // number of edges that pass data | 219 | // number of edges that pass data |
207 | int nr_in_data; | 220 | int nr_in_data; |
221 | // number of edges signaled using condition variables | ||
208 | int nr_in_signaled; | 222 | int nr_in_signaled; |
209 | 223 | ||
210 | // bit is set if edge is a singalling edge. | 224 | // number of data-passing edges that are backedges |
225 | int nr_in_data_backedges; | ||
226 | // number of signal-based edges that are backedges | ||
227 | int nr_in_signaled_backedges; | ||
228 | |||
229 | // bit is set if edge is a singaling edge. | ||
211 | pgm_fd_mask_t signal_edge_mask; | 230 | pgm_fd_mask_t signal_edge_mask; |
212 | 231 | ||
213 | // only used if inbound edges are signal-based | 232 | // only used if inbound edges are signal-based |
@@ -231,9 +250,9 @@ struct pgm_graph | |||
231 | pthread_mutex_t lock; | 250 | pthread_mutex_t lock; |
232 | 251 | ||
233 | int nr_nodes; | 252 | int nr_nodes; |
234 | struct pgm_node nodes[PGM_MAX_NODES]; | ||
235 | |||
236 | int nr_edges; | 253 | int nr_edges; |
254 | |||
255 | struct pgm_node nodes[PGM_MAX_NODES]; | ||
237 | struct pgm_edge edges[PGM_MAX_EDGES]; | 256 | struct pgm_edge edges[PGM_MAX_EDGES]; |
238 | }; | 257 | }; |
239 | 258 | ||
@@ -1914,9 +1933,10 @@ int pgm_init_node(node_t* node, graph_t graph, unsigned int numerical_name) | |||
1914 | return pgm_init_node(node, graph, name); | 1933 | return pgm_init_node(node, graph, name); |
1915 | } | 1934 | } |
1916 | 1935 | ||
1917 | int pgm_init_edge(edge_t* edge, | 1936 | static int __pgm_init_edge(edge_t* edge, |
1918 | node_t producer, node_t consumer, const char* name, | 1937 | node_t producer, node_t consumer, const char* name, |
1919 | const edge_attr_t* attr) | 1938 | const edge_attr_t* attr, |
1939 | size_t nr_skips) | ||
1920 | { | 1940 | { |
1921 | int ret = -1; | 1941 | int ret = -1; |
1922 | struct pgm_graph* g; | 1942 | struct pgm_graph* g; |
@@ -1990,10 +2010,19 @@ int pgm_init_edge(edge_t* edge, | |||
1990 | { | 2010 | { |
1991 | nc->nr_in_signaled++; | 2011 | nc->nr_in_signaled++; |
1992 | nc->signal_edge_mask |= ((pgm_fd_mask_t)(1))<<(nc->nr_in); | 2012 | nc->signal_edge_mask |= ((pgm_fd_mask_t)(1))<<(nc->nr_in); |
2013 | |||
2014 | if(nr_skips) | ||
2015 | { | ||
2016 | nc->nr_in_signaled_backedges++; | ||
2017 | } | ||
1993 | } | 2018 | } |
1994 | if(is_data_passing(attr)) | 2019 | if(is_data_passing(attr)) |
1995 | { | 2020 | { |
1996 | nc->nr_in_data++; | 2021 | nc->nr_in_data++; |
2022 | if(nr_skips) | ||
2023 | { | ||
2024 | nc->nr_in_data_backedges++; | ||
2025 | } | ||
1997 | } | 2026 | } |
1998 | 2027 | ||
1999 | np->out[np->nr_out++] = edge->edge; | 2028 | np->out[np->nr_out++] = edge->edge; |
@@ -2006,6 +2035,12 @@ int pgm_init_edge(edge_t* edge, | |||
2006 | e->consumer = consumer.node; | 2035 | e->consumer = consumer.node; |
2007 | e->attr = *attr; | 2036 | e->attr = *attr; |
2008 | 2037 | ||
2038 | if(nr_skips) | ||
2039 | { | ||
2040 | e->is_backedge = true; | ||
2041 | e->nr_skips = nr_skips; | ||
2042 | } | ||
2043 | |||
2009 | if (attr->type & __PGM_EDGE_CV) | 2044 | if (attr->type & __PGM_EDGE_CV) |
2010 | e->ops = &pgm_cv_edge_ops; | 2045 | e->ops = &pgm_cv_edge_ops; |
2011 | else if(attr->type & __PGM_EDGE_FIFO) | 2046 | else if(attr->type & __PGM_EDGE_FIFO) |
@@ -2027,6 +2062,14 @@ out: | |||
2027 | return ret; | 2062 | return ret; |
2028 | } | 2063 | } |
2029 | 2064 | ||
2065 | int pgm_init_edge(edge_t* edge, | ||
2066 | node_t producer, node_t consumer, const char* name, | ||
2067 | const edge_attr_t* attr) | ||
2068 | { | ||
2069 | int ret = __pgm_init_edge(edge, producer, consumer, name, attr, 0); | ||
2070 | return ret; | ||
2071 | } | ||
2072 | |||
2030 | int pgm_init_edge(edge_t* edge, node_t producer, node_t consumer, | 2073 | int pgm_init_edge(edge_t* edge, node_t producer, node_t consumer, |
2031 | unsigned int numerical_name, | 2074 | unsigned int numerical_name, |
2032 | const edge_attr_t* attrs) | 2075 | const edge_attr_t* attrs) |
@@ -2036,6 +2079,24 @@ int pgm_init_edge(edge_t* edge, node_t producer, node_t consumer, | |||
2036 | return pgm_init_edge(edge, producer, consumer, name, attrs); | 2079 | return pgm_init_edge(edge, producer, consumer, name, attrs); |
2037 | } | 2080 | } |
2038 | 2081 | ||
2082 | int pgm_init_backedge(edge_t* edge, size_t nr_skips, | ||
2083 | node_t producer, node_t consumer, const char* name, | ||
2084 | const edge_attr_t* attr) | ||
2085 | { | ||
2086 | int ret = __pgm_init_edge(edge, producer, consumer, name, attr, nr_skips); | ||
2087 | return ret; | ||
2088 | } | ||
2089 | |||
2090 | int pgm_init_backedge(edge_t* edge, size_t nr_skips, | ||
2091 | node_t producer, node_t consumer, | ||
2092 | unsigned int numerical_name, | ||
2093 | const edge_attr_t* attrs) | ||
2094 | { | ||
2095 | char name[PGM_EDGE_NAME_LEN]; | ||
2096 | snprintf(name, PGM_EDGE_NAME_LEN, "%x", numerical_name); | ||
2097 | return pgm_init_backedge(edge, nr_skips, producer, consumer, name, attrs); | ||
2098 | } | ||
2099 | |||
2039 | /////////////////////////////////////////////////// | 2100 | /////////////////////////////////////////////////// |
2040 | // Graph/Node/Edge Query Routines // | 2101 | // Graph/Node/Edge Query Routines // |
2041 | /////////////////////////////////////////////////// | 2102 | /////////////////////////////////////////////////// |
@@ -2247,11 +2308,12 @@ out: | |||
2247 | return udata; | 2308 | return udata; |
2248 | } | 2309 | } |
2249 | 2310 | ||
2250 | int pgm_get_successors(node_t node, node_t* successors, int len) | 2311 | int pgm_get_successors(node_t node, node_t* successors, int len, int ignore_backedges) |
2251 | { | 2312 | { |
2252 | int num = -1; | 2313 | int num = -1; |
2253 | struct pgm_graph* g; | 2314 | struct pgm_graph* g; |
2254 | struct pgm_node* n; | 2315 | struct pgm_node* n; |
2316 | node_t* step = successors; | ||
2255 | 2317 | ||
2256 | if(!successors || !is_valid_graph(node.graph)) | 2318 | if(!successors || !is_valid_graph(node.graph)) |
2257 | goto out; | 2319 | goto out; |
@@ -2265,15 +2327,23 @@ int pgm_get_successors(node_t node, node_t* successors, int len) | |||
2265 | goto out_unlock; | 2327 | goto out_unlock; |
2266 | num = n->nr_out; | 2328 | num = n->nr_out; |
2267 | 2329 | ||
2268 | for(int i = 0; i < num; ++i) | 2330 | for(int i = 0, nr_to_check = num; i < nr_to_check; ++i) |
2269 | { | 2331 | { |
2270 | const pgm_node* const _succ = &g->nodes[g->edges[n->out[i]].consumer]; | 2332 | if(ignore_backedges && g->edges[n->out[i]].is_backedge) |
2271 | node_t succ = | ||
2272 | { | 2333 | { |
2273 | .graph = node.graph, | 2334 | --num; |
2274 | .node = (int)(_succ - &g->nodes[0]) | 2335 | } |
2275 | }; | 2336 | else |
2276 | successors[i] = succ; | 2337 | { |
2338 | const pgm_node* const _succ = &g->nodes[g->edges[n->out[i]].consumer]; | ||
2339 | node_t succ = | ||
2340 | { | ||
2341 | .graph = node.graph, | ||
2342 | .node = (int)(_succ - &g->nodes[0]) | ||
2343 | }; | ||
2344 | *step = succ; | ||
2345 | ++step; | ||
2346 | } | ||
2277 | } | 2347 | } |
2278 | out_unlock: | 2348 | out_unlock: |
2279 | pthread_mutex_unlock(&g->lock); | 2349 | pthread_mutex_unlock(&g->lock); |
@@ -2281,11 +2351,12 @@ out: | |||
2281 | return num; | 2351 | return num; |
2282 | } | 2352 | } |
2283 | 2353 | ||
2284 | int pgm_get_edges_out(node_t node, edge_t* edges, int len) | 2354 | int pgm_get_edges_out(node_t node, edge_t* edges, int len, int ignore_backedges) |
2285 | { | 2355 | { |
2286 | int num = -1; | 2356 | int num = -1; |
2287 | struct pgm_graph* g; | 2357 | struct pgm_graph* g; |
2288 | struct pgm_node* n; | 2358 | struct pgm_node* n; |
2359 | edge_t* step = edges; | ||
2289 | 2360 | ||
2290 | if(!edges || !is_valid_graph(node.graph)) | 2361 | if(!edges || !is_valid_graph(node.graph)) |
2291 | goto out; | 2362 | goto out; |
@@ -2299,14 +2370,22 @@ int pgm_get_edges_out(node_t node, edge_t* edges, int len) | |||
2299 | goto out_unlock; | 2370 | goto out_unlock; |
2300 | num = n->nr_out; | 2371 | num = n->nr_out; |
2301 | 2372 | ||
2302 | for(int i = 0; i < num; ++i) | 2373 | for(int i = 0, nr_to_check = num; i < nr_to_check; ++i) |
2303 | { | 2374 | { |
2304 | edge_t e = | 2375 | if(ignore_backedges && g->edges[n->out[i]].is_backedge) |
2305 | { | 2376 | { |
2306 | .graph = node.graph, | 2377 | --num; |
2307 | .edge = n->out[i] | 2378 | } |
2308 | }; | 2379 | else |
2309 | edges[i] = e; | 2380 | { |
2381 | edge_t e = | ||
2382 | { | ||
2383 | .graph = node.graph, | ||
2384 | .edge = n->out[i] | ||
2385 | }; | ||
2386 | *step = e; | ||
2387 | ++step; | ||
2388 | } | ||
2310 | } | 2389 | } |
2311 | out_unlock: | 2390 | out_unlock: |
2312 | pthread_mutex_unlock(&g->lock); | 2391 | pthread_mutex_unlock(&g->lock); |
@@ -2314,11 +2393,12 @@ out: | |||
2314 | return num; | 2393 | return num; |
2315 | } | 2394 | } |
2316 | 2395 | ||
2317 | int pgm_get_predecessors(node_t node, node_t* predecessors, int len) | 2396 | int pgm_get_predecessors(node_t node, node_t* predecessors, int len, int ignore_backedges) |
2318 | { | 2397 | { |
2319 | int num = -1; | 2398 | int num = -1; |
2320 | struct pgm_graph* g; | 2399 | struct pgm_graph* g; |
2321 | struct pgm_node* n; | 2400 | struct pgm_node* n; |
2401 | node_t* step = predecessors; | ||
2322 | 2402 | ||
2323 | if(!predecessors || !is_valid_graph(node.graph)) | 2403 | if(!predecessors || !is_valid_graph(node.graph)) |
2324 | goto out; | 2404 | goto out; |
@@ -2332,15 +2412,23 @@ int pgm_get_predecessors(node_t node, node_t* predecessors, int len) | |||
2332 | goto out_unlock; | 2412 | goto out_unlock; |
2333 | num = n->nr_in; | 2413 | num = n->nr_in; |
2334 | 2414 | ||
2335 | for(int i = 0; i < num; ++i) | 2415 | for(int i = 0, nr_to_check = num; i < nr_to_check; ++i) |
2336 | { | 2416 | { |
2337 | const pgm_node* const _pred = &g->nodes[g->edges[n->in[i]].producer]; | 2417 | if(ignore_backedges && g->edges[n->in[i]].is_backedge) |
2338 | node_t pred = | ||
2339 | { | 2418 | { |
2340 | .graph = node.graph, | 2419 | --num; |
2341 | .node = (int)(_pred - &g->nodes[0]) | 2420 | } |
2342 | }; | 2421 | else |
2343 | predecessors[i] = pred; | 2422 | { |
2423 | const pgm_node* const _pred = &g->nodes[g->edges[n->in[i]].producer]; | ||
2424 | node_t pred = | ||
2425 | { | ||
2426 | .graph = node.graph, | ||
2427 | .node = (int)(_pred - &g->nodes[0]) | ||
2428 | }; | ||
2429 | *step = pred; | ||
2430 | ++step; | ||
2431 | } | ||
2344 | } | 2432 | } |
2345 | out_unlock: | 2433 | out_unlock: |
2346 | pthread_mutex_unlock(&g->lock); | 2434 | pthread_mutex_unlock(&g->lock); |
@@ -2348,11 +2436,12 @@ out: | |||
2348 | return num; | 2436 | return num; |
2349 | } | 2437 | } |
2350 | 2438 | ||
2351 | int pgm_get_edges_in(node_t node, edge_t* edges, int len) | 2439 | int pgm_get_edges_in(node_t node, edge_t* edges, int len, int ignore_backedges) |
2352 | { | 2440 | { |
2353 | int num = -1; | 2441 | int num = -1; |
2354 | struct pgm_graph* g; | 2442 | struct pgm_graph* g; |
2355 | struct pgm_node* n; | 2443 | struct pgm_node* n; |
2444 | edge_t* step = edges; | ||
2356 | 2445 | ||
2357 | if(!edges || !is_valid_graph(node.graph)) | 2446 | if(!edges || !is_valid_graph(node.graph)) |
2358 | goto out; | 2447 | goto out; |
@@ -2366,14 +2455,22 @@ int pgm_get_edges_in(node_t node, edge_t* edges, int len) | |||
2366 | goto out_unlock; | 2455 | goto out_unlock; |
2367 | num = n->nr_in; | 2456 | num = n->nr_in; |
2368 | 2457 | ||
2369 | for(int i = 0; i < num; ++i) | 2458 | for(int i = 0, nr_to_check = num; i < nr_to_check; ++i) |
2370 | { | 2459 | { |
2371 | edge_t e = | 2460 | if(ignore_backedges && g->edges[n->in[i]].is_backedge) |
2372 | { | 2461 | { |
2373 | .graph = node.graph, | 2462 | --num; |
2374 | .edge = n->in[i] | 2463 | } |
2375 | }; | 2464 | else |
2376 | edges[i] = e; | 2465 | { |
2466 | edge_t e = | ||
2467 | { | ||
2468 | .graph = node.graph, | ||
2469 | .edge = n->in[i] | ||
2470 | }; | ||
2471 | *step = e; | ||
2472 | ++step; | ||
2473 | } | ||
2377 | } | 2474 | } |
2378 | out_unlock: | 2475 | out_unlock: |
2379 | pthread_mutex_unlock(&g->lock); | 2476 | pthread_mutex_unlock(&g->lock); |
@@ -2444,6 +2541,37 @@ out: | |||
2444 | return ret; | 2541 | return ret; |
2445 | } | 2542 | } |
2446 | 2543 | ||
2544 | int pgm_is_backedge(edge_t backedge) | ||
2545 | { | ||
2546 | int is_be = 0; | ||
2547 | struct pgm_graph* g; | ||
2548 | |||
2549 | if(!is_valid_graph(backedge.graph)) | ||
2550 | goto out; | ||
2551 | |||
2552 | g = &gGraphs[backedge.graph]; | ||
2553 | is_be = g->edges[backedge.edge].is_backedge; | ||
2554 | |||
2555 | out: | ||
2556 | return is_be; | ||
2557 | } | ||
2558 | |||
2559 | size_t pgn_get_nr_skips_remaining(edge_t backedge) | ||
2560 | { | ||
2561 | size_t remaining = 0; | ||
2562 | struct pgm_graph* g; | ||
2563 | |||
2564 | if(!is_valid_graph(backedge.graph)) | ||
2565 | goto out; | ||
2566 | |||
2567 | g = &gGraphs[backedge.graph]; | ||
2568 | if(g->edges[backedge.edge].is_backedge) | ||
2569 | remaining = g->edges[backedge.edge].nr_skips; | ||
2570 | |||
2571 | out: | ||
2572 | return remaining; | ||
2573 | } | ||
2574 | |||
2447 | int pgm_get_nr_produce(edge_t edge) | 2575 | int pgm_get_nr_produce(edge_t edge) |
2448 | { | 2576 | { |
2449 | int produced = -1; | 2577 | int produced = -1; |
@@ -2489,7 +2617,7 @@ out: | |||
2489 | return threshold; | 2617 | return threshold; |
2490 | } | 2618 | } |
2491 | 2619 | ||
2492 | int pgm_get_degree(node_t node) | 2620 | int pgm_get_degree(node_t node, int ignore_backedges) |
2493 | { | 2621 | { |
2494 | int ret = -1; | 2622 | int ret = -1; |
2495 | struct pgm_graph* g; | 2623 | struct pgm_graph* g; |
@@ -2502,14 +2630,31 @@ int pgm_get_degree(node_t node) | |||
2502 | n = &g->nodes[node.node]; | 2630 | n = &g->nodes[node.node]; |
2503 | 2631 | ||
2504 | pthread_mutex_lock(&g->lock); | 2632 | pthread_mutex_lock(&g->lock); |
2505 | ret = n->nr_in + n->nr_out; | 2633 | if(!ignore_backedges) |
2634 | { | ||
2635 | ret = n->nr_in + n->nr_out; | ||
2636 | } | ||
2637 | else | ||
2638 | { | ||
2639 | ret = 0; | ||
2640 | for(int i = 0; i < n->nr_in; ++i) | ||
2641 | { | ||
2642 | if(!g->edges[n->in[i]].is_backedge) | ||
2643 | ++ret; | ||
2644 | } | ||
2645 | for(int i = 0; i < n->nr_out; ++i) | ||
2646 | { | ||
2647 | if(!g->edges[n->out[i]].is_backedge) | ||
2648 | ++ret; | ||
2649 | } | ||
2650 | } | ||
2506 | pthread_mutex_unlock(&g->lock); | 2651 | pthread_mutex_unlock(&g->lock); |
2507 | 2652 | ||
2508 | out: | 2653 | out: |
2509 | return ret; | 2654 | return ret; |
2510 | } | 2655 | } |
2511 | 2656 | ||
2512 | int pgm_get_degree_in(node_t node) | 2657 | int pgm_get_degree_in(node_t node, int ignore_backedges) |
2513 | { | 2658 | { |
2514 | int ret = -1; | 2659 | int ret = -1; |
2515 | struct pgm_graph* g; | 2660 | struct pgm_graph* g; |
@@ -2520,15 +2665,28 @@ int pgm_get_degree_in(node_t node) | |||
2520 | 2665 | ||
2521 | g = &gGraphs[node.graph]; | 2666 | g = &gGraphs[node.graph]; |
2522 | n = &g->nodes[node.node]; | 2667 | n = &g->nodes[node.node]; |
2523 | __sync_synchronize(); | 2668 | |
2524 | ret = n->nr_in; | 2669 | pthread_mutex_lock(&g->lock); |
2525 | __sync_synchronize(); | 2670 | if(!ignore_backedges) |
2671 | { | ||
2672 | ret = n->nr_in; | ||
2673 | } | ||
2674 | else | ||
2675 | { | ||
2676 | ret = 0; | ||
2677 | for(int i = 0; i < n->nr_in; ++i) | ||
2678 | { | ||
2679 | if(!g->edges[n->in[i]].is_backedge) | ||
2680 | ++ret; | ||
2681 | } | ||
2682 | } | ||
2683 | pthread_mutex_unlock(&g->lock); | ||
2526 | 2684 | ||
2527 | out: | 2685 | out: |
2528 | return ret; | 2686 | return ret; |
2529 | } | 2687 | } |
2530 | 2688 | ||
2531 | int pgm_get_degree_out(node_t node) | 2689 | int pgm_get_degree_out(node_t node, int ignore_backedges) |
2532 | { | 2690 | { |
2533 | int ret = -1; | 2691 | int ret = -1; |
2534 | struct pgm_graph* g; | 2692 | struct pgm_graph* g; |
@@ -2539,9 +2697,22 @@ int pgm_get_degree_out(node_t node) | |||
2539 | 2697 | ||
2540 | g = &gGraphs[node.graph]; | 2698 | g = &gGraphs[node.graph]; |
2541 | n = &g->nodes[node.node]; | 2699 | n = &g->nodes[node.node]; |
2542 | __sync_synchronize(); | 2700 | |
2543 | ret = n->nr_out; | 2701 | pthread_mutex_lock(&g->lock); |
2544 | __sync_synchronize(); | 2702 | if(!ignore_backedges) |
2703 | { | ||
2704 | ret = n->nr_out; | ||
2705 | } | ||
2706 | else | ||
2707 | { | ||
2708 | ret = 0; | ||
2709 | for(int i = 0; i < n->nr_out; ++i) | ||
2710 | { | ||
2711 | if(!g->edges[n->out[i]].is_backedge) | ||
2712 | ++ret; | ||
2713 | } | ||
2714 | } | ||
2715 | pthread_mutex_unlock(&g->lock); | ||
2545 | 2716 | ||
2546 | out: | 2717 | out: |
2547 | return ret; | 2718 | return ret; |
@@ -2556,7 +2727,8 @@ static int dag_visit( | |||
2556 | const struct pgm_graph* const g, | 2727 | const struct pgm_graph* const g, |
2557 | const struct pgm_node* const n, | 2728 | const struct pgm_node* const n, |
2558 | std::set<std::string>& visited, | 2729 | std::set<std::string>& visited, |
2559 | std::set<std::string>& path) | 2730 | std::set<std::string>& path, |
2731 | int ignore_explicit_backedges) | ||
2560 | { | 2732 | { |
2561 | const std::string name(n->name); | 2733 | const std::string name(n->name); |
2562 | 2734 | ||
@@ -2568,6 +2740,11 @@ static int dag_visit( | |||
2568 | 2740 | ||
2569 | for(int i = 0; i < n->nr_out; ++i) | 2741 | for(int i = 0; i < n->nr_out; ++i) |
2570 | { | 2742 | { |
2743 | if(ignore_explicit_backedges && g->edges[n->out[i]].is_backedge) | ||
2744 | { | ||
2745 | continue; | ||
2746 | } | ||
2747 | |||
2571 | const struct pgm_node* const successor = | 2748 | const struct pgm_node* const successor = |
2572 | &(g->nodes[g->edges[n->out[i]].consumer]); | 2749 | &(g->nodes[g->edges[n->out[i]].consumer]); |
2573 | const std::string successor_name(successor->name); | 2750 | const std::string successor_name(successor->name); |
@@ -2577,7 +2754,7 @@ static int dag_visit( | |||
2577 | return 0; | 2754 | return 0; |
2578 | 2755 | ||
2579 | // visit successor | 2756 | // visit successor |
2580 | if(!dag_visit(g, successor, visited, path)) | 2757 | if(!dag_visit(g, successor, visited, path, ignore_explicit_backedges)) |
2581 | return 0; | 2758 | return 0; |
2582 | } | 2759 | } |
2583 | 2760 | ||
@@ -2587,7 +2764,7 @@ static int dag_visit( | |||
2587 | return 1; | 2764 | return 1; |
2588 | } | 2765 | } |
2589 | 2766 | ||
2590 | int pgm_is_dag(graph_t graph) | 2767 | int pgm_is_dag(graph_t graph, int ignore_explicit_backedges) |
2591 | { | 2768 | { |
2592 | int isDag = 1; // assume true | 2769 | int isDag = 1; // assume true |
2593 | if(!is_valid_graph(graph)) | 2770 | if(!is_valid_graph(graph)) |
@@ -2608,7 +2785,7 @@ int pgm_is_dag(graph_t graph) | |||
2608 | if(visited.find(std::string(n->name)) == visited.end()) | 2785 | if(visited.find(std::string(n->name)) == visited.end()) |
2609 | { | 2786 | { |
2610 | std::set<std::string> path; | 2787 | std::set<std::string> path; |
2611 | isDag = dag_visit(g, n, visited, path); | 2788 | isDag = dag_visit(g, n, visited, path, ignore_explicit_backedges); |
2612 | } | 2789 | } |
2613 | } | 2790 | } |
2614 | } | 2791 | } |
@@ -2649,7 +2826,7 @@ double pgm_get_max_depth(node_t target, pgm_weight_func_t wfunc, void* user) | |||
2649 | 2826 | ||
2650 | if(!is_valid_graph(target.graph)) | 2827 | if(!is_valid_graph(target.graph)) |
2651 | goto out; | 2828 | goto out; |
2652 | if(!pgm_is_dag(target.graph)) | 2829 | if(!pgm_is_dag(target.graph, true)) |
2653 | goto out; | 2830 | goto out; |
2654 | if(target.node < 0) | 2831 | if(target.node < 0) |
2655 | goto out; | 2832 | goto out; |
@@ -2668,8 +2845,11 @@ double pgm_get_max_depth(node_t target, pgm_weight_func_t wfunc, void* user) | |||
2668 | double* weights = new double[g->nr_edges]; | 2845 | double* weights = new double[g->nr_edges]; |
2669 | for(int i = 0; i < g->nr_edges; ++i) | 2846 | for(int i = 0; i < g->nr_edges; ++i) |
2670 | { | 2847 | { |
2671 | edge_array[i] = | 2848 | if(!g->edges[i].is_backedge) |
2849 | { | ||
2850 | edge_array[i] = | ||
2672 | std::make_pair(g->edges[i].producer, g->edges[i].consumer); | 2851 | std::make_pair(g->edges[i].producer, g->edges[i].consumer); |
2852 | } | ||
2673 | } | 2853 | } |
2674 | if(wfunc) | 2854 | if(wfunc) |
2675 | { | 2855 | { |
@@ -2722,7 +2902,7 @@ double pgm_get_min_depth(node_t target, pgm_weight_func_t wfunc, void* user) | |||
2722 | 2902 | ||
2723 | if(!is_valid_graph(target.graph)) | 2903 | if(!is_valid_graph(target.graph)) |
2724 | goto out; | 2904 | goto out; |
2725 | if(!pgm_is_dag(target.graph)) | 2905 | if(!pgm_is_dag(target.graph, true)) |
2726 | goto out; | 2906 | goto out; |
2727 | if(target.node < 0) | 2907 | if(target.node < 0) |
2728 | goto out; | 2908 | goto out; |
@@ -2741,8 +2921,11 @@ double pgm_get_min_depth(node_t target, pgm_weight_func_t wfunc, void* user) | |||
2741 | double* weights = new double[g->nr_edges]; | 2921 | double* weights = new double[g->nr_edges]; |
2742 | for(int i = 0; i < g->nr_edges; ++i) | 2922 | for(int i = 0; i < g->nr_edges; ++i) |
2743 | { | 2923 | { |
2744 | edge_array[i] = | 2924 | if(!g->edges[i].is_backedge) |
2925 | { | ||
2926 | edge_array[i] = | ||
2745 | std::make_pair(g->edges[i].producer, g->edges[i].consumer); | 2927 | std::make_pair(g->edges[i].producer, g->edges[i].consumer); |
2928 | } | ||
2746 | } | 2929 | } |
2747 | if(wfunc) | 2930 | if(wfunc) |
2748 | { | 2931 | { |
@@ -2842,7 +3025,8 @@ int pgm_claim_node(node_t node, pid_t tid) | |||
2842 | pthread_mutex_unlock(&g->lock); | 3025 | pthread_mutex_unlock(&g->lock); |
2843 | goto out; | 3026 | goto out; |
2844 | } | 3027 | } |
2845 | n->owner = tid; | 3028 | |
3029 | n->owner = (tid == 0) ? gettid() : tid; | ||
2846 | } | 3030 | } |
2847 | pthread_mutex_unlock(&g->lock); | 3031 | pthread_mutex_unlock(&g->lock); |
2848 | 3032 | ||
@@ -2874,7 +3058,7 @@ int pgm_claim_any_node(graph_t graph, node_t* node, pid_t tid) | |||
2874 | { | 3058 | { |
2875 | node_id = i; | 3059 | node_id = i; |
2876 | n = &g->nodes[i]; | 3060 | n = &g->nodes[i]; |
2877 | n->owner = tid; | 3061 | n->owner = (tid == 0) ? gettid() : tid; |
2878 | break; | 3062 | break; |
2879 | } | 3063 | } |
2880 | } | 3064 | } |
@@ -2908,6 +3092,11 @@ int pgm_release_node(node_t node, pid_t tid) | |||
2908 | g = &gGraphs[node.graph]; | 3092 | g = &gGraphs[node.graph]; |
2909 | n = &g->nodes[node.node]; | 3093 | n = &g->nodes[node.node]; |
2910 | 3094 | ||
3095 | if(tid == 0) | ||
3096 | { | ||
3097 | tid = gettid(); | ||
3098 | } | ||
3099 | |||
2911 | pthread_mutex_lock(&g->lock); | 3100 | pthread_mutex_lock(&g->lock); |
2912 | 3101 | ||
2913 | if(node.node < 0 || node.node >= g->nr_nodes || n->owner != tid || n->owner == UNCLAIMED_NODE) | 3102 | if(node.node < 0 || node.node >= g->nr_nodes || n->owner != tid || n->owner == UNCLAIMED_NODE) |
@@ -2966,8 +3155,11 @@ static int pgm_nr_ready_edges(struct pgm_graph* g, struct pgm_node* n) | |||
2966 | for(int i = 0; i < n->nr_in; ++i) | 3155 | for(int i = 0; i < n->nr_in; ++i) |
2967 | { | 3156 | { |
2968 | struct pgm_edge* e = &g->edges[n->in[i]]; | 3157 | struct pgm_edge* e = &g->edges[n->in[i]]; |
2969 | if(is_signal_driven(e) && (e->nr_pending >= e->attr.nr_threshold)) | 3158 | if(is_signal_driven(e) && |
3159 | ((e->nr_pending >= e->attr.nr_threshold) || (e->nr_skips > 0))) | ||
3160 | { | ||
2970 | ++nr_ready; | 3161 | ++nr_ready; |
3162 | } | ||
2971 | } | 3163 | } |
2972 | return nr_ready; | 3164 | return nr_ready; |
2973 | } | 3165 | } |
@@ -2985,7 +3177,9 @@ static eWaitStatus pgm_wait_for_tokens(struct pgm_graph* g, struct pgm_node* n) | |||
2985 | 3177 | ||
2986 | // We're out of tokens to consume. | 3178 | // We're out of tokens to consume. |
2987 | // Have we been signaled to exit? | 3179 | // Have we been signaled to exit? |
2988 | if(nr_ready == 0 && n->nr_terminate_signals == n->nr_in_signaled) | 3180 | if(nr_ready == 0 && |
3181 | n->nr_terminate_signals != 0 && | ||
3182 | n->nr_terminate_signals == (n->nr_in_signaled - n->nr_in_signaled_backedges)) | ||
2989 | { | 3183 | { |
2990 | wait_status = WaitExhaustedAndTerminate; | 3184 | wait_status = WaitExhaustedAndTerminate; |
2991 | goto out; | 3185 | goto out; |
@@ -2999,7 +3193,9 @@ static eWaitStatus pgm_wait_for_tokens(struct pgm_graph* g, struct pgm_node* n) | |||
2999 | nr_ready = pgm_nr_ready_edges(g, n); | 3193 | nr_ready = pgm_nr_ready_edges(g, n); |
3000 | if(nr_ready == n->nr_in_signaled) | 3194 | if(nr_ready == n->nr_in_signaled) |
3001 | break; | 3195 | break; |
3002 | if(nr_ready == 0 && n->nr_terminate_signals == n->nr_in_signaled) | 3196 | if(nr_ready == 0 && |
3197 | n->nr_terminate_signals != 0 && | ||
3198 | n->nr_terminate_signals == (n->nr_in_signaled - n->nr_in_signaled_backedges)) | ||
3003 | { | 3199 | { |
3004 | wait_status = WaitExhaustedAndTerminate; | 3200 | wait_status = WaitExhaustedAndTerminate; |
3005 | break; | 3201 | break; |
@@ -3013,13 +3209,27 @@ out: | |||
3013 | return wait_status; | 3209 | return wait_status; |
3014 | } | 3210 | } |
3015 | 3211 | ||
3212 | static void pgm_consume_skips(struct pgm_graph* g, struct pgm_node* n) | ||
3213 | { | ||
3214 | for(int i = 0; i < n->nr_in; ++i) | ||
3215 | { | ||
3216 | struct pgm_edge* e = &g->edges[n->in[i]]; | ||
3217 | if(e->nr_skips > 0) | ||
3218 | { | ||
3219 | e->nr_skips--; | ||
3220 | } | ||
3221 | } | ||
3222 | } | ||
3223 | |||
3016 | static void pgm_consume_tokens(struct pgm_graph* g, struct pgm_node* n) | 3224 | static void pgm_consume_tokens(struct pgm_graph* g, struct pgm_node* n) |
3017 | { | 3225 | { |
3018 | for(int i = 0; i < n->nr_in; ++i) | 3226 | for(int i = 0; i < n->nr_in; ++i) |
3019 | { | 3227 | { |
3020 | struct pgm_edge* e = &g->edges[n->in[i]]; | 3228 | struct pgm_edge* e = &g->edges[n->in[i]]; |
3021 | if(is_signal_driven(e)) | 3229 | if(is_signal_driven(e) && !(e->nr_skips)) |
3230 | { | ||
3022 | __sync_fetch_and_sub(&e->nr_pending, e->attr.nr_consume); | 3231 | __sync_fetch_and_sub(&e->nr_pending, e->attr.nr_consume); |
3232 | } | ||
3023 | } | 3233 | } |
3024 | } | 3234 | } |
3025 | 3235 | ||
@@ -3166,6 +3376,7 @@ static eWaitStatus pgm_recv_data(struct pgm_graph* g, struct pgm_node* n) | |||
3166 | 3376 | ||
3167 | eWaitStatus wait_status = WaitSuccess; | 3377 | eWaitStatus wait_status = WaitSuccess; |
3168 | pgm_fd_mask_t to_wait; | 3378 | pgm_fd_mask_t to_wait; |
3379 | pgm_fd_mask_t to_skip = 0; | ||
3169 | 3380 | ||
3170 | // Each element points to where data needs to be copied. | 3381 | // Each element points to where data needs to be copied. |
3171 | // Reads for each edge do not always read all the needed | 3382 | // Reads for each edge do not always read all the needed |
@@ -3177,15 +3388,28 @@ static eWaitStatus pgm_recv_data(struct pgm_graph* g, struct pgm_node* n) | |||
3177 | { | 3388 | { |
3178 | struct pgm_edge* e = &g->edges[n->in[i]]; | 3389 | struct pgm_edge* e = &g->edges[n->in[i]]; |
3179 | if(!is_data_passing(e)) | 3390 | if(!is_data_passing(e)) |
3391 | { | ||
3392 | continue; | ||
3393 | } | ||
3394 | if(e->nr_skips > 0) | ||
3395 | { | ||
3396 | to_skip |= ((pgm_fd_mask_t)0x1)<<i; | ||
3180 | continue; | 3397 | continue; |
3398 | } | ||
3181 | // initialize to the start of the input edge buffer | 3399 | // initialize to the start of the input edge buffer |
3182 | dest_ptrs[i] = (char*)pgm_get_user_ptr(e->buf_in); | 3400 | dest_ptrs[i] = (char*)pgm_get_user_ptr(e->buf_in); |
3183 | } | 3401 | } |
3184 | 3402 | ||
3185 | // create a bitmask for each edge to wait upon (brainfart. easier way?) | 3403 | // create a bitmask for each edge to wait upon... |
3186 | to_wait = ~((pgm_fd_mask_t)0) >> (sizeof(to_wait)*8 - n->nr_in); | 3404 | to_wait = ~((pgm_fd_mask_t)0) >> (sizeof(to_wait)*8 - n->nr_in); |
3187 | // ...but mask out the signal-driven edges | 3405 | |
3188 | to_wait &= ~(n->signal_edge_mask); | 3406 | // (don't read anything if we're skipping all the edges) |
3407 | if(to_wait == to_skip) | ||
3408 | goto out; | ||
3409 | |||
3410 | // ...but mask out the signal-driven edges and edges we're skipping | ||
3411 | to_wait &= ~(n->signal_edge_mask | to_skip); | ||
3412 | |||
3189 | 3413 | ||
3190 | wait_for_data: // jump here if we would block on read | 3414 | wait_for_data: // jump here if we would block on read |
3191 | while(to_wait) | 3415 | while(to_wait) |
@@ -3219,6 +3443,8 @@ wait_for_data: // jump here if we would block on read | |||
3219 | // skip over non-data-passing edges | 3443 | // skip over non-data-passing edges |
3220 | if(!is_data_passing(e)) | 3444 | if(!is_data_passing(e)) |
3221 | continue; | 3445 | continue; |
3446 | if(e->nr_skips > 0) | ||
3447 | continue; | ||
3222 | 3448 | ||
3223 | if(e->attr.type & __PGM_EDGE_RING) | 3449 | if(e->attr.type & __PGM_EDGE_RING) |
3224 | { | 3450 | { |
@@ -3330,10 +3556,12 @@ read_more: // jump to here if we need to read more bytes into our buffer | |||
3330 | 3556 | ||
3331 | // recompute a mask for this edge and all after i. | 3557 | // recompute a mask for this edge and all after i. |
3332 | to_wait = ~((pgm_fd_mask_t)0) >> (sizeof(to_wait)*8 - (i + 1)); | 3558 | to_wait = ~((pgm_fd_mask_t)0) >> (sizeof(to_wait)*8 - (i + 1)); |
3333 | // ...but mask out signal-driven edges | 3559 | // ...but mask out signal-driven edges and edge's we're skipping |
3334 | to_wait &= ~(n->signal_edge_mask); | 3560 | to_wait &= ~(n->signal_edge_mask | to_skip); |
3335 | // ...but still make sure that we wait for this edge, | 3561 | // ...but still make sure that we wait for this edge, |
3336 | // even if it's a singalled one. | 3562 | // even if it's a singalled one (we can't be reading an edge |
3563 | // that we're skipping since we would have skipped it and | ||
3564 | // there would have been no failure). | ||
3337 | to_wait |= ((pgm_fd_mask_t)1)<<i; | 3565 | to_wait |= ((pgm_fd_mask_t)1)<<i; |
3338 | 3566 | ||
3339 | goto wait_for_data; | 3567 | goto wait_for_data; |
@@ -3350,7 +3578,8 @@ read_more: // jump to here if we need to read more bytes into our buffer | |||
3350 | 3578 | ||
3351 | out: | 3579 | out: |
3352 | // signal terminte if everyone has checked in | 3580 | // signal terminte if everyone has checked in |
3353 | if(n->nr_terminate_msgs == n->nr_in_data) | 3581 | if(n->nr_terminate_msgs && |
3582 | (n->nr_terminate_msgs == (n->nr_in_data - n->nr_in_data_backedges))) | ||
3354 | wait_status = WaitExhaustedAndTerminate; | 3583 | wait_status = WaitExhaustedAndTerminate; |
3355 | 3584 | ||
3356 | return wait_status; | 3585 | return wait_status; |
@@ -3371,7 +3600,9 @@ int pgm_wait(node_t node) | |||
3371 | 3600 | ||
3372 | // wait to be signaled before attempting to read | 3601 | // wait to be signaled before attempting to read |
3373 | if(n->nr_in_signaled) | 3602 | if(n->nr_in_signaled) |
3603 | { | ||
3374 | token_status = pgm_wait_for_tokens(g, n); | 3604 | token_status = pgm_wait_for_tokens(g, n); |
3605 | } | ||
3375 | if(n->nr_in_data) | 3606 | if(n->nr_in_data) |
3376 | { | 3607 | { |
3377 | data_status = pgm_recv_data(g, n); | 3608 | data_status = pgm_recv_data(g, n); |
@@ -3392,6 +3623,8 @@ int pgm_wait(node_t node) | |||
3392 | if(n->nr_in_signaled && ret != PGM_TERMINATE) | 3623 | if(n->nr_in_signaled && ret != PGM_TERMINATE) |
3393 | pgm_consume_tokens(g, n); // consume the token counters | 3624 | pgm_consume_tokens(g, n); // consume the token counters |
3394 | 3625 | ||
3626 | pgm_consume_skips(g, n); // decrement skip counts | ||
3627 | |||
3395 | if(ret == PGM_TERMINATE) | 3628 | if(ret == PGM_TERMINATE) |
3396 | pgm_terminate(node); | 3629 | pgm_terminate(node); |
3397 | 3630 | ||
@@ -3415,6 +3648,11 @@ static int pgm_produce(node_t node, pgm_command_t command = PGM_NORMAL) | |||
3415 | for(int i = 0; i < n->nr_out; ++i) | 3648 | for(int i = 0; i < n->nr_out; ++i) |
3416 | { | 3649 | { |
3417 | e = &g->edges[n->out[i]]; | 3650 | e = &g->edges[n->out[i]]; |
3651 | |||
3652 | // terminate messages are not sent over backedges | ||
3653 | if((command & PGM_TERMINATE) && e->is_backedge) | ||
3654 | continue; | ||
3655 | |||
3418 | if(is_data_passing(e)) | 3656 | if(is_data_passing(e)) |
3419 | { | 3657 | { |
3420 | ret = pgm_send_data(e, command); | 3658 | ret = pgm_send_data(e, command); |