utilize SnapshotAlloc STL allocator
[model-checker.git] / cyclegraph.cc
1 #include "cyclegraph.h"
2 #include "action.h"
3 #include "common.h"
4 #include "promise.h"
5 #include "model.h"
6
7 /** Initializes a CycleGraph object. */
8 CycleGraph::CycleGraph() :
9         hasCycles(false),
10         oldCycles(false),
11         hasRMWViolation(false),
12         oldRMWViolation(false)
13 {
14 }
15
16 /** CycleGraph destructor */
17 CycleGraph::~CycleGraph() {
18 }
19
20 /**
21  * @brief Returns the CycleNode corresponding to a given ModelAction
22  * @param action The ModelAction to find a node for
23  * @return The CycleNode paired with this action
24  */
25 CycleNode * CycleGraph::getNode(const ModelAction *action) {
26         CycleNode *node=actionToNode.get(action);
27         if (node==NULL) {
28                 node=new CycleNode(action);
29                 actionToNode.put(action, node);
30 #if SUPPORT_MOD_ORDER_DUMP
31                 nodeList.push_back(node);
32 #endif
33         }
34         return node;
35 }
36
37 /**
38  * Adds an edge between two ModelActions. The ModelAction @a to is ordered
39  * after the ModelAction @a from.
40  * @param to The edge points to this ModelAction
41  * @param from The edge comes from this ModelAction
42  */
43 void CycleGraph::addEdge(const ModelAction *from, const ModelAction *to) {
44         ASSERT(from);
45         ASSERT(to);
46
47         CycleNode *fromnode=getNode(from);
48         CycleNode *tonode=getNode(to);
49
50         if (!hasCycles) {
51                 // Reflexive edges are cycles
52                 hasCycles = (from == to);
53         }
54         if (!hasCycles) {
55                 // Check for Cycles
56                 hasCycles=checkReachable(tonode, fromnode);
57         }
58
59         if (fromnode->addEdge(tonode))
60                 rollbackvector.push_back(fromnode);
61
62
63         CycleNode * rmwnode=fromnode->getRMW();
64
65         //If the fromnode has a rmwnode that is not the tonode, we
66         //should add an edge between its rmwnode and the tonode
67
68         //If tonode is also a rmw, don't do this check as the execution is
69         //doomed and we'll catch the problem elsewhere, but we want to allow
70         //for the possibility of sending to's write value to rmwnode
71
72         if (rmwnode!=NULL&&!to->is_rmw()) {
73                 if (!hasCycles) {
74                         // Check for Cycles
75                         hasCycles=checkReachable(tonode, rmwnode);
76                 }
77
78                 if (rmwnode->addEdge(tonode))
79                         rollbackvector.push_back(rmwnode);
80         }
81 }
82
83 /** Handles special case of a RMW action.  The ModelAction rmw reads
84  *  from the ModelAction from.  The key differences are: (1) no write
85  *  can occur in between the rmw and the from action.  Only one RMW
86  *  action can read from a given write.
87  */
88 void CycleGraph::addRMWEdge(const ModelAction *from, const ModelAction *rmw) {
89         ASSERT(from);
90         ASSERT(rmw);
91
92         CycleNode *fromnode=getNode(from);
93         CycleNode *rmwnode=getNode(rmw);
94
95         /* Two RMW actions cannot read from the same write. */
96         if (fromnode->setRMW(rmwnode)) {
97                 hasRMWViolation=true;
98         } else {
99                 rmwrollbackvector.push_back(fromnode);
100         }
101
102         /* Transfer all outgoing edges from the from node to the rmw node */
103         /* This process should not add a cycle because either:
104          * (1) The rmw should not have any incoming edges yet if it is the
105          * new node or
106          * (2) the fromnode is the new node and therefore it should not
107          * have any outgoing edges.
108          */
109         std::vector<CycleNode *> * edges=fromnode->getEdges();
110         for(unsigned int i=0;i<edges->size();i++) {
111                 CycleNode * tonode=(*edges)[i];
112                 if (tonode!=rmwnode) {
113                         if (rmwnode->addEdge(tonode))
114                                 rollbackvector.push_back(rmwnode);
115                 }
116         }
117
118
119         if (!hasCycles) {
120                 // Reflexive edges are cycles
121                 hasCycles = (from == rmw);
122         }
123         if (!hasCycles) {
124                 // With promises we could be setting up a cycle here if we aren't
125                 // careful...avoid it..
126                 hasCycles=checkReachable(rmwnode, fromnode);
127         }
128         if (fromnode->addEdge(rmwnode))
129                 rollbackvector.push_back(fromnode);
130 }
131
132 #if SUPPORT_MOD_ORDER_DUMP
133 void CycleGraph::dumpNodes(FILE *file) {
134         for (unsigned int i=0;i<nodeList.size();i++) {
135                 CycleNode *cn=nodeList[i];
136                 std::vector<CycleNode *> * edges=cn->getEdges();
137                 const ModelAction *action=cn->getAction();
138                 fprintf(file, "N%u [label=\"%u, T%u\"];\n",action->get_seq_number(),action->get_seq_number(), action->get_tid());
139                 if (cn->getRMW()!=NULL) {
140                         fprintf(file, "N%u -> N%u[style=dotted];\n", action->get_seq_number(), cn->getRMW()->getAction()->get_seq_number());
141                 }
142                 for (unsigned int j=0;j<edges->size();j++) {
143                         CycleNode *dst=(*edges)[j];
144                         const ModelAction *dstaction=dst->getAction();
145                         fprintf(file, "N%u -> N%u;\n", action->get_seq_number(), dstaction->get_seq_number());
146                 }
147         }
148 }
149
150 void CycleGraph::dumpGraphToFile(const char *filename) {
151         char buffer[200];
152         sprintf(buffer, "%s.dot",filename);
153         FILE *file=fopen(buffer, "w");
154         fprintf(file, "digraph %s {\n",filename);
155         dumpNodes(file);
156         fprintf(file,"}\n");
157         fclose(file);   
158 }
159 #endif
160
161 /**
162  * Checks whether one ModelAction can reach another.
163  * @param from The ModelAction from which to begin exploration
164  * @param to The ModelAction to reach
165  * @return True, @a from can reach @a to; otherwise, false
166  */
167 bool CycleGraph::checkReachable(const ModelAction *from, const ModelAction *to) {
168         CycleNode *fromnode = actionToNode.get(from);
169         CycleNode *tonode = actionToNode.get(to);
170
171         if (!fromnode || !tonode)
172                 return false;
173
174         return checkReachable(fromnode, tonode);
175 }
176
177 /**
178  * Checks whether one CycleNode can reach another.
179  * @param from The CycleNode from which to begin exploration
180  * @param to The CycleNode to reach
181  * @return True, @a from can reach @a to; otherwise, false
182  */
183 bool CycleGraph::checkReachable(CycleNode *from, CycleNode *to) {
184         std::vector<CycleNode *, ModelAlloc<CycleNode *> > queue;
185         HashTable<CycleNode *, CycleNode *, uintptr_t, 4, model_malloc, model_calloc, model_free> discovered(64);
186
187         queue.push_back(from);
188         discovered.put(from, from);
189         while(!queue.empty()) {
190                 CycleNode * node=queue.back();
191                 queue.pop_back();
192                 if (node==to)
193                         return true;
194
195                 for(unsigned int i=0;i<node->getEdges()->size();i++) {
196                         CycleNode *next=(*node->getEdges())[i];
197                         if (!discovered.contains(next)) {
198                                 discovered.put(next,next);
199                                 queue.push_back(next);
200                         }
201                 }
202         }
203         return false;
204 }
205
206 bool CycleGraph::checkPromise(const ModelAction *fromact, Promise *promise) {
207         std::vector<CycleNode *, ModelAlloc<CycleNode *> > queue;
208         HashTable<CycleNode *, CycleNode *, uintptr_t, 4, model_malloc, model_calloc, model_free> discovered(64);
209         CycleNode *from = actionToNode.get(fromact);
210
211
212         queue.push_back(from);
213         discovered.put(from, from);
214         while(!queue.empty()) {
215                 CycleNode * node=queue.back();
216                 queue.pop_back();
217
218                 if (promise->increment_threads(node->getAction()->get_tid())) {
219                         return true;
220                 }
221
222                 for(unsigned int i=0;i<node->getEdges()->size();i++) {
223                         CycleNode *next=(*node->getEdges())[i];
224                         if (!discovered.contains(next)) {
225                                 discovered.put(next,next);
226                                 queue.push_back(next);
227                         }
228                 }
229         }
230         return false;
231 }
232
233 void CycleGraph::startChanges() {
234         ASSERT(rollbackvector.size()==0);
235         ASSERT(rmwrollbackvector.size()==0);
236         ASSERT(oldCycles==hasCycles);
237         ASSERT(oldRMWViolation==hasRMWViolation);
238 }
239
240 /** Commit changes to the cyclegraph. */
241 void CycleGraph::commitChanges() {
242         rollbackvector.resize(0);
243         rmwrollbackvector.resize(0);
244         oldCycles=hasCycles;
245         oldRMWViolation=hasRMWViolation;
246 }
247
248 /** Rollback changes to the previous commit. */
249 void CycleGraph::rollbackChanges() {
250         for (unsigned int i = 0; i < rollbackvector.size(); i++) {
251                 rollbackvector[i]->popEdge();
252         }
253
254         for (unsigned int i = 0; i < rmwrollbackvector.size(); i++) {
255                 rmwrollbackvector[i]->clearRMW();
256         }
257
258         hasCycles = oldCycles;
259         hasRMWViolation = oldRMWViolation;
260         rollbackvector.resize(0);
261         rmwrollbackvector.resize(0);
262 }
263
264 /** @returns whether a CycleGraph contains cycles. */
265 bool CycleGraph::checkForCycles() {
266         return hasCycles;
267 }
268
269 bool CycleGraph::checkForRMWViolation() {
270         return hasRMWViolation;
271 }
272
273 /**
274  * Constructor for a CycleNode.
275  * @param modelaction The ModelAction for this node
276  */
277 CycleNode::CycleNode(const ModelAction *modelaction) :
278         action(modelaction),
279         hasRMW(NULL)
280 {
281 }
282
283 /** @returns a vector of the edges from a CycleNode. */
284 std::vector<CycleNode *> * CycleNode::getEdges() {
285         return &edges;
286 }
287
288 /**
289  * Adds an edge from this CycleNode to another CycleNode.
290  * @param node The node to which we add a directed edge
291  */
292 bool CycleNode::addEdge(CycleNode *node) {
293         for(unsigned int i=0;i<edges.size();i++)
294                 if (edges[i]==node)
295                         return false;
296         edges.push_back(node);
297         return true;
298 }
299
300 /** @returns the RMW CycleNode that reads from the current CycleNode */
301 CycleNode * CycleNode::getRMW() {
302         return hasRMW;
303 }
304
305 /**
306  * Set a RMW action node that reads from the current CycleNode.
307  * @param node The RMW that reads from the current node
308  * @return True, if this node already was read by another RMW; false otherwise
309  * @see CycleGraph::addRMWEdge
310  */
311 bool CycleNode::setRMW(CycleNode *node) {
312         if (hasRMW!=NULL)
313                 return true;
314         hasRMW=node;
315         return false;
316 }