promise: associate Promises with a set of threads
authorBrian Norris <banorris@uci.edu>
Thu, 24 Jan 2013 02:43:14 +0000 (18:43 -0800)
committerBrian Norris <banorris@uci.edu>
Thu, 24 Jan 2013 02:43:14 +0000 (18:43 -0800)
A Promise can be associated with a set of threads, so that we can
perform elimination more efficiently and precisely.

model.cc
promise.cc
promise.h

index c707ff8771b023d0f4b71b259e42dce77b7105e6..9aaab916849f466d66578d42108e55c1567ba41f 100644 (file)
--- a/model.cc
+++ b/model.cc
@@ -2475,7 +2475,7 @@ void ModelChecker::mo_check_promises(thread_id_t tid, const ModelAction *write,
                }
 
                // Don't do any lookups twice for the same thread
-               if (promise->thread_is_eliminated(tid))
+               if (!promise->thread_is_available(tid))
                        continue;
 
                if (promise->get_write() && mo_graph->checkReachable(promise->get_write(), write)) {
index 016b809aefaacf0d6e38e0674e60b89503bb3d31..e3b8d65e48d7c542bcf7e27da0473bb012a39057 100644 (file)
@@ -1,3 +1,6 @@
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
+
 #include "promise.h"
 #include "model.h"
 #include "schedule.h"
 bool Promise::eliminate_thread(thread_id_t tid)
 {
        unsigned int id = id_to_int(tid);
-       if (id >= eliminated_thread.size())
-               eliminated_thread.resize(id + 1, false);
-       if (eliminated_thread[id])
+       if (!thread_is_available(tid))
                return false;
 
-       eliminated_thread[id] = true;
+       available_thread[id] = false;
+       num_available_threads--;
        return has_failed();
 }
 
 /**
- * Check if a thread has already been eliminated from resolving this
- * promise
+ * Add a thread which may resolve this promise
+ *
+ * @param tid The thread ID
+ */
+void Promise::add_thread(thread_id_t tid)
+{
+       unsigned int id = id_to_int(tid);
+       if (id >= available_thread.size())
+               available_thread.resize(id + 1, false);
+       if (!available_thread[id]) {
+               available_thread[id] = true;
+               num_available_threads++;
+       }
+}
+
+/**
+ * Check if a thread is available for resolving this promise. That is, the
+ * thread must have been previously marked for resolving this promise, and it
+ * cannot have been eliminated due to synchronization, etc.
+ *
  * @param tid Thread ID of the thread to check
- * @return True if the thread is already eliminated; false otherwise
+ * @return True if the thread is available; false otherwise
  */
-bool Promise::thread_is_eliminated(thread_id_t tid) const
+bool Promise::thread_is_available(thread_id_t tid) const
 {
        unsigned int id = id_to_int(tid);
-       if (id >= eliminated_thread.size())
+       if (id >= available_thread.size())
                return false;
-       return eliminated_thread[id];
+       return available_thread[id];
+}
+
+/** @brief Print debug info about the Promise */
+void Promise::print() const
+{
+       model_print("Promised value %#" PRIx64 ", read from thread %d, available threads to resolve: ", value, read->get_tid());
+       for (unsigned int i = 0; i < available_thread.size(); i++)
+               if (available_thread[i])
+                       model_print("[%d]", i);
+       model_print("\n");
 }
 
 /**
@@ -44,10 +74,11 @@ bool Promise::thread_is_eliminated(thread_id_t tid) const
  */
 bool Promise::has_failed() const
 {
-       for (unsigned int i = 1; i < model->get_num_threads(); i++) {
+       for (unsigned int i = 0; i < available_thread.size(); i++) {
                thread_id_t tid = int_to_id(i);
-               if (!thread_is_eliminated(tid) && model->is_enabled(tid))
+               if (thread_is_available(tid) && model->is_enabled(tid))
                        return false;
        }
+       ASSERT(num_available_threads == 0);
        return true;
 }
index 3c0d5dddd7330e33f06bbc9c2a21320963e6fc4c..35515d24b2da913b387e5ec06b786a83e3d43877 100644 (file)
--- a/promise.h
+++ b/promise.h
@@ -22,25 +22,36 @@ struct future_value {
 class Promise {
  public:
        Promise(ModelAction *act, struct future_value fv) :
+               num_available_threads(0),
                value(fv.value),
                expiration(fv.expiration),
                read(act),
                write(NULL)
        {
+               add_thread(fv.tid);
                eliminate_thread(act->get_tid());
        }
        modelclock_t get_expiration() const { return expiration; }
        ModelAction * get_action() const { return read; }
        bool eliminate_thread(thread_id_t tid);
-       bool thread_is_eliminated(thread_id_t tid) const;
+       void add_thread(thread_id_t tid);
+       bool thread_is_available(thread_id_t tid) const;
        bool has_failed() const;
        uint64_t get_value() const { return value; }
        void set_write(const ModelAction *act) { write = act; }
        const ModelAction * get_write() { return write; }
+       int get_num_available_threads() { return num_available_threads; }
+
+       void print() const;
 
        SNAPSHOTALLOC
  private:
-       std::vector< bool, SnapshotAlloc<bool> > eliminated_thread;
+       /** @brief Thread ID(s) for thread(s) that potentially can satisfy this
+        *  promise */
+       std::vector< bool, SnapshotAlloc<bool> > available_thread;
+
+       int num_available_threads;
+
        const uint64_t value;
        const modelclock_t expiration;
        ModelAction * const read;