]> AND Public Git Repository - simgrid.git/blobdiff - src/mc/remote/AppSide.cpp
Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Finalize passing transitions during model checking
[simgrid.git] / src / mc / remote / AppSide.cpp
index cd8412e686a870cbe7df0a5610f8bab689e5d84c..3adb9b99f6971a56ec574c3232a2c00f4668bd6f 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2022. The SimGrid Team. All rights reserved.          */
+/* Copyright (c) 2015-2023. 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. */
@@ -15,6 +15,7 @@
 #if HAVE_SMPI
 #include "src/smpi/include/private.hpp"
 #endif
+#include "src/sthread/sthread.h"
 #include "xbt/coverage.h"
 #include "xbt/str.h"
 #include "xbt/xbt_modinter.h" /* mmalloc_preinit to get the default mmalloc arena address */
 #include <cstdlib>
 #include <cstring>
 #include <memory>
+#include <numeric>
 #include <sys/ptrace.h>
 #include <sys/socket.h>
 #include <sys/types.h>
 
 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_client, mc, "MC client logic");
+XBT_LOG_EXTERNAL_CATEGORY(mc_global);
 
 namespace simgrid::mc {
 
@@ -44,7 +47,7 @@ AppSide* AppSide::initialize()
   if (instance_)
     return instance_.get();
 
-  simgrid::mc::cfg_do_model_check = 1;
+  simgrid::mc::cfg_do_model_check = true;
 
   setvbuf(stdout, nullptr, _IOLBF, 0);
 
@@ -84,11 +87,18 @@ AppSide* AppSide::initialize()
 
 void AppSide::handle_deadlock_check(const s_mc_message_t*) const
 {
-  const auto& actor_list = kernel::EngineImpl::get_instance()->get_actor_list();
+  const auto* engine     = kernel::EngineImpl::get_instance();
+  const auto& actor_list = engine->get_actor_list();
   bool deadlock = not actor_list.empty() && std::none_of(begin(actor_list), end(actor_list), [](const auto& kv) {
     return mc::actor_is_enabled(kv.second);
   });
 
+  if (deadlock) {
+    XBT_CINFO(mc_global, "**************************");
+    XBT_CINFO(mc_global, "*** DEADLOCK DETECTED ***");
+    XBT_CINFO(mc_global, "**************************");
+    engine->display_all_actor_status();
+  }
   // Send result:
   s_mc_message_int_t answer{MessageType::DEADLOCK_CHECK_REPLY, deadlock};
   xbt_assert(channel_.send(answer) == 0, "Could not send response");
@@ -145,25 +155,71 @@ void AppSide::handle_finalize(const s_mc_message_int_t* msg) const
 void AppSide::handle_actors_status() const
 {
   auto const& actor_list = kernel::EngineImpl::get_instance()->get_actor_list();
-  int count              = actor_list.size();
-  XBT_DEBUG("Serialize the actors to answer ACTORS_STATUS from the checker. %d actors to go.", count);
+  const int num_actors   = actor_list.size();
+  XBT_DEBUG("Serialize the actors to answer ACTORS_STATUS from the checker. %d actors to go.", num_actors);
+
+  std::vector<s_mc_message_actors_status_one_t> status(num_actors);
+  int i                 = 0;
+  int total_transitions = 0;
 
-  struct s_mc_message_actors_status_answer_t answer {
-    MessageType::ACTORS_STATUS_REPLY, count
-  };
-  std::vector<s_mc_message_actors_status_one_t> status(count);
-  int i = 0;
   for (auto const& [aid, actor] : actor_list) {
     status[i].aid            = aid;
     status[i].enabled        = mc::actor_is_enabled(actor);
     status[i].max_considered = actor->simcall_.observer_->get_max_consider();
+    status[i].n_transitions  = mc::actor_is_enabled(actor) ? status[i].max_considered : 0;
+    total_transitions += status[i].n_transitions;
     i++;
   }
+
+  struct s_mc_message_actors_status_answer_t answer {
+    MessageType::ACTORS_STATUS_REPLY, num_actors, total_transitions
+  };
+
   xbt_assert(channel_.send(answer) == 0, "Could not send ACTORS_STATUS_REPLY msg");
   if (answer.count > 0) {
     size_t size = status.size() * sizeof(s_mc_message_actors_status_one_t);
     xbt_assert(channel_.send(status.data(), size) == 0, "Could not send ACTORS_STATUS_REPLY data");
   }
+
+  // Serialize each transition to describe what each actor is doing
+  if (total_transitions > 0) {
+    std::vector<s_mc_message_simcall_probe_one_t> probes(total_transitions);
+    auto probes_iter = probes.begin();
+
+    for (const auto& actor_status : status) {
+      if (not actor_status.enabled)
+        continue;
+
+      const auto& actor        = actor_list.at(actor_status.aid);
+      const int max_considered = actor_status.max_considered;
+
+      for (int times_considered = 0; times_considered < max_considered; times_considered++, probes_iter++) {
+        std::stringstream stream;
+        s_mc_message_simcall_probe_one_t& probe = *probes_iter;
+
+        if (actor->simcall_.observer_ != nullptr) {
+          actor->simcall_.observer_->prepare(times_considered);
+          actor->simcall_.observer_->serialize(stream);
+        } else {
+          stream << (short)mc::Transition::Type::UNKNOWN;
+        }
+
+        std::string str = stream.str();
+        xbt_assert(str.size() + 1 <= probe.buffer.size(),
+                   "The serialized transition is too large for the buffer. Please fix the code.");
+        strncpy(probe.buffer.data(), str.c_str(), probe.buffer.size() - 1);
+        probe.buffer.back() = '\0';
+
+        // TODO: Do we need to reset `times_considered` for each actor's
+        // simcall observer here to the "original" value? We may need to
+        // add a method to handle this
+      }
+    }
+
+    size_t size = probes.size() * sizeof(s_mc_message_simcall_probe_one_t);
+    XBT_DEBUG("Deliver ACTOR_TRANSITION_PROBE payload");
+    xbt_assert(channel_.send(probes.data(), size) == 0, "Could not send ACTOR_TRANSITION_PROBE payload");
+  }
 }
 
 #define assert_msg_size(_name_, _type_)                                                                                \
@@ -219,7 +275,9 @@ void AppSide::main_loop() const
   MC_ignore_heap(simgrid::mc::processes_time.data(),
                  simgrid::mc::processes_time.size() * sizeof(simgrid::mc::processes_time[0]));
 
+  sthread_disable();
   coverage_checkpoint();
+  sthread_enable();
   while (true) {
     simgrid::mc::execute_actors();
     xbt_assert(channel_.send(MessageType::WAITING) == 0, "Could not send WAITING message to model-checker");
@@ -289,7 +347,7 @@ void AppSide::declare_symbol(const char* name, int* value) const
   memset(&message, 0, sizeof(message));
   message.type = MessageType::REGISTER_SYMBOL;
   xbt_assert(strlen(name) + 1 <= message.name.size(), "Symbol is too long");
-  strncpy(message.name.data(), name, message.name.size());
+  strncpy(message.name.data(), name, message.name.size() - 1);
   message.callback = nullptr;
   message.data     = value;
   xbt_assert(channel_.send(message) == 0, "Could send REGISTER_SYMBOL message to model-checker");