aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGlenn Elliott <gelliott@cs.unc.edu>2014-07-24 19:09:06 -0400
committerGlenn Elliott <gelliott@cs.unc.edu>2014-07-24 19:09:06 -0400
commit4f12aa3d2eb3ac041af74ba2632086545e783f3d (patch)
treed33448726c7dfd8e030960cde2dcc9ebf03abc8b
parent5692d325b5c1b443fe91b126e686b314cc313976 (diff)
Add support for backedges.
This patch adds support for explicit backedges in PGM graphs.
-rw-r--r--include/pgm.h66
-rw-r--r--src/pgm.cpp370
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 */
202int pgm_init_edge(edge_t* edge, node_t producer, node_t consumer, 202int 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 */
218int 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 */
233int pgm_find_edge(edge_t* edge, node_t producer, node_t consumer, 250int 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 */
245int pgm_find_first_edge(edge_t* edge, node_t producer, node_t consumer, 262int 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 */
271int pgm_get_successors(node_t n, node_t* successors, int len); 288int 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 */
281int pgm_get_edges_out(node_t n, edge_t* edges, int len); 298int 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 */
291int pgm_get_predecessors(node_t, node_t* predecessors, int len); 308int 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 */
301int pgm_get_edges_in(node_t n, edge_t* edges, int len); 318int 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 */
308int pgm_get_degree(node_t node); 325int 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 */
315int pgm_get_degree_in(node_t node); 332int 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 */
322int pgm_get_degree_out(node_t node); 339int 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);
351int pgm_get_edge_attrs(edge_t edge, edge_attr_t* attrs); 368int 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 */
375int 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 */
382size_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 */
379int pgm_is_dag(graph_t graph); 412int 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 */
382typedef double (*pgm_weight_func_t)(edge_t e, void* user); 415typedef 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
597int 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
562int pgm_find_edge(edge_t* edge, node_t producer, node_t consumer, 602int 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
65static __thread char errnostr_buf[80]; 67static __thread char errnostr_buf[80];
66 68
69static 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, ...) \
69do { \ 77do { \
@@ -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
1917int pgm_init_edge(edge_t* edge, 1936static 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
2065int 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
2030int pgm_init_edge(edge_t* edge, node_t producer, node_t consumer, 2073int 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
2082int 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
2090int 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
2250int pgm_get_successors(node_t node, node_t* successors, int len) 2311int 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 }
2278out_unlock: 2348out_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
2284int pgm_get_edges_out(node_t node, edge_t* edges, int len) 2354int 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 }
2311out_unlock: 2390out_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
2317int pgm_get_predecessors(node_t node, node_t* predecessors, int len) 2396int 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 }
2345out_unlock: 2433out_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
2351int pgm_get_edges_in(node_t node, edge_t* edges, int len) 2439int 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 }
2378out_unlock: 2475out_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
2544int 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
2555out:
2556 return is_be;
2557}
2558
2559size_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
2571out:
2572 return remaining;
2573}
2574
2447int pgm_get_nr_produce(edge_t edge) 2575int 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
2492int pgm_get_degree(node_t node) 2620int 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
2508out: 2653out:
2509 return ret; 2654 return ret;
2510} 2655}
2511 2656
2512int pgm_get_degree_in(node_t node) 2657int 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
2527out: 2685out:
2528 return ret; 2686 return ret;
2529} 2687}
2530 2688
2531int pgm_get_degree_out(node_t node) 2689int 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
2546out: 2717out:
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
2590int pgm_is_dag(graph_t graph) 2767int 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
3212static 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
3016static void pgm_consume_tokens(struct pgm_graph* g, struct pgm_node* n) 3224static 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
3190wait_for_data: // jump here if we would block on read 3414wait_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
3351out: 3579out:
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);