Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
simcall_check_dependency() defined and implemented
[simgrid.git] / src / mc / mc_api.cpp
index 92702d5142e204c830a8bdcfec2bf37bfe76e2a1..33cc69249dabab1926d316c367c712bc3a157daf 100644 (file)
@@ -48,6 +48,93 @@ static char* buff_size_to_string(size_t buff_size)
   return xbt_strdup("(verbose only)");
 }
 
+inline
+smx_mailbox_t get_mbox(smx_simcall_t const r)
+{
+  switch (r->call_) {
+    case Simcall::COMM_ISEND:
+      return simcall_comm_isend__get__mbox(r);
+    case Simcall::COMM_IRECV:
+      return simcall_comm_irecv__get__mbox(r);
+    default:
+      return nullptr;
+  }
+}
+
+inline simgrid::kernel::activity::CommImpl* get_comm(smx_simcall_t const r)
+{
+  switch (r->call_) {
+    case Simcall::COMM_WAIT:
+      return simcall_comm_wait__getraw__comm(r);
+    case Simcall::COMM_TEST:
+      return simcall_comm_test__getraw__comm(r);
+    default:
+      return nullptr;
+  }
+}
+
+// Does half the job
+inline bool request_depend_asymmetric(smx_simcall_t r1, smx_simcall_t r2)
+{
+  if (r1->call_ == Simcall::COMM_ISEND && r2->call_ == Simcall::COMM_IRECV)
+    return false;
+
+  if (r1->call_ == Simcall::COMM_IRECV && r2->call_ == Simcall::COMM_ISEND)
+    return false;
+
+  // Those are internal requests, we do not need indirection because those objects are copies:
+  const kernel::activity::CommImpl* synchro1 = get_comm(r1);
+  const kernel::activity::CommImpl* synchro2 = get_comm(r2);
+
+  if ((r1->call_ == Simcall::COMM_ISEND || r1->call_ == Simcall::COMM_IRECV) && r2->call_ == Simcall::COMM_WAIT) {
+    const kernel::activity::MailboxImpl* mbox = get_mbox(r1);
+
+    if (mbox != synchro2->mbox_cpy
+        && simcall_comm_wait__get__timeout(r2) <= 0)
+      return false;
+
+    if ((r1->issuer_ != synchro2->src_actor_.get()) && (r1->issuer_ != synchro2->dst_actor_.get()) &&
+        simcall_comm_wait__get__timeout(r2) <= 0)
+      return false;
+
+    if ((r1->call_ == Simcall::COMM_ISEND) && (synchro2->type_ == kernel::activity::CommImpl::Type::SEND) &&
+        (synchro2->src_buff_ != simcall_comm_isend__get__src_buff(r1)) && simcall_comm_wait__get__timeout(r2) <= 0)
+      return false;
+
+    if ((r1->call_ == Simcall::COMM_IRECV) && (synchro2->type_ == kernel::activity::CommImpl::Type::RECEIVE) &&
+        (synchro2->dst_buff_ != simcall_comm_irecv__get__dst_buff(r1)) && simcall_comm_wait__get__timeout(r2) <= 0)
+      return false;
+  }
+
+  /* FIXME: the following rule assumes that the result of the isend/irecv call is not stored in a buffer used in the
+   * test call. */
+#if 0
+  if((r1->call == Simcall::COMM_ISEND || r1->call == Simcall::COMM_IRECV)
+      &&  r2->call == Simcall::COMM_TEST)
+    return false;
+#endif
+
+  if (r1->call_ == Simcall::COMM_WAIT && (r2->call_ == Simcall::COMM_WAIT || r2->call_ == Simcall::COMM_TEST) &&
+      (synchro1->src_actor_.get() == nullptr || synchro1->dst_actor_.get() == nullptr))
+    return false;
+
+  if (r1->call_ == Simcall::COMM_TEST &&
+      (simcall_comm_test__get__comm(r1) == nullptr || synchro1->src_buff_ == nullptr || synchro1->dst_buff_ == nullptr))
+    return false;
+
+  if (r1->call_ == Simcall::COMM_TEST && r2->call_ == Simcall::COMM_WAIT &&
+      synchro1->src_buff_ == synchro2->src_buff_ && synchro1->dst_buff_ == synchro2->dst_buff_)
+    return false;
+
+  if (r1->call_ == Simcall::COMM_WAIT && r2->call_ == Simcall::COMM_TEST && synchro1->src_buff_ != nullptr &&
+      synchro1->dst_buff_ != nullptr && synchro2->src_buff_ != nullptr && synchro2->dst_buff_ != nullptr &&
+      synchro1->dst_buff_ != synchro2->src_buff_ && synchro1->dst_buff_ != synchro2->dst_buff_ &&
+      synchro2->dst_buff_ != synchro1->src_buff_)
+    return false;
+
+  return true;
+}
+
 /* Search an enabled transition for the given process.
  *
  * This can be seen as an iterator returning the next transition of the process.
@@ -367,11 +454,6 @@ void mc_api::session_initialize() const
   session->initialize();
 }
 
-ModelChecker* mc_api::get_model_checker() const
-{
-  return mc_model_checker;
-}
-
 void mc_api::mc_inc_visited_states() const
 {
   mc_model_checker->visited_states++;
@@ -407,11 +489,21 @@ smx_actor_t mc_api::simcall_get_issuer(s_smx_simcall const* req) const
   return MC_smx_simcall_get_issuer(req);
 }
 
-long mc_api::simcall_get_issuer_id(s_smx_simcall const* req) const
+long mc_api::simcall_get_actor_id(s_smx_simcall const* req) const
 {
   return MC_smx_simcall_get_issuer(req)->get_pid();
 }
 
+smx_mailbox_t mc_api::simcall_get_mbox(smx_simcall_t const req) const
+{
+  return get_mbox(req);
+}
+
+simgrid::kernel::activity::CommImpl* mc_api::simcall_get_comm(smx_simcall_t const req) const
+{
+  return get_comm(req);
+}
+
 bool mc_api::mc_is_null() const
 {
   auto is_null = (mc_model_checker == nullptr) ? true : false;
@@ -474,9 +566,39 @@ smx_simcall_t mc_api::mc_state_choose_request(simgrid::mc::State* state) const
   return nullptr;
 }
 
-bool mc_api::request_depend(smx_simcall_t req1, smx_simcall_t req2) const
+bool mc_api::simcall_check_dependency(smx_simcall_t const req1, smx_simcall_t const req2) const
 {
-  return simgrid::mc::request_depend(req1, req2);
+  if (req1->issuer_ == req2->issuer_)
+    return false;
+
+  /* Wait with timeout transitions are not considered by the independence theorem, thus we consider them as dependent with all other transitions */
+  if ((req1->call_ == Simcall::COMM_WAIT && simcall_comm_wait__get__timeout(req1) > 0) ||
+      (req2->call_ == Simcall::COMM_WAIT && simcall_comm_wait__get__timeout(req2) > 0))
+    return true;
+
+  if (req1->call_ != req2->call_)
+    return request_depend_asymmetric(req1, req2) && request_depend_asymmetric(req2, req1);
+
+  // Those are internal requests, we do not need indirection because those objects are copies:
+  const kernel::activity::CommImpl* synchro1 = get_comm(req1);
+  const kernel::activity::CommImpl* synchro2 = get_comm(req2);
+
+  switch (req1->call_) {
+    case Simcall::COMM_ISEND:
+      return simcall_comm_isend__get__mbox(req1) == simcall_comm_isend__get__mbox(req2);
+    case Simcall::COMM_IRECV:
+      return simcall_comm_irecv__get__mbox(req1) == simcall_comm_irecv__get__mbox(req2);
+    case Simcall::COMM_WAIT:
+      if (synchro1->src_buff_ == synchro2->src_buff_ && synchro1->dst_buff_ == synchro2->dst_buff_)
+        return false;
+      if (synchro1->src_buff_ != nullptr && synchro1->dst_buff_ != nullptr && synchro2->src_buff_ != nullptr &&
+          synchro2->dst_buff_ != nullptr && synchro1->dst_buff_ != synchro2->src_buff_ &&
+          synchro1->dst_buff_ != synchro2->dst_buff_ && synchro2->dst_buff_ != synchro1->src_buff_)
+        return false;
+      return true;
+    default:
+      return true;
+  }
 }
 
 std::string mc_api::request_to_string(smx_simcall_t req, int value, RequestType request_type) const