nodestack: spacing
[model-checker.git] / nodestack.cc
1 #include <string.h>
2
3 #include "nodestack.h"
4 #include "action.h"
5 #include "common.h"
6 #include "model.h"
7 #include "threads-model.h"
8
9 /**
10  * @brief Node constructor
11  *
12  * Constructs a single Node for use in a NodeStack. Each Node is associated
13  * with exactly one ModelAction (exception: the first Node should be created
14  * as an empty stub, to represent the first thread "choice") and up to one
15  * parent.
16  *
17  * @param act The ModelAction to associate with this Node. May be NULL.
18  * @param par The parent Node in the NodeStack. May be NULL if there is no
19  * parent.
20  * @param nthreads The number of threads which exist at this point in the
21  * execution trace.
22  */
23 Node::Node(ModelAction *act, Node *par, int nthreads, Node *prevfairness)
24         : action(act),
25         parent(par),
26         num_threads(nthreads),
27         explored_children(num_threads),
28         backtrack(num_threads),
29         fairness(num_threads),
30         numBacktracks(0),
31         enabled_array(NULL),
32         may_read_from(),
33         read_from_index(0),
34         future_values(),
35         future_index(-1),
36         relseq_break_writes(),
37         relseq_break_index(0),
38         misc_index(0),
39         misc_max(0)
40 {
41         if (act) {
42                 act->set_node(this);
43                 int currtid = id_to_int(act->get_tid());
44                 int prevtid = (prevfairness != NULL) ? id_to_int(prevfairness->action->get_tid()) : 0;
45                 
46                 if (model->params.fairwindow != 0) {
47                         for (int i = 0; i < nthreads; i++) {
48                                 ASSERT(i < ((int)fairness.size()));
49                                 struct fairness_info *fi = &fairness[i];
50                                 struct fairness_info *prevfi = (par != NULL) && (i < par->get_num_threads()) ? &par->fairness[i] : NULL;
51                                 if (prevfi) {
52                                         *fi = *prevfi;
53                                 }
54                                 if (parent->is_enabled(int_to_id(i))) {
55                                         fi->enabled_count++;
56                                 }
57                                 if (i == currtid) {
58                                         fi->turns++;
59                                         fi->priority = false;
60                                 }
61                                 /* Do window processing */
62                                 if (prevfairness != NULL) {
63                                         if (prevfairness->parent->is_enabled(int_to_id(i)))
64                                                 fi->enabled_count--;
65                                         if (i == prevtid) {
66                                                 fi->turns--;
67                                         }
68                                         /* Need full window to start evaluating
69                                          * conditions
70                                          * If we meet the enabled count and
71                                          * have no turns, give us priority */
72                                         if ((fi->enabled_count >= model->params.enabledcount) &&
73                                                         (fi->turns == 0))
74                                                 fi->priority = true;
75                                 }
76                         }
77                 }
78         }
79 }
80
81 /** @brief Node desctructor */
82 Node::~Node()
83 {
84         if (action)
85                 delete action;
86         if (enabled_array)
87                 model_free(enabled_array);
88 }
89
90 /** Prints debugging info for the ModelAction associated with this Node */
91 void Node::print()
92 {
93         if (action)
94                 action->print();
95         else
96                 model_print("******** empty action ********\n");
97 }
98
99 /** @brief Prints info about may_read_from set */
100 void Node::print_may_read_from()
101 {
102         for (unsigned int i = 0; i < may_read_from.size(); i++)
103                 may_read_from[i]->print();
104 }
105
106 /**
107  * Sets a promise to explore meeting with the given node.
108  * @param i is the promise index.
109  */
110 void Node::set_promise(unsigned int i, bool is_rmw) {
111         if (i >= promises.size())
112                 promises.resize(i + 1, PROMISE_IGNORE);
113         if (promises[i] == PROMISE_IGNORE) {
114                 promises[i] = PROMISE_UNFULFILLED;
115                 if (is_rmw)
116                         promises[i] |= PROMISE_RMW;
117         }
118 }
119
120 /**
121  * Looks up whether a given promise should be satisfied by this node.
122  * @param i The promise index.
123  * @return true if the promise should be satisfied by the given model action.
124  */
125 bool Node::get_promise(unsigned int i) const
126 {
127         return (i < promises.size()) && ((promises[i] & PROMISE_MASK) == PROMISE_FULFILLED);
128 }
129
130 /**
131  * Increments to the next combination of promises.
132  * @return true if we have a valid combination.
133  */
134 bool Node::increment_promise() {
135         DBG();
136         unsigned int rmw_count = 0;
137         for (unsigned int i = 0; i < promises.size(); i++) {
138                 if (promises[i] == (PROMISE_RMW|PROMISE_FULFILLED))
139                         rmw_count++;
140         }
141         
142         for (unsigned int i = 0; i < promises.size(); i++) {
143                 if ((promises[i] & PROMISE_MASK) == PROMISE_UNFULFILLED) {
144                         if ((rmw_count > 0) && (promises[i] & PROMISE_RMW)) {
145                                 //sending our value to two rmws... not going to work..try next combination
146                                 continue;
147                         }
148                         promises[i] = (promises[i] & PROMISE_RMW) |PROMISE_FULFILLED;
149                         while (i > 0) {
150                                 i--;
151                                 if ((promises[i] & PROMISE_MASK) == PROMISE_FULFILLED)
152                                         promises[i] = (promises[i] & PROMISE_RMW) | PROMISE_UNFULFILLED;
153                         }
154                         return true;
155                 } else if (promises[i] == (PROMISE_RMW|PROMISE_FULFILLED)) {
156                         rmw_count--;
157                 }
158         }
159         return false;
160 }
161
162 /**
163  * Returns whether the promise set is empty.
164  * @return true if we have explored all promise combinations.
165  */
166 bool Node::promise_empty() const
167 {
168         bool fulfilledrmw = false;
169         for (int i = promises.size() - 1 ; i >= 0; i--) {
170                 if (promises[i] == PROMISE_UNFULFILLED)
171                         return false;
172                 if (!fulfilledrmw && ((promises[i]&PROMISE_MASK) == PROMISE_UNFULFILLED))
173                         return false;
174                 if (promises[i] == (PROMISE_FULFILLED|PROMISE_RMW))
175                         fulfilledrmw = true;
176         }
177         return true;
178 }
179
180
181 void Node::set_misc_max(int i)
182 {
183         misc_max = i;
184 }
185
186 int Node::get_misc() const
187 {
188         return misc_index;
189 }
190
191 bool Node::increment_misc() {
192         return (misc_index<misc_max)&&((++misc_index)<misc_max);
193 }
194
195 bool Node::misc_empty() const
196 {
197         return (misc_index + 1) >= misc_max;
198 }
199
200
201 /**
202  * Adds a value from a weakly ordered future write to backtrack to. This
203  * operation may "fail" if the future value has already been run (within some
204  * sloppiness window of this expiration), or if the futurevalues set has
205  * reached its maximum.
206  * @see model_params.maxfuturevalues
207  *
208  * @param value is the value to backtrack to.
209  * @return True if the future value was successully added; false otherwise
210  */
211 bool Node::add_future_value(uint64_t value, modelclock_t expiration) {
212         int idx = -1; /* Highest index where value is found */
213         for (unsigned int i = 0; i < future_values.size(); i++) {
214                 if (future_values[i].value == value) {
215                         if (expiration <= future_values[i].expiration)
216                                 return false;
217                         idx = i;
218                 }
219         }
220         if (idx > future_index) {
221                 /* Future value hasn't been explored; update expiration */
222                 future_values[idx].expiration = expiration;
223                 return true;
224         } else if (idx >= 0 && expiration <= future_values[idx].expiration + model->params.expireslop) {
225                 /* Future value has been explored and is within the "sloppy" window */
226                 return false;
227         }
228
229         /* Limit the size of the future-values set */
230         if (model->params.maxfuturevalues > 0 &&
231                         (int)future_values.size() >= model->params.maxfuturevalues)
232                 return false;
233
234         struct future_value newfv = {value, expiration};
235         future_values.push_back(newfv);
236         return true;
237 }
238
239 /**
240  * Checks whether the future_values set for this node is empty.
241  * @return true if the future_values set is empty.
242  */
243 bool Node::future_value_empty() const
244 {
245         return ((future_index + 1) >= ((int)future_values.size()));
246 }
247
248 /**
249  * Checks if the Thread associated with this thread ID has been explored from
250  * this Node already.
251  * @param tid is the thread ID to check
252  * @return true if this thread choice has been explored already, false
253  * otherwise
254  */
255 bool Node::has_been_explored(thread_id_t tid) const
256 {
257         int id = id_to_int(tid);
258         return explored_children[id];
259 }
260
261 /**
262  * Checks if the backtracking set is empty.
263  * @return true if the backtracking set is empty
264  */
265 bool Node::backtrack_empty() const
266 {
267         return (numBacktracks == 0);
268 }
269
270 /**
271  * Checks whether the readsfrom set for this node is empty.
272  * @return true if the readsfrom set is empty.
273  */
274 bool Node::read_from_empty() const
275 {
276         return ((read_from_index + 1) >= may_read_from.size());
277 }
278
279 /**
280  * Mark the appropriate backtracking information for exploring a thread choice.
281  * @param act The ModelAction to explore
282  */
283 void Node::explore_child(ModelAction *act, enabled_type_t * is_enabled)
284 {
285         if (!enabled_array)
286                 enabled_array = (enabled_type_t *)model_malloc(sizeof(enabled_type_t) * num_threads);
287         if (is_enabled != NULL)
288                 memcpy(enabled_array, is_enabled, sizeof(enabled_type_t)*num_threads);
289         else {
290                 for(int i = 0; i < num_threads; i++)
291                         enabled_array[i] = THREAD_DISABLED;
292         }
293
294         explore(act->get_tid());
295 }
296
297 /**
298  * Records a backtracking reference for a thread choice within this Node.
299  * Provides feedback as to whether this thread choice is already set for
300  * backtracking.
301  * @return false if the thread was already set to be backtracked, true
302  * otherwise
303  */
304 bool Node::set_backtrack(thread_id_t id)
305 {
306         int i = id_to_int(id);
307         ASSERT(i<((int)backtrack.size()));
308         if (backtrack[i])
309                 return false;
310         backtrack[i] = true;
311         numBacktracks++;
312         return true;
313 }
314
315 thread_id_t Node::get_next_backtrack()
316 {
317         /** @todo Find next backtrack */
318         unsigned int i;
319         for (i = 0; i < backtrack.size(); i++)
320                 if (backtrack[i] == true)
321                         break;
322         /* Backtrack set was empty? */
323         ASSERT(i != backtrack.size());
324
325         backtrack[i] = false;
326         numBacktracks--;
327         return int_to_id(i);
328 }
329
330 bool Node::is_enabled(Thread *t) const
331 {
332         int thread_id = id_to_int(t->get_id());
333         return thread_id < num_threads && (enabled_array[thread_id] != THREAD_DISABLED);
334 }
335
336 enabled_type_t Node::enabled_status(thread_id_t tid) const
337 {
338         int thread_id = id_to_int(tid);
339         if (thread_id < num_threads)
340                 return enabled_array[thread_id];
341         else
342                 return THREAD_DISABLED;
343 }
344
345 bool Node::is_enabled(thread_id_t tid) const
346 {
347         int thread_id = id_to_int(tid);
348         return thread_id < num_threads && (enabled_array[thread_id] != THREAD_DISABLED);
349 }
350
351 bool Node::has_priority(thread_id_t tid) const
352 {
353         return fairness[id_to_int(tid)].priority;
354 }
355
356 /**
357  * Add an action to the may_read_from set.
358  * @param act is the action to add
359  */
360 void Node::add_read_from(const ModelAction *act)
361 {
362         may_read_from.push_back(act);
363 }
364
365 /**
366  * Gets the next 'future_value' value from this Node. Only valid for a node
367  * where this->action is a 'read'.
368  * @return The first element in future_values
369  */
370 uint64_t Node::get_future_value() const
371 {
372         ASSERT(future_index >= 0 && future_index<((int)future_values.size()));
373         return future_values[future_index].value;
374 }
375
376 modelclock_t Node::get_future_value_expiration() const
377 {
378         ASSERT(future_index >= 0 && future_index<((int)future_values.size()));
379         return future_values[future_index].expiration;
380 }
381
382
383 int Node::get_read_from_size() const
384 {
385         return may_read_from.size();
386 }
387
388 const ModelAction * Node::get_read_from_at(int i) {
389         return may_read_from[i];
390 }
391
392 /**
393  * Gets the next 'may_read_from' action from this Node. Only valid for a node
394  * where this->action is a 'read'.
395  * @return The first element in may_read_from
396  */
397 const ModelAction * Node::get_read_from() const
398 {
399         if (read_from_index < may_read_from.size())
400                 return may_read_from[read_from_index];
401         else
402                 return NULL;
403 }
404
405 /**
406  * Increments the index into the readsfrom set to explore the next item.
407  * @return Returns false if we have explored all items.
408  */
409 bool Node::increment_read_from() {
410         DBG();
411         promises.clear();
412         if (read_from_index < may_read_from.size()) {
413                 read_from_index++;
414                 return read_from_index < may_read_from.size();
415         }
416         return false;
417 }
418
419 /**
420  * Increments the index into the future_values set to explore the next item.
421  * @return Returns false if we have explored all values.
422  */
423 bool Node::increment_future_value() {
424         DBG();
425         promises.clear();
426         if (future_index < ((int)future_values.size())) {
427                 future_index++;
428                 return (future_index < ((int)future_values.size()));
429         }
430         return false;
431 }
432
433 /**
434  * Add a write ModelAction to the set of writes that may break the release
435  * sequence. This is used during replay exploration of pending release
436  * sequences. This Node must correspond to a release sequence fixup action.
437  *
438  * @param write The write that may break the release sequence. NULL means we
439  * allow the release sequence to synchronize.
440  */
441 void Node::add_relseq_break(const ModelAction *write)
442 {
443         relseq_break_writes.push_back(write);
444 }
445
446 /**
447  * Get the write that may break the current pending release sequence,
448  * according to the replay / divergence pattern.
449  *
450  * @return A write that may break the release sequence. If NULL, that means
451  * the release sequence should not be broken.
452  */
453 const ModelAction * Node::get_relseq_break() const
454 {
455         if (relseq_break_index < (int)relseq_break_writes.size())
456                 return relseq_break_writes[relseq_break_index];
457         else
458                 return NULL;
459 }
460
461 /**
462  * Increments the index into the relseq_break_writes set to explore the next
463  * item.
464  * @return Returns false if we have explored all values.
465  */
466 bool Node::increment_relseq_break()
467 {
468         DBG();
469         promises.clear();
470         if (relseq_break_index < ((int)relseq_break_writes.size())) {
471                 relseq_break_index++;
472                 return (relseq_break_index < ((int)relseq_break_writes.size()));
473         }
474         return false;
475 }
476
477 /**
478  * @return True if all writes that may break the release sequence have been
479  * explored
480  */
481 bool Node::relseq_break_empty() const
482 {
483         return ((relseq_break_index + 1) >= ((int)relseq_break_writes.size()));
484 }
485
486 void Node::explore(thread_id_t tid)
487 {
488         int i = id_to_int(tid);
489         ASSERT(i<((int)backtrack.size()));
490         if (backtrack[i]) {
491                 backtrack[i] = false;
492                 numBacktracks--;
493         }
494         explored_children[i] = true;
495 }
496
497 NodeStack::NodeStack() :
498         node_list(1, new Node()),
499         iter(0),
500         total_nodes(0)
501 {
502         total_nodes++;
503 }
504
505 NodeStack::~NodeStack()
506 {
507         for (unsigned int i = 0; i < node_list.size(); i++)
508                 delete node_list[i];
509 }
510
511 void NodeStack::print() const
512 {
513         model_print("............................................\n");
514         model_print("NodeStack printing node_list:\n");
515         for (unsigned int it = 0; it < node_list.size(); it++) {
516                 if (it == this->iter)
517                         model_print("vvv following action is the current iterator vvv\n");
518                 node_list[it]->print();
519         }
520         model_print("............................................\n");
521 }
522
523 /** Note: The is_enabled set contains what actions were enabled when
524  *  act was chosen. */
525 ModelAction * NodeStack::explore_action(ModelAction *act, enabled_type_t *is_enabled)
526 {
527         DBG();
528
529         ASSERT(!node_list.empty());
530
531         if ((iter + 1) < node_list.size()) {
532                 iter++;
533                 return node_list[iter]->get_action();
534         }
535
536         /* Record action */
537         get_head()->explore_child(act, is_enabled);
538         Node *prevfairness = NULL;
539         if (model->params.fairwindow != 0 && iter > model->params.fairwindow)
540                 prevfairness = node_list[iter - model->params.fairwindow];
541         node_list.push_back(new Node(act, get_head(), model->get_num_threads(), prevfairness));
542         total_nodes++;
543         iter++;
544         return NULL;
545 }
546
547 /**
548  * Empties the stack of all trailing nodes after a given position and calls the
549  * destructor for each. This function is provided an offset which determines
550  * how many nodes (relative to the current replay state) to save before popping
551  * the stack.
552  * @param numAhead gives the number of Nodes (including this Node) to skip over
553  * before removing nodes.
554  */
555 void NodeStack::pop_restofstack(int numAhead)
556 {
557         /* Diverging from previous execution; clear out remainder of list */
558         unsigned int it = iter + numAhead;
559         for(unsigned int i = it; i < node_list.size(); i++)
560                 delete node_list[i];
561         node_list.resize(it);
562 }
563
564 Node * NodeStack::get_head() const
565 {
566         if (node_list.empty())
567                 return NULL;
568         return node_list[iter];
569 }
570
571 Node * NodeStack::get_next() const
572 {
573         if (node_list.empty()) {
574                 DEBUG("Empty\n");
575                 return NULL;
576         }
577         unsigned int it = iter + 1;
578         if (it == node_list.size()) {
579                 DEBUG("At end\n");
580                 return NULL;
581         }
582         return node_list[it];
583 }
584
585 void NodeStack::reset_execution()
586 {
587         iter = 0;
588 }