bugfix - add stl-model.h wrappers, to provide more control over STL
[cdsspec-compiler.git] / cyclegraph.cc
1 #include "cyclegraph.h"
2 #include "action.h"
3 #include "common.h"
4 #include "promise.h"
5 #include "model.h"
6 #include "threads-model.h"
7
8 /** Initializes a CycleGraph object. */
9 CycleGraph::CycleGraph() :
10         discovered(new HashTable<const CycleNode *, const CycleNode *, uintptr_t, 4, model_malloc, model_calloc, model_free>(16)),
11         queue(new ModelVector<const CycleNode *>()),
12         hasCycles(false),
13         oldCycles(false)
14 {
15 }
16
17 /** CycleGraph destructor */
18 CycleGraph::~CycleGraph()
19 {
20         delete queue;
21         delete discovered;
22 }
23
24 /**
25  * Add a CycleNode to the graph, corresponding to a store ModelAction
26  * @param act The write action that should be added
27  * @param node The CycleNode that corresponds to the store
28  */
29 void CycleGraph::putNode(const ModelAction *act, CycleNode *node)
30 {
31         actionToNode.put(act, node);
32 #if SUPPORT_MOD_ORDER_DUMP
33         nodeList.push_back(node);
34 #endif
35 }
36
37 /**
38  * Add a CycleNode to the graph, corresponding to a Promise
39  * @param promise The Promise that should be added
40  * @param node The CycleNode that corresponds to the Promise
41  */
42 void CycleGraph::putNode(const Promise *promise, CycleNode *node)
43 {
44         promiseToNode.put(promise, node);
45 #if SUPPORT_MOD_ORDER_DUMP
46         nodeList.push_back(node);
47 #endif
48 }
49
50 /**
51  * @brief Remove the Promise node from the graph
52  * @param promise The promise to remove from the graph
53  */
54 void CycleGraph::erasePromiseNode(const Promise *promise)
55 {
56         promiseToNode.put(promise, NULL);
57 #if SUPPORT_MOD_ORDER_DUMP
58         /* Remove the promise node from nodeList */
59         CycleNode *node = getNode_noCreate(promise);
60         for (unsigned int i = 0; i < nodeList.size(); )
61                 if (nodeList[i] == node)
62                         nodeList.erase(nodeList.begin() + i);
63                 else
64                         i++;
65 #endif
66 }
67
68 /** @return The corresponding CycleNode, if exists; otherwise NULL */
69 CycleNode * CycleGraph::getNode_noCreate(const ModelAction *act) const
70 {
71         return actionToNode.get(act);
72 }
73
74 /** @return The corresponding CycleNode, if exists; otherwise NULL */
75 CycleNode * CycleGraph::getNode_noCreate(const Promise *promise) const
76 {
77         return promiseToNode.get(promise);
78 }
79
80 /**
81  * @brief Returns the CycleNode corresponding to a given ModelAction
82  *
83  * Gets (or creates, if none exist) a CycleNode corresponding to a ModelAction
84  *
85  * @param action The ModelAction to find a node for
86  * @return The CycleNode paired with this action
87  */
88 CycleNode * CycleGraph::getNode(const ModelAction *action)
89 {
90         CycleNode *node = getNode_noCreate(action);
91         if (node == NULL) {
92                 node = new CycleNode(action);
93                 putNode(action, node);
94         }
95         return node;
96 }
97
98 /**
99  * @brief Returns a CycleNode corresponding to a promise
100  *
101  * Gets (or creates, if none exist) a CycleNode corresponding to a promised
102  * value.
103  *
104  * @param promise The Promise generated by a reader
105  * @return The CycleNode corresponding to the Promise
106  */
107 CycleNode * CycleGraph::getNode(const Promise *promise)
108 {
109         CycleNode *node = getNode_noCreate(promise);
110         if (node == NULL) {
111                 node = new CycleNode(promise);
112                 putNode(promise, node);
113         }
114         return node;
115 }
116
117 /**
118  * Resolve/satisfy a Promise with a particular store ModelAction, taking care
119  * of the CycleGraph cleanups, including merging any necessary CycleNodes.
120  *
121  * @param promise The Promise to resolve
122  * @param writer The store that will resolve this Promise
123  * @return false if the resolution results in a cycle (or fails in some other
124  * way); true otherwise
125  */
126 bool CycleGraph::resolvePromise(const Promise *promise, ModelAction *writer)
127 {
128         CycleNode *promise_node = promiseToNode.get(promise);
129         CycleNode *w_node = actionToNode.get(writer);
130         ASSERT(promise_node);
131
132         if (w_node)
133                 return mergeNodes(w_node, promise_node);
134         /* No existing write-node; just convert the promise-node */
135         promise_node->resolvePromise(writer);
136         erasePromiseNode(promise_node->getPromise());
137         putNode(writer, promise_node);
138         return true;
139 }
140
141 /**
142  * @brief Merge two CycleNodes that represent the same write
143  *
144  * Note that this operation cannot be rolled back.
145  *
146  * @param w_node The write ModelAction node with which to merge
147  * @param p_node The Promise node to merge. Will be destroyed after this
148  * function.
149  *
150  * @return false if the merge cannot succeed; true otherwise
151  */
152 bool CycleGraph::mergeNodes(CycleNode *w_node, CycleNode *p_node)
153 {
154         ASSERT(!w_node->is_promise());
155         ASSERT(p_node->is_promise());
156
157         const Promise *promise = p_node->getPromise();
158         if (!promise->is_compatible(w_node->getAction()) ||
159                         !promise->same_value(w_node->getAction()))
160                 return false;
161
162         /* Transfer the RMW */
163         CycleNode *promise_rmw = p_node->getRMW();
164         if (promise_rmw && promise_rmw != w_node->getRMW() && w_node->setRMW(promise_rmw))
165                 return false;
166
167         /* Transfer back edges to w_node */
168         while (p_node->getNumBackEdges() > 0) {
169                 CycleNode *back = p_node->removeBackEdge();
170                 if (back == w_node)
171                         continue;
172                 addNodeEdge(back, w_node);
173                 if (hasCycles)
174                         return false;
175         }
176
177         /* Transfer forward edges to w_node */
178         while (p_node->getNumEdges() > 0) {
179                 CycleNode *forward = p_node->removeEdge();
180                 if (forward == w_node)
181                         continue;
182                 addNodeEdge(w_node, forward);
183                 if (hasCycles)
184                         return false;
185         }
186
187         erasePromiseNode(promise);
188         /* Not deleting p_node, to maintain consistency if mergeNodes() fails */
189
190         return !hasCycles;
191 }
192
193 /**
194  * Adds an edge between two CycleNodes.
195  * @param fromnode The edge comes from this CycleNode
196  * @param tonode The edge points to this CycleNode
197  * @return True, if new edge(s) are added; otherwise false
198  */
199 bool CycleGraph::addNodeEdge(CycleNode *fromnode, CycleNode *tonode)
200 {
201         bool added;
202
203         if ((added = fromnode->addEdge(tonode))) {
204                 rollbackvector.push_back(fromnode);
205                 if (!hasCycles)
206                         hasCycles = checkReachable(tonode, fromnode);
207         }
208
209         /*
210          * If the fromnode has a rmwnode that is not the tonode, we should add
211          * an edge between its rmwnode and the tonode
212          */
213         CycleNode *rmwnode = fromnode->getRMW();
214         if (rmwnode && rmwnode != tonode) {
215                 if (rmwnode->addEdge(tonode)) {
216                         if (!hasCycles)
217                                 hasCycles = checkReachable(tonode, rmwnode);
218
219                         rollbackvector.push_back(rmwnode);
220                         added = true;
221                 }
222         }
223         return added;
224 }
225
226 /**
227  * @brief Add an edge between a write and the RMW which reads from it
228  *
229  * Handles special case of a RMW action, where the ModelAction rmw reads from
230  * the ModelAction/Promise from. The key differences are:
231  * (1) no write can occur in between the rmw and the from action.
232  * (2) Only one RMW action can read from a given write.
233  *
234  * @param from The edge comes from this ModelAction/Promise
235  * @param rmw The edge points to this ModelAction; this action must read from
236  * the ModelAction/Promise from
237  */
238 template <typename T>
239 void CycleGraph::addRMWEdge(const T *from, const ModelAction *rmw)
240 {
241         ASSERT(from);
242         ASSERT(rmw);
243
244         CycleNode *fromnode = getNode(from);
245         CycleNode *rmwnode = getNode(rmw);
246
247         /* Two RMW actions cannot read from the same write. */
248         if (fromnode->setRMW(rmwnode))
249                 hasCycles = true;
250         else
251                 rmwrollbackvector.push_back(fromnode);
252
253         /* Transfer all outgoing edges from the from node to the rmw node */
254         /* This process should not add a cycle because either:
255          * (1) The rmw should not have any incoming edges yet if it is the
256          * new node or
257          * (2) the fromnode is the new node and therefore it should not
258          * have any outgoing edges.
259          */
260         for (unsigned int i = 0; i < fromnode->getNumEdges(); i++) {
261                 CycleNode *tonode = fromnode->getEdge(i);
262                 if (tonode != rmwnode) {
263                         if (rmwnode->addEdge(tonode))
264                                 rollbackvector.push_back(rmwnode);
265                 }
266         }
267
268         addNodeEdge(fromnode, rmwnode);
269 }
270 /* Instantiate two forms of CycleGraph::addRMWEdge */
271 template void CycleGraph::addRMWEdge(const ModelAction *from, const ModelAction *rmw);
272 template void CycleGraph::addRMWEdge(const Promise *from, const ModelAction *rmw);
273
274 /**
275  * @brief Adds an edge between objects
276  *
277  * This function will add an edge between any two objects which can be
278  * associated with a CycleNode. That is, if they have a CycleGraph::getNode
279  * implementation.
280  *
281  * The object to is ordered after the object from.
282  *
283  * @param to The edge points to this object, of type T
284  * @param from The edge comes from this object, of type U
285  * @return True, if new edge(s) are added; otherwise false
286  */
287 template <typename T, typename U>
288 bool CycleGraph::addEdge(const T *from, const U *to)
289 {
290         ASSERT(from);
291         ASSERT(to);
292
293         CycleNode *fromnode = getNode(from);
294         CycleNode *tonode = getNode(to);
295
296         return addNodeEdge(fromnode, tonode);
297 }
298 /* Instantiate four forms of CycleGraph::addEdge */
299 template bool CycleGraph::addEdge(const ModelAction *from, const ModelAction *to);
300 template bool CycleGraph::addEdge(const ModelAction *from, const Promise *to);
301 template bool CycleGraph::addEdge(const Promise *from, const ModelAction *to);
302 template bool CycleGraph::addEdge(const Promise *from, const Promise *to);
303
304 #if SUPPORT_MOD_ORDER_DUMP
305
306 static void print_node(FILE *file, const CycleNode *node, int label)
307 {
308         if (node->is_promise()) {
309                 const Promise *promise = node->getPromise();
310                 int idx = model->get_promise_number(promise);
311                 fprintf(file, "P%u", idx);
312                 if (label) {
313                         int first = 1;
314                         fprintf(file, " [label=\"P%d, T", idx);
315                         for (unsigned int i = 0 ; i < model->get_num_threads(); i++)
316                                 if (promise->thread_is_available(int_to_id(i))) {
317                                         fprintf(file, "%s%u", first ? "": ",", i);
318                                         first = 0;
319                                 }
320                         fprintf(file, "\"]");
321                 }
322         } else {
323                 const ModelAction *act = node->getAction();
324                 modelclock_t idx = act->get_seq_number();
325                 fprintf(file, "N%u", idx);
326                 if (label)
327                         fprintf(file, " [label=\"N%u, T%u\"]", idx, act->get_tid());
328         }
329 }
330
331 static void print_edge(FILE *file, const CycleNode *from, const CycleNode *to, const char *prop)
332 {
333         print_node(file, from, 0);
334         fprintf(file, " -> ");
335         print_node(file, to, 0);
336         if (prop && strlen(prop))
337                 fprintf(file, " [%s]", prop);
338         fprintf(file, ";\n");
339 }
340
341 void CycleGraph::dot_print_node(FILE *file, const ModelAction *act)
342 {
343         print_node(file, getNode(act), 1);
344 }
345
346 template <typename T, typename U>
347 void CycleGraph::dot_print_edge(FILE *file, const T *from, const U *to, const char *prop)
348 {
349         CycleNode *fromnode = getNode(from);
350         CycleNode *tonode = getNode(to);
351
352         print_edge(file, fromnode, tonode, prop);
353 }
354 /* Instantiate two forms of CycleGraph::dot_print_edge */
355 template void CycleGraph::dot_print_edge(FILE *file, const Promise *from, const ModelAction *to, const char *prop);
356 template void CycleGraph::dot_print_edge(FILE *file, const ModelAction *from, const ModelAction *to, const char *prop);
357
358 void CycleGraph::dumpNodes(FILE *file) const
359 {
360         for (unsigned int i = 0; i < nodeList.size(); i++) {
361                 CycleNode *n = nodeList[i];
362                 print_node(file, n, 1);
363                 fprintf(file, ";\n");
364                 if (n->getRMW())
365                         print_edge(file, n, n->getRMW(), "style=dotted");
366                 for (unsigned int j = 0; j < n->getNumEdges(); j++)
367                         print_edge(file, n, n->getEdge(j), NULL);
368         }
369 }
370
371 void CycleGraph::dumpGraphToFile(const char *filename) const
372 {
373         char buffer[200];
374         sprintf(buffer, "%s.dot", filename);
375         FILE *file = fopen(buffer, "w");
376         fprintf(file, "digraph %s {\n", filename);
377         dumpNodes(file);
378         fprintf(file, "}\n");
379         fclose(file);
380 }
381 #endif
382
383 /**
384  * Checks whether one CycleNode can reach another.
385  * @param from The CycleNode from which to begin exploration
386  * @param to The CycleNode to reach
387  * @return True, @a from can reach @a to; otherwise, false
388  */
389 bool CycleGraph::checkReachable(const CycleNode *from, const CycleNode *to) const
390 {
391         discovered->reset();
392         queue->clear();
393         queue->push_back(from);
394         discovered->put(from, from);
395         while (!queue->empty()) {
396                 const CycleNode *node = queue->back();
397                 queue->pop_back();
398                 if (node == to)
399                         return true;
400                 for (unsigned int i = 0; i < node->getNumEdges(); i++) {
401                         CycleNode *next = node->getEdge(i);
402                         if (!discovered->contains(next)) {
403                                 discovered->put(next, next);
404                                 queue->push_back(next);
405                         }
406                 }
407         }
408         return false;
409 }
410
411 /**
412  * Checks whether one ModelAction/Promise can reach another ModelAction/Promise
413  * @param from The ModelAction or Promise from which to begin exploration
414  * @param to The ModelAction or Promise to reach
415  * @return True, @a from can reach @a to; otherwise, false
416  */
417 template <typename T, typename U>
418 bool CycleGraph::checkReachable(const T *from, const U *to) const
419 {
420         CycleNode *fromnode = getNode_noCreate(from);
421         CycleNode *tonode = getNode_noCreate(to);
422
423         if (!fromnode || !tonode)
424                 return false;
425
426         return checkReachable(fromnode, tonode);
427 }
428 /* Instantiate four forms of CycleGraph::checkReachable */
429 template bool CycleGraph::checkReachable(const ModelAction *from,
430                 const ModelAction *to) const;
431 template bool CycleGraph::checkReachable(const ModelAction *from,
432                 const Promise *to) const;
433 template bool CycleGraph::checkReachable(const Promise *from,
434                 const ModelAction *to) const;
435 template bool CycleGraph::checkReachable(const Promise *from,
436                 const Promise *to) const;
437
438 /** @return True, if the promise has failed; false otherwise */
439 bool CycleGraph::checkPromise(const ModelAction *fromact, Promise *promise) const
440 {
441         discovered->reset();
442         queue->clear();
443         CycleNode *from = actionToNode.get(fromact);
444
445         queue->push_back(from);
446         discovered->put(from, from);
447         while (!queue->empty()) {
448                 const CycleNode *node = queue->back();
449                 queue->pop_back();
450
451                 if (node->getPromise() == promise)
452                         return true;
453                 if (!node->is_promise() &&
454                                 promise->eliminate_thread(node->getAction()->get_tid()))
455                         return true;
456
457                 for (unsigned int i = 0; i < node->getNumEdges(); i++) {
458                         CycleNode *next = node->getEdge(i);
459                         if (!discovered->contains(next)) {
460                                 discovered->put(next, next);
461                                 queue->push_back(next);
462                         }
463                 }
464         }
465         return false;
466 }
467
468 void CycleGraph::startChanges()
469 {
470         ASSERT(rollbackvector.empty());
471         ASSERT(rmwrollbackvector.empty());
472         ASSERT(oldCycles == hasCycles);
473 }
474
475 /** Commit changes to the cyclegraph. */
476 void CycleGraph::commitChanges()
477 {
478         rollbackvector.clear();
479         rmwrollbackvector.clear();
480         oldCycles = hasCycles;
481 }
482
483 /** Rollback changes to the previous commit. */
484 void CycleGraph::rollbackChanges()
485 {
486         for (unsigned int i = 0; i < rollbackvector.size(); i++)
487                 rollbackvector[i]->removeEdge();
488
489         for (unsigned int i = 0; i < rmwrollbackvector.size(); i++)
490                 rmwrollbackvector[i]->clearRMW();
491
492         hasCycles = oldCycles;
493         rollbackvector.clear();
494         rmwrollbackvector.clear();
495 }
496
497 /** @returns whether a CycleGraph contains cycles. */
498 bool CycleGraph::checkForCycles() const
499 {
500         return hasCycles;
501 }
502
503 /**
504  * @brief Constructor for a CycleNode
505  * @param act The ModelAction for this node
506  */
507 CycleNode::CycleNode(const ModelAction *act) :
508         action(act),
509         promise(NULL),
510         hasRMW(NULL)
511 {
512 }
513
514 /**
515  * @brief Constructor for a Promise CycleNode
516  * @param promise The Promise which was generated
517  */
518 CycleNode::CycleNode(const Promise *promise) :
519         action(NULL),
520         promise(promise),
521         hasRMW(NULL)
522 {
523 }
524
525 /**
526  * @param i The index of the edge to return
527  * @returns The a CycleNode edge indexed by i
528  */
529 CycleNode * CycleNode::getEdge(unsigned int i) const
530 {
531         return edges[i];
532 }
533
534 /** @returns The number of edges leaving this CycleNode */
535 unsigned int CycleNode::getNumEdges() const
536 {
537         return edges.size();
538 }
539
540 CycleNode * CycleNode::getBackEdge(unsigned int i) const
541 {
542         return back_edges[i];
543 }
544
545 unsigned int CycleNode::getNumBackEdges() const
546 {
547         return back_edges.size();
548 }
549
550 /**
551  * @brief Remove an element from a vector
552  * @param v The vector
553  * @param n The element to remove
554  * @return True if the element was found; false otherwise
555  */
556 template <typename T>
557 static bool vector_remove_node(SnapVector<T>& v, const T n)
558 {
559         for (unsigned int i = 0; i < v.size(); i++) {
560                 if (v[i] == n) {
561                         v.erase(v.begin() + i);
562                         return true;
563                 }
564         }
565         return false;
566 }
567
568 /**
569  * @brief Remove a (forward) edge from this CycleNode
570  * @return The CycleNode which was popped, if one exists; otherwise NULL
571  */
572 CycleNode * CycleNode::removeEdge()
573 {
574         if (edges.empty())
575                 return NULL;
576
577         CycleNode *ret = edges.back();
578         edges.pop_back();
579         vector_remove_node(ret->back_edges, this);
580         return ret;
581 }
582
583 /**
584  * @brief Remove a (back) edge from this CycleNode
585  * @return The CycleNode which was popped, if one exists; otherwise NULL
586  */
587 CycleNode * CycleNode::removeBackEdge()
588 {
589         if (back_edges.empty())
590                 return NULL;
591
592         CycleNode *ret = back_edges.back();
593         back_edges.pop_back();
594         vector_remove_node(ret->edges, this);
595         return ret;
596 }
597
598 /**
599  * Adds an edge from this CycleNode to another CycleNode.
600  * @param node The node to which we add a directed edge
601  * @return True if this edge is a new edge; false otherwise
602  */
603 bool CycleNode::addEdge(CycleNode *node)
604 {
605         for (unsigned int i = 0; i < edges.size(); i++)
606                 if (edges[i] == node)
607                         return false;
608         edges.push_back(node);
609         node->back_edges.push_back(this);
610         return true;
611 }
612
613 /** @returns the RMW CycleNode that reads from the current CycleNode */
614 CycleNode * CycleNode::getRMW() const
615 {
616         return hasRMW;
617 }
618
619 /**
620  * Set a RMW action node that reads from the current CycleNode.
621  * @param node The RMW that reads from the current node
622  * @return True, if this node already was read by another RMW; false otherwise
623  * @see CycleGraph::addRMWEdge
624  */
625 bool CycleNode::setRMW(CycleNode *node)
626 {
627         if (hasRMW != NULL)
628                 return true;
629         hasRMW = node;
630         return false;
631 }
632
633 /**
634  * Convert a Promise CycleNode into a concrete-valued CycleNode. Should only be
635  * used when there's no existing ModelAction CycleNode for this write.
636  *
637  * @param writer The ModelAction which wrote the future value represented by
638  * this CycleNode
639  */
640 void CycleNode::resolvePromise(const ModelAction *writer)
641 {
642         ASSERT(is_promise());
643         ASSERT(promise->is_compatible(writer));
644         action = writer;
645         promise = NULL;
646         ASSERT(!is_promise());
647 }