Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
model-checker : cleanups, refactoring and apply indent script
[simgrid.git] / src / mc / mc_visited.c
diff --git a/src/mc/mc_visited.c b/src/mc/mc_visited.c
new file mode 100644 (file)
index 0000000..172d1a8
--- /dev/null
@@ -0,0 +1,481 @@
+/* Copyright (c) 2011-2014. The SimGrid Team.
+ * All rights reserved.                                                     */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#include "mc_private.h"
+#include <unistd.h>
+#include <sys/wait.h>
+
+XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_visited, mc,
+                                "Logging specific to state equaity detection mechanisms");
+
+xbt_dynar_t visited_pairs;
+xbt_dynar_t visited_states;
+
+void visited_state_free(mc_visited_state_t state)
+{
+  if (state) {
+    MC_free_snapshot(state->system_state);
+    xbt_free(state);
+  }
+}
+
+void visited_state_free_voidp(void *s)
+{
+  visited_state_free((mc_visited_state_t) * (void **) s);
+}
+
+/**
+ * \brief Save the current state
+ * \return Snapshot of the current state.
+ */
+static mc_visited_state_t visited_state_new()
+{
+  mc_visited_state_t new_state = NULL;
+  new_state = xbt_new0(s_mc_visited_state_t, 1);
+  new_state->heap_bytes_used = mmalloc_get_bytes_used(std_heap);
+  new_state->nb_processes = xbt_swag_size(simix_global->process_list);
+  new_state->system_state = MC_take_snapshot(mc_stats->expanded_states);
+  new_state->num = mc_stats->expanded_states;
+  new_state->other_num = -1;
+  return new_state;
+}
+
+
+mc_visited_pair_t MC_visited_pair_new(int pair_num,
+                                      xbt_automaton_state_t automaton_state,
+                                      xbt_dynar_t atomic_propositions)
+{
+  mc_visited_pair_t pair = NULL;
+  pair = xbt_new0(s_mc_visited_pair_t, 1);
+  pair->graph_state = MC_state_new();
+  pair->graph_state->system_state = MC_take_snapshot(pair_num);
+  pair->heap_bytes_used = mmalloc_get_bytes_used(std_heap);
+  pair->nb_processes = xbt_swag_size(simix_global->process_list);
+  pair->automaton_state = automaton_state;
+  pair->num = pair_num;
+  pair->other_num = -1;
+  pair->acceptance_removed = 0;
+  pair->visited_removed = 0;
+  pair->acceptance_pair = 0;
+  pair->atomic_propositions = xbt_dynar_new(sizeof(int), NULL);
+  unsigned int cursor = 0;
+  int value;
+  xbt_dynar_foreach(atomic_propositions, cursor, value)
+      xbt_dynar_push_as(pair->atomic_propositions, int, value);
+  return pair;
+}
+
+void MC_visited_pair_delete(mc_visited_pair_t p)
+{
+  p->automaton_state = NULL;
+  MC_state_delete(p->graph_state);
+  xbt_dynar_free(&(p->atomic_propositions));
+  xbt_free(p);
+  p = NULL;
+}
+
+/**
+ *  \brief Find a suitable subrange of candidate duplicates for a given state
+ *  \param list dynamic array of states/pairs with candidate duplicates of the current state;
+ *  \param ref current state/pair;
+ *  \param min (output) index of the beginning of the the subrange
+ *  \param max (output) index of the enf of the subrange
+ *
+ *  Given a suitably ordered array of states/pairs, this function extracts a subrange
+ *  (with index *min <= i <= *max) with candidate duplicates of the given state/pair.
+ *  This function uses only fast discriminating criterions and does not use the
+ *  full state/pair comparison algorithms.
+ *
+ *  The states/pairs in list MUST be ordered using a (given) weak order
+ *  (based on nb_processes and heap_bytes_used).
+ *  The subrange is the subrange of "equivalence" of the given state/pair.
+ */
+int get_search_interval(xbt_dynar_t list, void *ref, int *min, int *max)
+{
+
+  int mc_mem_set = (mmalloc_get_current_heap() == mc_heap);
+
+  MC_SET_MC_HEAP;
+
+  int cursor = 0, previous_cursor, next_cursor;
+  int nb_processes, heap_bytes_used, nb_processes_test, heap_bytes_used_test;
+  void *ref_test;
+
+  if (_sg_mc_safety) {
+    nb_processes = ((mc_visited_state_t) ref)->nb_processes;
+    heap_bytes_used = ((mc_visited_state_t) ref)->heap_bytes_used;
+  } else if (_sg_mc_liveness) {
+    nb_processes = ((mc_visited_pair_t) ref)->nb_processes;
+    heap_bytes_used = ((mc_visited_pair_t) ref)->heap_bytes_used;
+  }
+
+  int start = 0;
+  int end = xbt_dynar_length(list) - 1;
+
+  while (start <= end) {
+    cursor = (start + end) / 2;
+    if (_sg_mc_safety) {
+      ref_test =
+          (mc_visited_state_t) xbt_dynar_get_as(list, cursor,
+                                                mc_visited_state_t);
+      nb_processes_test = ((mc_visited_state_t) ref_test)->nb_processes;
+      heap_bytes_used_test = ((mc_visited_state_t) ref_test)->heap_bytes_used;
+    } else if (_sg_mc_liveness) {
+      ref_test =
+          (mc_visited_pair_t) xbt_dynar_get_as(list, cursor, mc_visited_pair_t);
+      nb_processes_test = ((mc_visited_pair_t) ref_test)->nb_processes;
+      heap_bytes_used_test = ((mc_visited_pair_t) ref_test)->heap_bytes_used;
+    }
+    if (nb_processes_test < nb_processes) {
+      start = cursor + 1;
+    } else if (nb_processes_test > nb_processes) {
+      end = cursor - 1;
+    } else {
+      if (heap_bytes_used_test < heap_bytes_used) {
+        start = cursor + 1;
+      } else if (heap_bytes_used_test > heap_bytes_used) {
+        end = cursor - 1;
+      } else {
+        *min = *max = cursor;
+        previous_cursor = cursor - 1;
+        while (previous_cursor >= 0) {
+          if (_sg_mc_safety) {
+            ref_test =
+                (mc_visited_state_t) xbt_dynar_get_as(list, previous_cursor,
+                                                      mc_visited_state_t);
+            nb_processes_test = ((mc_visited_state_t) ref_test)->nb_processes;
+            heap_bytes_used_test =
+                ((mc_visited_state_t) ref_test)->heap_bytes_used;
+          } else if (_sg_mc_liveness) {
+            ref_test =
+                (mc_visited_pair_t) xbt_dynar_get_as(list, previous_cursor,
+                                                     mc_visited_pair_t);
+            nb_processes_test = ((mc_visited_pair_t) ref_test)->nb_processes;
+            heap_bytes_used_test =
+                ((mc_visited_pair_t) ref_test)->heap_bytes_used;
+          }
+          if (nb_processes_test != nb_processes
+              || heap_bytes_used_test != heap_bytes_used)
+            break;
+          *min = previous_cursor;
+          previous_cursor--;
+        }
+        next_cursor = cursor + 1;
+        while (next_cursor < xbt_dynar_length(list)) {
+          if (_sg_mc_safety) {
+            ref_test =
+                (mc_visited_state_t) xbt_dynar_get_as(list, next_cursor,
+                                                      mc_visited_state_t);
+            nb_processes_test = ((mc_visited_state_t) ref_test)->nb_processes;
+            heap_bytes_used_test =
+                ((mc_visited_state_t) ref_test)->heap_bytes_used;
+          } else if (_sg_mc_liveness) {
+            ref_test =
+                (mc_visited_pair_t) xbt_dynar_get_as(list, next_cursor,
+                                                     mc_visited_pair_t);
+            nb_processes_test = ((mc_visited_pair_t) ref_test)->nb_processes;
+            heap_bytes_used_test =
+                ((mc_visited_pair_t) ref_test)->heap_bytes_used;
+          }
+          if (nb_processes_test != nb_processes
+              || heap_bytes_used_test != heap_bytes_used)
+            break;
+          *max = next_cursor;
+          next_cursor++;
+        }
+        if (!mc_mem_set)
+          MC_SET_STD_HEAP;
+        return -1;
+      }
+    }
+  }
+
+  if (!mc_mem_set)
+    MC_SET_STD_HEAP;
+
+  return cursor;
+}
+
+
+/**
+ * \brief Checks whether a given state has already been visited by the algorithm.
+ */
+int is_visited_state()
+{
+
+  if (_sg_mc_visited == 0)
+    return -1;
+
+  int mc_mem_set = (mmalloc_get_current_heap() == mc_heap);
+
+  MC_SET_MC_HEAP;
+
+  mc_visited_state_t new_state = visited_state_new();
+
+  if (xbt_dynar_is_empty(visited_states)) {
+
+    xbt_dynar_push(visited_states, &new_state);
+
+    if (!mc_mem_set)
+      MC_SET_STD_HEAP;
+
+    return -1;
+
+  } else {
+
+    int min = -1, max = -1, index;
+    //int res;
+    mc_visited_state_t state_test;
+    int cursor;
+
+    index = get_search_interval(visited_states, new_state, &min, &max);
+
+    if (min != -1 && max != -1) {
+
+      // Parallell implementation
+      /*res = xbt_parmap_mc_apply(parmap, snapshot_compare, xbt_dynar_get_ptr(visited_states, min), (max-min)+1, new_state);
+         if(res != -1){
+         state_test = (mc_visited_state_t)xbt_dynar_get_as(visited_states, (min+res)-1, mc_visited_state_t);
+         if(state_test->other_num == -1)
+         new_state->other_num = state_test->num;
+         else
+         new_state->other_num = state_test->other_num;
+         if(dot_output == NULL)
+         XBT_DEBUG("State %d already visited ! (equal to state %d)", new_state->num, state_test->num);
+         else
+         XBT_DEBUG("State %d already visited ! (equal to state %d (state %d in dot_output))", new_state->num, state_test->num, new_state->other_num);
+         xbt_dynar_remove_at(visited_states, (min + res) - 1, NULL);
+         xbt_dynar_insert_at(visited_states, (min+res) - 1, &new_state);
+         if(!raw_mem_set)
+         MC_SET_STD_HEAP;
+         return new_state->other_num;
+         } */
+
+      cursor = min;
+      while (cursor <= max) {
+        state_test =
+            (mc_visited_state_t) xbt_dynar_get_as(visited_states, cursor,
+                                                  mc_visited_state_t);
+        if (snapshot_compare(state_test, new_state) == 0) {
+          // The state has been visited:
+
+          if (state_test->other_num == -1)
+            new_state->other_num = state_test->num;
+          else
+            new_state->other_num = state_test->other_num;
+          if (dot_output == NULL)
+            XBT_DEBUG("State %d already visited ! (equal to state %d)",
+                      new_state->num, state_test->num);
+          else
+            XBT_DEBUG
+                ("State %d already visited ! (equal to state %d (state %d in dot_output))",
+                 new_state->num, state_test->num, new_state->other_num);
+
+          // Replace the old state with the new one (why?):
+          xbt_dynar_remove_at(visited_states, cursor, NULL);
+          xbt_dynar_insert_at(visited_states, cursor, &new_state);
+
+          if (!mc_mem_set)
+            MC_SET_STD_HEAP;
+          return new_state->other_num;
+        }
+        cursor++;
+      }
+
+      // The state has not been visited, add it to the list:
+      xbt_dynar_insert_at(visited_states, min, &new_state);
+
+    } else {
+
+      // The state has not been visited: insert the state in the dynamic array.
+      state_test =
+          (mc_visited_state_t) xbt_dynar_get_as(visited_states, index,
+                                                mc_visited_state_t);
+      if (state_test->nb_processes < new_state->nb_processes) {
+        xbt_dynar_insert_at(visited_states, index + 1, &new_state);
+      } else {
+        if (state_test->heap_bytes_used < new_state->heap_bytes_used)
+          xbt_dynar_insert_at(visited_states, index + 1, &new_state);
+        else
+          xbt_dynar_insert_at(visited_states, index, &new_state);
+      }
+
+    }
+
+    // We have reached the maximum number of stored states;
+    if (xbt_dynar_length(visited_states) > _sg_mc_visited) {
+
+      // Find the (index of the) older state:
+      int min2 = mc_stats->expanded_states;
+      unsigned int cursor2 = 0;
+      unsigned int index2 = 0;
+      xbt_dynar_foreach(visited_states, cursor2, state_test) {
+        if (state_test->num < min2) {
+          index2 = cursor2;
+          min2 = state_test->num;
+        }
+      }
+
+      // and drop it:
+      xbt_dynar_remove_at(visited_states, index2, NULL);
+    }
+
+    if (!mc_mem_set)
+      MC_SET_STD_HEAP;
+
+    return -1;
+
+  }
+}
+
+/**
+ * \brief Checks whether a given pair has already been visited by the algorithm.
+ */
+int is_visited_pair(mc_visited_pair_t pair, int pair_num,
+                    xbt_automaton_state_t automaton_state,
+                    xbt_dynar_t atomic_propositions)
+{
+
+  if (_sg_mc_visited == 0)
+    return -1;
+
+  int mc_mem_set = (mmalloc_get_current_heap() == mc_heap);
+
+  MC_SET_MC_HEAP;
+
+  mc_visited_pair_t new_pair = NULL;
+
+  if (pair == NULL) {
+    new_pair =
+        MC_visited_pair_new(pair_num, automaton_state, atomic_propositions);
+  } else {
+    new_pair = pair;
+  }
+
+  if (xbt_dynar_is_empty(visited_pairs)) {
+
+    xbt_dynar_push(visited_pairs, &new_pair);
+
+  } else {
+
+    int min = -1, max = -1, index;
+    //int res;
+    mc_visited_pair_t pair_test;
+    int cursor;
+
+    index = get_search_interval(visited_pairs, new_pair, &min, &max);
+
+    if (min != -1 && max != -1) {       // Visited pair with same number of processes and same heap bytes used exists
+      /*res = xbt_parmap_mc_apply(parmap, snapshot_compare, xbt_dynar_get_ptr(visited_pairs, min), (max-min)+1, pair);
+         if(res != -1){
+         pair_test = (mc_pair_t)xbt_dynar_get_as(visited_pairs, (min+res)-1, mc_pair_t);
+         if(pair_test->other_num == -1)
+         pair->other_num = pair_test->num;
+         else
+         pair->other_num = pair_test->other_num;
+         if(dot_output == NULL)
+         XBT_DEBUG("Pair %d already visited ! (equal to pair %d)", pair->num, pair_test->num);
+         else
+         XBT_DEBUG("Pair %d already visited ! (equal to pair %d (pair %d in dot_output))", pair->num, pair_test->num, pair->other_num);
+         xbt_dynar_remove_at(visited_pairs, (min + res) - 1, NULL);
+         xbt_dynar_insert_at(visited_pairs, (min+res) - 1, &pair);
+         pair_test->visited_removed = 1;
+         if(pair_test->stack_removed && pair_test->visited_removed){
+         if((pair_test->automaton_state->type == 1) || (pair_test->automaton_state->type == 2)){
+         if(pair_test->acceptance_removed){
+         MC_pair_delete(pair_test);
+         }
+         }else{
+         MC_pair_delete(pair_test);
+         }
+         }
+         if(!raw_mem_set)
+         MC_SET_STD_HEAP;
+         return pair->other_num;
+         } */
+      cursor = min;
+      while (cursor <= max) {
+        pair_test =
+            (mc_visited_pair_t) xbt_dynar_get_as(visited_pairs, cursor,
+                                                 mc_visited_pair_t);
+        //if(pair_test->acceptance_pair == 0){ /* Acceptance pair have been already checked before */
+        if (xbt_automaton_state_compare
+            (pair_test->automaton_state, new_pair->automaton_state) == 0) {
+          if (xbt_automaton_propositional_symbols_compare_value
+              (pair_test->atomic_propositions,
+               new_pair->atomic_propositions) == 0) {
+            if (snapshot_compare(pair_test, new_pair) == 0) {
+              if (pair_test->other_num == -1)
+                new_pair->other_num = pair_test->num;
+              else
+                new_pair->other_num = pair_test->other_num;
+              if (dot_output == NULL)
+                XBT_DEBUG("Pair %d already visited ! (equal to pair %d)",
+                          new_pair->num, pair_test->num);
+              else
+                XBT_DEBUG
+                    ("Pair %d already visited ! (equal to pair %d (pair %d in dot_output))",
+                     new_pair->num, pair_test->num, new_pair->other_num);
+              xbt_dynar_remove_at(visited_pairs, cursor, NULL);
+              xbt_dynar_insert_at(visited_pairs, cursor, &new_pair);
+              pair_test->visited_removed = 1;
+              if (pair_test->acceptance_pair) {
+                if (pair_test->acceptance_removed == 1)
+                  MC_visited_pair_delete(pair_test);
+              } else {
+                MC_visited_pair_delete(pair_test);
+              }
+              if (!mc_mem_set)
+                MC_SET_STD_HEAP;
+              return new_pair->other_num;
+            }
+          }
+          //}
+        }
+        cursor++;
+      }
+      xbt_dynar_insert_at(visited_pairs, min, &new_pair);
+    } else {
+      pair_test =
+          (mc_visited_pair_t) xbt_dynar_get_as(visited_pairs, index,
+                                               mc_visited_pair_t);
+      if (pair_test->nb_processes < new_pair->nb_processes) {
+        xbt_dynar_insert_at(visited_pairs, index + 1, &new_pair);
+      } else {
+        if (pair_test->heap_bytes_used < new_pair->heap_bytes_used)
+          xbt_dynar_insert_at(visited_pairs, index + 1, &new_pair);
+        else
+          xbt_dynar_insert_at(visited_pairs, index, &new_pair);
+      }
+    }
+
+    if (xbt_dynar_length(visited_pairs) > _sg_mc_visited) {
+      int min2 = mc_stats->expanded_pairs;
+      unsigned int cursor2 = 0;
+      unsigned int index2 = 0;
+      xbt_dynar_foreach(visited_pairs, cursor2, pair_test) {
+        if (pair_test->num < min2) {
+          index2 = cursor2;
+          min2 = pair_test->num;
+        }
+      }
+      xbt_dynar_remove_at(visited_pairs, index2, &pair_test);
+      pair_test->visited_removed = 1;
+      if (pair_test->acceptance_pair) {
+        if (pair_test->acceptance_removed)
+          MC_visited_pair_delete(pair_test);
+      } else {
+        MC_visited_pair_delete(pair_test);
+      }
+    }
+
+  }
+
+  if (!mc_mem_set)
+    MC_SET_STD_HEAP;
+
+  return -1;
+}