Merge branch 'norris'
authorBrian Norris <banorris@uci.edu>
Fri, 14 Sep 2012 18:25:59 +0000 (11:25 -0700)
committerBrian Norris <banorris@uci.edu>
Fri, 14 Sep 2012 18:25:59 +0000 (11:25 -0700)
12 files changed:
.gitignore
action.cc
action.h
cmodelint.cc
cmodelint.h
config.h
cyclegraph.cc
cyclegraph.h
include/impatomic.h
model.cc
model.h
test/rmwprog.c

index 2ac6f537e490b9c4502b89e973cdfbf4cb21e574..dafb8c37ae227c5a6177d72cafbe07a1efad289a 100644 (file)
@@ -4,6 +4,7 @@
 *.swo
 *.so
 *~
+*.dot
 
 # files in this directory
 /tags
index 5d726a2a0514f1c63c66fc3604ec8409fe0ba8cb..1e28264fbcedf171c673bace33be6f41c3aa3f35 100644 (file)
--- a/action.cc
+++ b/action.cc
@@ -52,6 +52,11 @@ bool ModelAction::is_rmwc() const
        return type == ATOMIC_RMWC;
 }
 
+bool ModelAction::is_fence() const 
+{
+       return type == ATOMIC_FENCE;
+}
+
 bool ModelAction::is_initialization() const
 {
        return type == ATOMIC_INIT;
@@ -230,6 +235,9 @@ void ModelAction::print(void) const
        case ATOMIC_RMW:
                type_str = "atomic rmw";
                break;
+       case ATOMIC_FENCE:
+               type_str = "fence";
+               break;
        case ATOMIC_RMWR:
                type_str = "atomic rmwr";
                break;
index 3e590aae7f34a115cefb9fafed941a91d3bc5f92..9fa7a91c3f93443714f54ec34b153c4d09a1c20b 100644 (file)
--- a/action.h
+++ b/action.h
@@ -38,8 +38,9 @@ typedef enum action_type {
        ATOMIC_RMWR,          /**< The read part of an atomic RMW action */
        ATOMIC_RMW,           /**< The write part of an atomic RMW action */
        ATOMIC_RMWC,          /**< Convert an atomic RMW action into a READ */
-       ATOMIC_INIT           /**< Initialization of an atomic object (e.g.,
+       ATOMIC_INIT,          /**< Initialization of an atomic object (e.g.,
                               *   atomic_init()) */
+       ATOMIC_FENCE
 } action_type_t;
 
 /* Forward declaration */
@@ -71,6 +72,7 @@ public:
        bool is_rmwr() const;
        bool is_rmwc() const;
        bool is_rmw() const;
+       bool is_fence() const;
        bool is_initialization() const;
        bool is_acquire() const;
        bool is_release() const;
index 8919041be4589670d228ad3e3e7b00b7132a5f2b..228c40f9ec8d02b1a7b9c599a6cf69fc1c4ebf78 100644 (file)
@@ -36,3 +36,8 @@ void model_rmw_action(void *obj, memory_order ord, uint64_t val) {
 void model_rmwc_action(void *obj, memory_order ord) {
        model->switch_to_master(new ModelAction(ATOMIC_RMWC, ord, obj));
 }
+
+/** Issues a fence operation. */
+void model_fence_action(memory_order ord) {
+       model->switch_to_master(new ModelAction(ATOMIC_FENCE, ord, NULL));
+}
index c23c061221c7dfc3f8254fa99acacc3eb3c539b8..232648cd588ef8c4c69a752b3899d5a1572b510e 100644 (file)
@@ -17,6 +17,7 @@ void model_init_action(void * obj, uint64_t val);
 uint64_t model_rmwr_action(void *obj, memory_order ord);
 void model_rmw_action(void *obj, memory_order ord, uint64_t val);
 void model_rmwc_action(void *obj, memory_order ord);
+void model_fence_action(memory_order ord);
 
 
 #if __cplusplus
index 1d0b6380345af93e53a1f166bfc2c661778e3ee1..ab54e3abe68e12e8199976dfb415d188dff54258 100644 (file)
--- a/config.h
+++ b/config.h
@@ -11,6 +11,9 @@
                #endif
 */
 
+/** Turn on support for dumping cyclegraphs as dot files at each
+ *  printed summary.*/
+#define SUPPORT_MOD_ORDER_DUMP 0
 
 /** Do we have a 48 bit virtual address (64 bit machine) or 32 bit addresses.
  * Set to 1 for 48-bit, 0 for 32-bit. */
index 26235d651e10ecb5e2178d281048ea6ce5007893..ecf8a781c2770ebd09766cff47030e3e094bd2d7 100644 (file)
@@ -25,6 +25,9 @@ CycleNode * CycleGraph::getNode(const ModelAction *action) {
        if (node==NULL) {
                node=new CycleNode(action);
                actionToNode.put(action, node);
+#if SUPPORT_MOD_ORDER_DUMP
+               nodeList.push_back(node);
+#endif
        }
        return node;
 }
@@ -47,8 +50,9 @@ void CycleGraph::addEdge(const ModelAction *from, const ModelAction *to) {
                hasCycles=checkReachable(tonode, fromnode);
        }
 
-       rollbackvector.push_back(fromnode);
-       fromnode->addEdge(tonode);
+       if (fromnode->addEdge(tonode))
+               rollbackvector.push_back(fromnode);
+
 
        CycleNode * rmwnode=fromnode->getRMW();
 
@@ -64,8 +68,9 @@ void CycleGraph::addEdge(const ModelAction *from, const ModelAction *to) {
                        // Check for Cycles
                        hasCycles=checkReachable(tonode, rmwnode);
                }
-               rollbackvector.push_back(rmwnode);
-               rmwnode->addEdge(tonode);
+
+               if (rmwnode->addEdge(tonode))
+                       rollbackvector.push_back(rmwnode);
        }
 }
 
@@ -99,19 +104,45 @@ void CycleGraph::addRMWEdge(const ModelAction *from, const ModelAction *rmw) {
        for(unsigned int i=0;i<edges->size();i++) {
                CycleNode * tonode=(*edges)[i];
                if (tonode!=rmwnode) {
-                       rollbackvector.push_back(rmwnode);
-                       rmwnode->addEdge(tonode);
+                       if (rmwnode->addEdge(tonode))
+                               rollbackvector.push_back(rmwnode);
                }
        }
-       rollbackvector.push_back(fromnode);
+
 
        if (!hasCycles) {
                // With promises we could be setting up a cycle here if we aren't
                // careful...avoid it..
                hasCycles=checkReachable(rmwnode, fromnode);
        }
-       fromnode->addEdge(rmwnode);
+       if(fromnode->addEdge(rmwnode))
+               rollbackvector.push_back(fromnode);
+}
+
+#if SUPPORT_MOD_ORDER_DUMP
+void CycleGraph::dumpGraphToFile(const char *filename) {
+       char buffer[200];
+  sprintf(buffer, "%s.dot",filename);
+  FILE *file=fopen(buffer, "w");
+  fprintf(file, "digraph %s {\n",filename);
+  for(unsigned int i=0;i<nodeList.size();i++) {
+               CycleNode *cn=nodeList[i];
+               std::vector<CycleNode *> * edges=cn->getEdges();
+               const ModelAction *action=cn->getAction();
+               fprintf(file, "N%u [label=\"%u, T%u\"];\n",action->get_seq_number(),action->get_seq_number(), action->get_tid());
+               if (cn->getRMW()!=NULL) {
+                       fprintf(file, "N%u -> N%u[style=dotted];\n", action->get_seq_number(), cn->getRMW()->getAction()->get_seq_number());
+               }
+               for(unsigned int j=0;j<edges->size();j++) {
+                 CycleNode *dst=(*edges)[j];
+                       const ModelAction *dstaction=dst->getAction();
+      fprintf(file, "N%u -> N%u;\n", action->get_seq_number(), dstaction->get_seq_number());
+         }
+       }
+  fprintf(file,"}\n");
+  fclose(file);        
 }
+#endif
 
 /**
  * Checks whether one ModelAction can reach another.
@@ -136,8 +167,8 @@ bool CycleGraph::checkReachable(const ModelAction *from, const ModelAction *to)
  * @return True, @a from can reach @a to; otherwise, false
  */
 bool CycleGraph::checkReachable(CycleNode *from, CycleNode *to) {
-       std::vector<CycleNode *> queue;
-       HashTable<CycleNode *, CycleNode *, uintptr_t, 4> discovered;
+       std::vector<CycleNode *, MyAlloc<CycleNode *> > queue;
+       HashTable<CycleNode *, CycleNode *, uintptr_t, 4, MYMALLOC, MYCALLOC, MYFREE> discovered;
 
        queue.push_back(from);
        discovered.put(from, from);
@@ -217,8 +248,12 @@ std::vector<CycleNode *> * CycleNode::getEdges() {
  * Adds an edge from this CycleNode to another CycleNode.
  * @param node The node to which we add a directed edge
  */
-void CycleNode::addEdge(CycleNode *node) {
+bool CycleNode::addEdge(CycleNode *node) {
+       for(unsigned int i=0;i<edges.size();i++)
+               if (edges[i]==node)
+                       return false;
        edges.push_back(node);
+       return true;
 }
 
 /** @returns the RMW CycleNode that reads from the current CycleNode */
index 81d736962dcb6893c8ef213b9571454c24ac5ea6..c8e8956be10529d194304061f8f90a6c48181181 100644 (file)
@@ -8,7 +8,7 @@
 #include "hashtable.h"
 #include <vector>
 #include <inttypes.h>
-
+#include "config.h"
 #include "mymemory.h"
 
 class CycleNode;
@@ -28,6 +28,9 @@ class CycleGraph {
        void startChanges();
        void commitChanges();
        void rollbackChanges();
+#if SUPPORT_MOD_ORDER_DUMP
+       void dumpGraphToFile(const char * filename);
+#endif
 
        SNAPSHOTALLOC
  private:
@@ -35,6 +38,9 @@ class CycleGraph {
 
        /** @brief A table for mapping ModelActions to CycleNodes */
        HashTable<const ModelAction *, CycleNode *, uintptr_t, 4> actionToNode;
+#if SUPPORT_MOD_ORDER_DUMP
+       std::vector<CycleNode *> nodeList;
+#endif
 
        bool checkReachable(CycleNode *from, CycleNode *to);
 
@@ -53,10 +59,12 @@ class CycleGraph {
 class CycleNode {
  public:
        CycleNode(const ModelAction *action);
-       void addEdge(CycleNode * node);
+       bool addEdge(CycleNode * node);
        std::vector<CycleNode *> * getEdges();
        bool setRMW(CycleNode *);
        CycleNode* getRMW();
+       const ModelAction * getAction() {return action;};
+
        void popEdge() {
                edges.pop_back();
        };
index a69ba7860342ed34568a00930ed6b451a8663cee..2fde095ee67e6ce5498c4a8dd61d62c0779f2fec 100644 (file)
@@ -110,10 +110,9 @@ inline void atomic_flag::fence( memory_order __x__ ) const volatile
                 else {  model_rmwc_action((void *)__p__, __x__); *__q__ = __t__;  __r__ = false;} \
                 __r__; })
 
-//TODO
 #define _ATOMIC_FENCE_( __a__, __x__ ) \
-({ ;})
-
+       ({ model_fence_action(__x__);})
 
 #define ATOMIC_CHAR_LOCK_FREE 1
 #define ATOMIC_CHAR16_T_LOCK_FREE 1
index c7a71ccdb2f541869ae61bd968e78c1523c35548..954c07dd6dacdfc9473a4aa3f5e0a2f8db38bcbf 100644 (file)
--- a/model.cc
+++ b/model.cc
@@ -21,6 +21,7 @@ ModelChecker::ModelChecker(struct model_params params) :
        /* Initialize default scheduler */
        scheduler(new Scheduler()),
        num_executions(0),
+       num_feasible_executions(0),
        params(params),
        diverge(NULL),
        action_trace(new action_list_t()),
@@ -174,6 +175,8 @@ bool ModelChecker::next_execution()
        DBG();
 
        num_executions++;
+       if (isfinalfeasible())
+               num_feasible_executions++;
 
        if (isfinalfeasible() || DBG_ENABLED())
                print_summary();
@@ -614,7 +617,18 @@ void ModelChecker::check_recency(ModelAction *curr, bool already_added) {
 }
 
 /**
- * Updates the mo_graph with the constraints imposed from the current read.
+ * Updates the mo_graph with the constraints imposed from the current
+ * read.  
+ *
+ * Basic idea is the following: Go through each other thread and find
+ * the lastest action that happened before our read.  Two cases:
+ *
+ * (1) The action is a write => that write must either occur before
+ * the write we read from or be the write we read from.
+ *
+ * (2) The action is a read => the write that that action read from
+ * must occur before the write we read from or be the same write.
+ *
  * @param curr The current action. Must be a read.
  * @param rf The action that curr reads from. Must be a write.
  * @return True if modification order edges were added; false otherwise
@@ -657,7 +671,22 @@ bool ModelChecker::r_modification_order(ModelAction *curr, const ModelAction *rf
        return added;
 }
 
-/** Updates the mo_graph with the constraints imposed from the current read. */
+/** This method fixes up the modification order when we resolve a
+ *  promises.  The basic problem is that actions that occur after the
+ *  read curr could not property add items to the modification order
+ *  for our read.
+ *  
+ *  So for each thread, we find the earliest item that happens after
+ *  the read curr.  This is the item we have to fix up with additional
+ *  constraints.  If that action is write, we add a MO edge between
+ *  the Action rf and that action.  If the action is a read, we add a
+ *  MO edge between the Action rf, and whatever the read accessed.
+ *
+ * @param curr is the read ModelAction that we are fixing up MO edges for.
+ * @param rf is the write ModelAction that curr reads from.
+ *
+ */
+
 void ModelChecker::post_r_modification_order(ModelAction *curr, const ModelAction *rf)
 {
        std::vector<action_list_t> *thrd_lists = obj_thrd_map->get_safe_ptr(curr->get_location());
@@ -696,6 +725,23 @@ void ModelChecker::post_r_modification_order(ModelAction *curr, const ModelActio
 
 /**
  * Updates the mo_graph with the constraints imposed from the current write.
+ *
+ * Basic idea is the following: Go through each other thread and find
+ * the lastest action that happened before our write.  Two cases:
+ *
+ * (1) The action is a write => that write must occur before
+ * the current write
+ *
+ * (2) The action is a read => the write that that action read from
+ * must occur before the current write.
+ *
+ * This method also handles two other issues:
+ *
+ * (I) Sequential Consistency: Making sure that if the current write is
+ * seq_cst, that it occurs after the previous seq_cst write.
+ *
+ * (II) Sending the write back to non-synchronizing reads.
+ *
  * @param curr The current action. Must be a write.
  * @return True if modification order edges were added; false otherwise
  */
@@ -1078,7 +1124,11 @@ bool ModelChecker::resolve_promises(ModelAction *write)
                        if (read->is_rmw()) {
                                mo_graph->addRMWEdge(write, read);
                        }
+                       //First fix up the modification order for actions that happened
+                       //before the read
                        r_modification_order(read, write);
+                       //Next fix up the modification order for actions that happened
+                       //after the read.
                        post_r_modification_order(read, write);
                        promises->erase(promises->begin() + promise_index);
                        resolved = true;
@@ -1217,9 +1267,15 @@ void ModelChecker::print_summary()
 {
        printf("\n");
        printf("Number of executions: %d\n", num_executions);
+       printf("Number of feasible executions: %d\n", num_feasible_executions);
        printf("Total nodes created: %d\n", node_stack->get_total_nodes());
 
+#if SUPPORT_MOD_ORDER_DUMP
        scheduler->print();
+       char buffername[100];
+       sprintf(buffername, "exec%u",num_executions);
+       mo_graph->dumpGraphToFile(buffername);
+#endif
 
        if (!isfinalfeasible())
                printf("INFEASIBLE EXECUTION!\n");
diff --git a/model.h b/model.h
index 3d3eba78db81ee8a2904c1e14ed37102e4c4a930..4fc32c6db6c2800d2bdf705d7a8b256683968bab 100644 (file)
--- a/model.h
+++ b/model.h
@@ -100,6 +100,7 @@ private:
        bool has_asserted() {return asserted;}
        void reset_asserted() {asserted=false;}
        int num_executions;
+       int num_feasible_executions;
        bool promises_expired();
        const model_params params;
 
index 14929ee23b6502403d12f8dda1194b38c233c59e..c3a5ea82fb328b793b967707b2a2c3ec2cb38990 100644 (file)
@@ -17,7 +17,6 @@ void user_main()
        thrd_t t1, t2;
 
        atomic_init(&x, 0);
-
        thrd_create(&t1, (thrd_start_t)&a, NULL);
        thrd_create(&t2, (thrd_start_t)&a, NULL);