Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
setter function only need a simcall in MC or with parallel execs
authorMartin Quinson <martin.quinson@ens-rennes.fr>
Sun, 6 Nov 2022 00:17:57 +0000 (01:17 +0100)
committerMartin Quinson <martin.quinson@ens-rennes.fr>
Sun, 6 Nov 2022 00:24:31 +0000 (01:24 +0100)
This change introduce a new kind of simcalls alongside
simcall_answered and simcall_blocking: simcall_run_object_access that
is dedicated to object setter functions.

This is an answered simcall if running in // or in MC, and just a
regular function call if runnning a plain simulation.

This may speed up large simulations with a huge amount of activities,
but the perf improvement is not evaluated yet.

The performance could be further improved with a SIMGRID_HAVE_PARALLEL
option allowing the compiler to know beforhand that the simcall branch
will never be taken. But such an option would require to be tested and
I'm too lazy for that.

26 files changed:
examples/c/exec-dvfs/exec-dvfs.tesh
examples/cpp/exec-dvfs/s4u-exec-dvfs.tesh
examples/python/exec-dvfs/exec-dvfs.tesh
include/simgrid/forward.h
include/simgrid/simix.hpp
src/kernel/activity/ActivityImpl.hpp
src/kernel/actor/ActorImpl.hpp
src/kernel/actor/CommObserver.cpp
src/kernel/actor/Simcall.cpp
src/kernel/actor/Simcall.hpp
src/kernel/actor/SimcallObserver.cpp
src/kernel/actor/SimcallObserver.hpp
src/kernel/resource/Resource.hpp
src/mc/compare.cpp
src/mc/transition/Transition.cpp
src/mc/transition/Transition.hpp
src/s4u/s4u_ConditionVariable.cpp
src/s4u/s4u_Disk.cpp
src/s4u/s4u_Exec.cpp
src/s4u/s4u_Host.cpp
src/s4u/s4u_Io.cpp
src/s4u/s4u_Link.cpp
src/s4u/s4u_VirtualMachine.cpp
src/simix/libsmx.cpp
src/surf/HostImpl.hpp
teshsuite/s4u/storage_client_server/storage_client_server.tesh

index 882c433..5485497 100644 (file)
@@ -7,9 +7,9 @@ $ ${bindir:=.}/c-exec-dvfs ${platfdir}/energy_platform.xml "--log=root.fmt:[%10.
 > [  0.000000] (2:dvfs_test@MyHost2) Current power peak=100000000.000000
 > [  1.000000] (1:dvfs_test@MyHost1) Task1 simulation time: 1.000000e+00
 > [  1.000000] (1:dvfs_test@MyHost1) Changing power peak value to 20000000.000000 (at index 2)
+> [  1.000000] (1:dvfs_test@MyHost1) Current power peak=20000000.000000
 > [  1.000000] (2:dvfs_test@MyHost2) Task1 simulation time: 1.000000e+00
 > [  1.000000] (2:dvfs_test@MyHost2) Changing power peak value to 20000000.000000 (at index 2)
-> [  1.000000] (1:dvfs_test@MyHost1) Current power peak=20000000.000000
 > [  1.000000] (2:dvfs_test@MyHost2) Current power peak=20000000.000000
 > [  6.000000] (1:dvfs_test@MyHost1) Task2 simulation time: 5.000000e+00
 > [  6.000000] (1:dvfs_test@MyHost1) Count of Processor states=3
@@ -28,9 +28,9 @@ $ ${bindir:=.}/c-exec-dvfs ${platfdir}/energy_cluster.xml "--log=root.fmt:[%10.6
 > [  0.000000] (2:dvfs_test@MyHost2) Current power peak=100000000.000000
 > [  1.000000] (1:dvfs_test@MyHost1) Task1 simulation time: 1.000000e+00
 > [  1.000000] (1:dvfs_test@MyHost1) Changing power peak value to 20000000.000000 (at index 2)
+> [  1.000000] (1:dvfs_test@MyHost1) Current power peak=20000000.000000
 > [  1.000000] (2:dvfs_test@MyHost2) Task1 simulation time: 1.000000e+00
 > [  1.000000] (2:dvfs_test@MyHost2) Changing power peak value to 20000000.000000 (at index 2)
-> [  1.000000] (1:dvfs_test@MyHost1) Current power peak=20000000.000000
 > [  1.000000] (2:dvfs_test@MyHost2) Current power peak=20000000.000000
 > [  6.000000] (1:dvfs_test@MyHost1) Task2 simulation time: 5.000000e+00
 > [  6.000000] (1:dvfs_test@MyHost1) Count of Processor states=3
index 8ad80a9..f0febb1 100644 (file)
@@ -9,9 +9,9 @@ $ ${bindir:=.}/s4u-exec-dvfs ${platfdir}/energy_platform.xml "--log=root.fmt:[%1
 > [  0.000000] (2:dvfs_test@MyHost2) Current power peak=100000000.000000
 > [  1.000000] (1:dvfs_test@MyHost1) Computation1 duration: 1.00
 > [  1.000000] (1:dvfs_test@MyHost1) Changing power peak value to 20000000.000000 (at index 2)
+> [  1.000000] (1:dvfs_test@MyHost1) Current power peak=20000000.000000
 > [  1.000000] (2:dvfs_test@MyHost2) Computation1 duration: 1.00
 > [  1.000000] (2:dvfs_test@MyHost2) Changing power peak value to 20000000.000000 (at index 2)
-> [  1.000000] (1:dvfs_test@MyHost1) Current power peak=20000000.000000
 > [  1.000000] (2:dvfs_test@MyHost2) Current power peak=20000000.000000
 > [  6.000000] (1:dvfs_test@MyHost1) Computation2 duration: 5.00
 > [  6.000000] (1:dvfs_test@MyHost1) Count of Processor states=3
@@ -28,9 +28,9 @@ $ ${bindir:=.}/s4u-exec-dvfs ${platfdir}/energy_cluster.xml "--log=root.fmt:[%10
 > [  0.000000] (2:dvfs_test@MyHost2) Current power peak=100000000.000000
 > [  1.000000] (1:dvfs_test@MyHost1) Computation1 duration: 1.00
 > [  1.000000] (1:dvfs_test@MyHost1) Changing power peak value to 20000000.000000 (at index 2)
+> [  1.000000] (1:dvfs_test@MyHost1) Current power peak=20000000.000000
 > [  1.000000] (2:dvfs_test@MyHost2) Computation1 duration: 1.00
 > [  1.000000] (2:dvfs_test@MyHost2) Changing power peak value to 20000000.000000 (at index 2)
-> [  1.000000] (1:dvfs_test@MyHost1) Current power peak=20000000.000000
 > [  1.000000] (2:dvfs_test@MyHost2) Current power peak=20000000.000000
 > [  6.000000] (1:dvfs_test@MyHost1) Computation2 duration: 5.00
 > [  6.000000] (1:dvfs_test@MyHost1) Count of Processor states=3
index 06bd190..7055274 100644 (file)
@@ -9,9 +9,9 @@ $ ${pythoncmd:=python3} ${PYTHON_TOOL_OPTIONS:=} ${srcdir:=.}/exec-dvfs.py ${pla
 > [  0.000000] (2:dvfs_test@MyHost2) Current power peak=100000000.000000
 > [  1.000000] (1:dvfs_test@MyHost1) Task1 duration: 1.00
 > [  1.000000] (1:dvfs_test@MyHost1) Changing power peak value to 20000000.000000 (at index 2)
+> [  1.000000] (1:dvfs_test@MyHost1) Changed power peak=20000000.000000
 > [  1.000000] (2:dvfs_test@MyHost2) Task1 duration: 1.00
 > [  1.000000] (2:dvfs_test@MyHost2) Changing power peak value to 20000000.000000 (at index 2)
-> [  1.000000] (1:dvfs_test@MyHost1) Changed power peak=20000000.000000
 > [  1.000000] (2:dvfs_test@MyHost2) Changed power peak=20000000.000000
 > [  6.000000] (1:dvfs_test@MyHost1) Task2 duration: 5.00
 > [  6.000000] (1:dvfs_test@MyHost1) Count of Processor states=3
@@ -27,9 +27,9 @@ $ ${pythoncmd:=python3} ${PYTHON_TOOL_OPTIONS:=} ${srcdir:=.}/exec-dvfs.py ${pla
 > [  0.000000] (2:dvfs_test@MyHost2) Current power peak=100000000.000000
 > [  1.000000] (1:dvfs_test@MyHost1) Task1 duration: 1.00
 > [  1.000000] (1:dvfs_test@MyHost1) Changing power peak value to 20000000.000000 (at index 2)
+> [  1.000000] (1:dvfs_test@MyHost1) Changed power peak=20000000.000000
 > [  1.000000] (2:dvfs_test@MyHost2) Task1 duration: 1.00
 > [  1.000000] (2:dvfs_test@MyHost2) Changing power peak value to 20000000.000000 (at index 2)
-> [  1.000000] (1:dvfs_test@MyHost1) Changed power peak=20000000.000000
 > [  1.000000] (2:dvfs_test@MyHost2) Changed power peak=20000000.000000
 > [  6.000000] (1:dvfs_test@MyHost1) Task2 duration: 5.00
 > [  6.000000] (1:dvfs_test@MyHost1) Count of Processor states=3
index 7cc1565..99c6265 100644 (file)
@@ -117,6 +117,8 @@ using ActorCodeFactory = std::function<ActorCode(std::vector<std::string> args)>
 
 class Simcall;
 class SimcallObserver;
+class ObjectAccessSimcallObserver;
+class ObjectAccessSimcallItem;
 } // namespace actor
 
 namespace activity {
index fb8addf..ac24d4f 100644 (file)
@@ -18,15 +18,15 @@ XBT_PUBLIC void simcall_run_answered(std::function<void()> const& code,
                                      simgrid::kernel::actor::SimcallObserver* observer);
 XBT_PUBLIC void simcall_run_blocking(std::function<void()> const& code,
                                      simgrid::kernel::actor::SimcallObserver* observer);
+XBT_PUBLIC void simcall_run_object_access(std::function<void()> const& code,
+                                          simgrid::kernel::actor::ObjectAccessSimcallItem* item);
 
-namespace simgrid {
-namespace kernel {
-namespace actor {
+namespace simgrid::kernel::actor {
 
 /** Execute some code in kernel context on behalf of the user code.
  *
  * Every modification of the environment must be protected this way: every setter, constructor and similar.
- * Getters don't have to be protected this way.
+ * Getters don't have to be protected this way, and setters may use the simcall_object_access() variant (see below).
  *
  * This allows deterministic parallel simulation without any locking, even if almost nobody uses parallel simulation in
  * SimGrid. More interestingly it makes every modification of the simulated world observable by the model-checker,
@@ -58,6 +58,29 @@ template <class F> typename std::result_of_t<F()> simcall_answered(F&& code, Sim
   return result.get();
 }
 
+/** Use a setter on the `item` object. That's a simcall only if running in parallel or with MC activated.
+ *
+ * Simulation without MC and without parallelism (contexts/nthreads=1) will not pay the price of a simcall for an
+ * harmless setter. When running in parallel, you want your write access to be done in a mutual exclusion way, while the
+ * getters can still occure out of order.
+ *
+ * When running in MC, you want to make this access visible to the checker. Actually in this case, it's not visible from
+ * the checker (and thus still use a fast track) if the setter is called from the actor that created the object.
+ */
+template <class F> typename std::result_of_t<F()> simcall_object_access(ObjectAccessSimcallItem* item, F&& code)
+{
+  // If we are in the maestro, we take the fast path and execute the code directly
+  if (simgrid::s4u::Actor::is_maestro())
+    return std::forward<F>(code)();
+
+  // If called from another thread, do a real simcall. It will be short-cut on need
+  using R = typename std::result_of_t<F()>;
+  simgrid::xbt::Result<R> result;
+  simcall_run_object_access([&result, &code] { simgrid::xbt::fulfill_promise(result, std::forward<F>(code)); }, item);
+
+  return result.get();
+}
+
 /** Execute some code (that does not return immediately) in kernel context
  *
  * This is very similar to simcall() right above, but the calling actor will not get rescheduled until
@@ -91,8 +114,6 @@ auto simcall_blocking(F&& code, Observer* observer) -> decltype(observer->get_re
   simcall_blocking(std::forward<F>(code), static_cast<SimcallObserver*>(observer));
   return observer->get_result();
 }
-} // namespace actor
-} // namespace kernel
-} // namespace simgrid
+} // namespace simgrid::kernel::actor
 
 #endif
index f3dca0b..a4993f9 100644 (file)
@@ -6,23 +6,23 @@
 #ifndef SIMGRID_KERNEL_ACTIVITY_ACTIVITYIMPL_HPP
 #define SIMGRID_KERNEL_ACTIVITY_ACTIVITYIMPL_HPP
 
-#include <list>
-#include <string>
-#include <string_view>
-
 #include "simgrid/forward.h"
-#include <xbt/utility.hpp>
+#include "simgrid/kernel/resource/Action.hpp"
+#include "simgrid/simix.hpp"
+#include "src/kernel/actor/Simcall.hpp"
+#include "xbt/utility.hpp"
 
 #include <atomic>
-#include <simgrid/kernel/resource/Action.hpp>
-#include <simgrid/simix.hpp>
+#include <list>
+#include <string>
+#include <string_view>
 
 namespace simgrid::kernel::activity {
 
 XBT_DECLARE_ENUM_CLASS(State, WAITING, READY, RUNNING, DONE, CANCELED, FAILED, SRC_HOST_FAILURE, DST_HOST_FAILURE,
                        TIMEOUT, SRC_TIMEOUT, DST_TIMEOUT, LINK_FAILURE);
 
-class XBT_PUBLIC ActivityImpl {
+class XBT_PUBLIC ActivityImpl : public kernel::actor::ObjectAccessSimcallItem {
   std::atomic_int_fast32_t refcount_{0};
   std::string name_        = "";
   actor::ActorImpl* actor_ = nullptr;
index 34b61de..044bbf5 100644 (file)
@@ -9,7 +9,10 @@
 #include "Simcall.hpp"
 #include "simgrid/kernel/Timer.hpp"
 #include "simgrid/s4u/Actor.hpp"
+#include "src/kernel/actor/Simcall.hpp"
 #include "xbt/PropertyHolder.hpp"
+
+#include <atomic>
 #include <boost/intrusive/list.hpp>
 #include <functional>
 #include <list>
index 9c55619..ae1d392 100644 (file)
@@ -51,13 +51,6 @@ static void serialize_activity_test(const activity::ActivityImpl* act, std::stri
     stream << (short)mc::Transition::Type::UNKNOWN;
   }
 }
-template <typename A> static std::string ptr_to_id(A* ptr)
-{
-  static std::unordered_map<A*, std::string> map;
-  if (map.find(ptr) == map.end())
-    map.insert(std::make_pair(ptr, std::to_string(map.size() + 1)));
-  return map[ptr];
-}
 static std::string to_string_activity_test(const activity::ActivityImpl* act)
 {
   if (auto* comm = dynamic_cast<activity::CommImpl const*>(act)) {
index 09c7cdf..622a6c8 100644 (file)
@@ -3,7 +3,7 @@
 /* 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 "Simcall.hpp"
+#include "src/kernel/actor/Simcall.hpp"
 #include "simgrid/s4u/Host.hpp"
 #include "src/kernel/actor/ActorImpl.hpp"
 #include "src/kernel/actor/SimcallObserver.hpp"
@@ -26,5 +26,13 @@ const char* Simcall::get_cname() const
     return to_c_str(call_);
   }
 }
+ObjectAccessSimcallItem::ObjectAccessSimcallItem()
+{
+  take_ownership();
+}
+void ObjectAccessSimcallItem::take_ownership()
+{
+  simcall_owner_ = ActorImpl::self();
+}
 
 } // namespace simgrid::kernel::actor
index 8e7869f..091040c 100644 (file)
@@ -3,18 +3,15 @@
 /* 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. */
 
-#ifndef SIMCALL_HPP
-#define SIMCALL_HPP
+#ifndef SIMGRID_SIMCALL_HPP
+#define SIMGRID_SIMCALL_HPP
 
 #include "simgrid/forward.h"
-#include "src/kernel/activity/ActivityImpl.hpp"
 #include "xbt/utility.hpp"
 
 namespace simgrid::kernel::actor {
 
-/**
- * @brief Represents a simcall to the kernel.
- */
+/** Contains what's needed to run some code in kernel mode on behalf of an actor */
 class Simcall {
 public:
   /** All possible simcalls. */
@@ -29,6 +26,14 @@ public:
   const char* get_cname() const;
 };
 
+/** A thing that can be used for an ObjectAccess simcall (getter or setter). */
+class ObjectAccessSimcallItem {
+public:
+  ObjectAccessSimcallItem();
+  void take_ownership();
+  ActorImpl* simcall_owner_;
+};
+
 } // namespace simgrid::kernel::actor
 
 #endif
index c07d073..0246d5a 100644 (file)
@@ -71,4 +71,24 @@ std::string ActorJoinSimcall::to_string() const
 {
   return std::string("ActorJoin(pid:") + std::to_string(other_->get_pid()) + ")";
 }
+
+void ObjectAccessSimcallObserver::serialize(std::stringstream& stream) const
+{
+  stream << (short)mc::Transition::Type::OBJECT_ACCESS << ' ';
+  stream << object_ << ' ' << get_owner()->get_pid();
+}
+std::string ObjectAccessSimcallObserver::to_string() const
+{
+  return std::string("ObjectAccess(obj:") + ptr_to_id<ObjectAccessSimcallItem const>(object_) +
+         " owner:" + std::to_string(get_owner()->get_pid()) + ")";
+}
+bool ObjectAccessSimcallObserver::is_visible() const
+{
+  return get_owner() != get_issuer();
+}
+ActorImpl* ObjectAccessSimcallObserver::get_owner() const
+{
+  return object_->simcall_owner_;
+}
+
 } // namespace simgrid::kernel::actor
index 5b47b31..cfc60a1 100644 (file)
@@ -125,6 +125,32 @@ public:
   s4u::ActorPtr get_other_actor() const { return other_; }
   double get_timeout() const { return timeout_; }
 };
+
+class ObjectAccessSimcallObserver final : public SimcallObserver {
+  ObjectAccessSimcallItem* const object_;
+
+public:
+  ObjectAccessSimcallObserver(ActorImpl* actor, ObjectAccessSimcallItem* object)
+      : SimcallObserver(actor), object_(object)
+  {
+  }
+  void serialize(std::stringstream& stream) const override;
+  std::string to_string() const override;
+  bool is_visible() const override;
+  bool is_enabled() override { return true; }
+
+  ActorImpl* get_owner() const;
+};
+
+/* Semi private template used by the to_string methods of various observer classes */
+template <typename A> static std::string ptr_to_id(A* ptr)
+{
+  static std::unordered_map<A*, std::string> map;
+  if (map.find(ptr) == map.end())
+    map.insert(std::make_pair(ptr, std::to_string(map.size() + 1)));
+  return map[ptr];
+}
+
 } // namespace simgrid::kernel::actor
 
 #endif
index ea32b92..32355aa 100644 (file)
@@ -7,6 +7,7 @@
 #define SIMGRID_KERNEL_RESOURCE_RESOURCE_HPP
 
 #include "simgrid/forward.h"
+#include "src/kernel/actor/Simcall.hpp"
 #include "src/kernel/lmm/maxmin.hpp" // Constraint
 #include "src/kernel/resource/profile/Event.hpp"
 #include "src/kernel/resource/profile/FutureEvtSet.hpp"
@@ -23,7 +24,7 @@ namespace simgrid::kernel::resource {
  * @brief SURF resource interface class
  * @details This is the ancestor class of every resources in SimGrid, such as links, CPU or disk
  */
-class XBT_PUBLIC Resource {
+class XBT_PUBLIC Resource : public actor::ObjectAccessSimcallItem {
   std::string name_            = "unnamed";
   bool is_on_                  = true;
   bool sealed_                 = false;
index fdeba59..c08b8f1 100644 (file)
@@ -8,6 +8,7 @@
 #include "src/mc/mc_config.hpp"
 #include "src/mc/mc_private.hpp"
 #include "src/mc/sosp/Snapshot.hpp"
+#include "xbt/ex.h"
 
 #include <algorithm>
 
index b10abd2..6b632ee 100644 (file)
@@ -4,6 +4,7 @@
  * under the terms of the license (GNU LGPL) which comes with this package. */
 
 #include "src/mc/transition/Transition.hpp"
+#include "src/kernel/actor/Simcall.hpp"
 #include "xbt/asserts.h"
 #include "xbt/string.hpp"
 #include <simgrid/config.h>
index 47a4b08..80a7818 100644 (file)
@@ -31,7 +31,8 @@ class Transition {
 
 public:
   /* Ordering is important here. depends() implementations only consider subsequent types in this ordering */
-  XBT_DECLARE_ENUM_CLASS(Type, RANDOM, ACTOR_JOIN, /* First because indep with anybody */
+  XBT_DECLARE_ENUM_CLASS(Type, RANDOM, ACTOR_JOIN, /* First because indep with anybody including themselves */
+                         OBJECT_ACCESS,            /* high priority because indep with almost everybody */
                          TESTANY, WAITANY,         /* high priority because they can rewrite themselves to *_WAIT */
                          BARRIER_ASYNC_LOCK, BARRIER_WAIT, /* BARRIER transitions sorted alphabetically */
                          COMM_ASYNC_RECV, COMM_ASYNC_SEND, COMM_TEST, COMM_WAIT, /* Alphabetical ordering of COMM_* */
index e7e7724..b04a2f3 100644 (file)
@@ -7,6 +7,7 @@
 #include <simgrid/s4u/ConditionVariable.hpp>
 #include <xbt/log.h>
 
+#include "src/kernel/activity/ActivityImpl.hpp"
 #include "src/kernel/activity/ConditionVariableImpl.hpp"
 #include "src/kernel/actor/SimcallObserver.hpp"
 
index fa64f72..c10ad5a 100644 (file)
@@ -31,13 +31,13 @@ const char* Disk::get_cname() const
 
 Disk* Disk::set_read_bandwidth(double read_bw)
 {
-  kernel::actor::simcall_answered([this, read_bw] { pimpl_->set_read_bandwidth(read_bw); });
+  kernel::actor::simcall_object_access(pimpl_, [this, read_bw] { pimpl_->set_read_bandwidth(read_bw); });
   return this;
 }
 
 Disk* Disk::set_write_bandwidth(double write_bw)
 {
-  kernel::actor::simcall_answered([this, write_bw] { pimpl_->set_write_bandwidth(write_bw); });
+  kernel::actor::simcall_object_access(pimpl_, [this, write_bw] { pimpl_->set_write_bandwidth(write_bw); });
   return this;
 }
 
@@ -48,7 +48,7 @@ double Disk::get_read_bandwidth() const
 
 Disk* Disk::set_readwrite_bandwidth(double bw)
 {
-  kernel::actor::simcall_answered([this, bw] { pimpl_->set_readwrite_bandwidth(bw); });
+  kernel::actor::simcall_object_access(pimpl_, [this, bw] { pimpl_->set_readwrite_bandwidth(bw); });
   return this;
 }
 
@@ -80,34 +80,36 @@ const char* Disk::get_property(const std::string& key) const
 
 Disk* Disk::set_property(const std::string& key, const std::string& value)
 {
-  kernel::actor::simcall_answered([this, &key, &value] { this->pimpl_->set_property(key, value); });
+  kernel::actor::simcall_object_access(pimpl_, [this, &key, &value] { this->pimpl_->set_property(key, value); });
   return this;
 }
 
 Disk* Disk::set_properties(const std::unordered_map<std::string, std::string>& properties)
 {
-  kernel::actor::simcall_answered([this, properties] { this->pimpl_->set_properties(properties); });
+  kernel::actor::simcall_object_access(pimpl_, [this, properties] { this->pimpl_->set_properties(properties); });
   return this;
 }
 
 Disk* Disk::set_state_profile(kernel::profile::Profile* profile)
 {
   xbt_assert(not pimpl_->is_sealed(), "Cannot set a state profile once the Disk is sealed");
-  kernel::actor::simcall_answered([this, profile]() { this->pimpl_->set_state_profile(profile); });
+  kernel::actor::simcall_object_access(pimpl_, [this, profile]() { this->pimpl_->set_state_profile(profile); });
   return this;
 }
 
 Disk* Disk::set_read_bandwidth_profile(kernel::profile::Profile* profile)
 {
   xbt_assert(not pimpl_->is_sealed(), "Cannot set a bandwidth profile once the Disk is sealed");
-  kernel::actor::simcall_answered([this, profile]() { this->pimpl_->set_read_bandwidth_profile(profile); });
+  kernel::actor::simcall_object_access(pimpl_,
+                                       [this, profile]() { this->pimpl_->set_read_bandwidth_profile(profile); });
   return this;
 }
 
 Disk* Disk::set_write_bandwidth_profile(kernel::profile::Profile* profile)
 {
   xbt_assert(not pimpl_->is_sealed(), "Cannot set a bandwidth profile once the Disk is sealed");
-  kernel::actor::simcall_answered([this, profile]() { this->pimpl_->set_write_bandwidth_profile(profile); });
+  kernel::actor::simcall_object_access(pimpl_,
+                                       [this, profile]() { this->pimpl_->set_write_bandwidth_profile(profile); });
   return this;
 }
 
@@ -156,7 +158,7 @@ sg_size_t Disk::write(sg_size_t size, double priority) const
 
 Disk* Disk::set_sharing_policy(Disk::Operation op, Disk::SharingPolicy policy, const NonLinearResourceCb& cb)
 {
-  kernel::actor::simcall_answered([this, op, policy, &cb] { pimpl_->set_sharing_policy(op, policy, cb); });
+  kernel::actor::simcall_object_access(pimpl_, [this, op, policy, &cb] { pimpl_->set_sharing_policy(op, policy, cb); });
   return this;
 }
 
@@ -167,7 +169,7 @@ Disk::SharingPolicy Disk::get_sharing_policy(Operation op) const
 
 Disk* Disk::set_factor_cb(const std::function<IoFactorCb>& cb)
 {
-  kernel::actor::simcall_answered([this, &cb] { pimpl_->set_factor_cb(cb); });
+  kernel::actor::simcall_object_access(pimpl_, [this, &cb] { pimpl_->set_factor_cb(cb); });
   return this;
 }
 
index 286340f..2494698 100644 (file)
@@ -3,6 +3,7 @@
 /* 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 "simgrid/simix.hpp"
 #include <simgrid/Exception.hpp>
 #include <simgrid/exec.h>
 #include <simgrid/s4u/Exec.hpp>
@@ -74,8 +75,9 @@ ExecPtr Exec::set_bound(double bound)
 {
   xbt_assert(state_ == State::INITED || state_ == State::STARTING,
              "Cannot change the bound of an exec after its start");
-  kernel::actor::simcall_answered(
-      [this, bound] { boost::static_pointer_cast<kernel::activity::ExecImpl>(pimpl_)->set_bound(bound); });
+  kernel::actor::simcall_object_access(pimpl_.get(), [this, bound] {
+    boost::static_pointer_cast<kernel::activity::ExecImpl>(pimpl_)->set_bound(bound);
+  });
   return this;
 }
 
@@ -89,7 +91,7 @@ ExecPtr Exec::set_priority(double priority)
 {
   xbt_assert(state_ == State::INITED || state_ == State::STARTING,
              "Cannot change the priority of an exec after its start");
-  kernel::actor::simcall_answered([this, priority] {
+  kernel::actor::simcall_object_access(pimpl_.get(), [this, priority] {
     boost::static_pointer_cast<kernel::activity::ExecImpl>(pimpl_)->set_sharing_penalty(1. / priority);
   });
   return this;
@@ -107,7 +109,7 @@ ExecPtr Exec::set_flops_amount(double flops_amount)
 {
   xbt_assert(state_ == State::INITED || state_ == State::STARTING,
       "Cannot change the flop_amount of an exec after its start");
-  kernel::actor::simcall_answered([this, flops_amount] {
+  kernel::actor::simcall_object_access(pimpl_.get(), [this, flops_amount] {
     boost::static_pointer_cast<kernel::activity::ExecImpl>(pimpl_)->set_flops_amount(flops_amount);
   });
   set_remaining(flops_amount);
@@ -118,7 +120,7 @@ ExecPtr Exec::set_flops_amounts(const std::vector<double>& flops_amounts)
 {
   xbt_assert(state_ == State::INITED || state_ == State::STARTING,
       "Cannot change the flops_amounts of an exec after its start");
-  kernel::actor::simcall_answered([this, flops_amounts] {
+  kernel::actor::simcall_object_access(pimpl_.get(), [this, flops_amounts] {
     boost::static_pointer_cast<kernel::activity::ExecImpl>(pimpl_)->set_flops_amounts(flops_amounts);
   });
   parallel_      = true;
@@ -129,7 +131,7 @@ ExecPtr Exec::set_bytes_amounts(const std::vector<double>& bytes_amounts)
 {
   xbt_assert(state_ == State::INITED || state_ == State::STARTING,
       "Cannot change the bytes_amounts of an exec after its start");
-  kernel::actor::simcall_answered([this, bytes_amounts] {
+  kernel::actor::simcall_object_access(pimpl_.get(), [this, bytes_amounts] {
     boost::static_pointer_cast<kernel::activity::ExecImpl>(pimpl_)->set_bytes_amounts(bytes_amounts);
   });
   parallel_      = true;
@@ -140,7 +142,7 @@ ExecPtr Exec::set_thread_count(int thread_count)
 {
   xbt_assert(state_ == State::INITED || state_ == State::STARTING,
              "Cannot change the bytes_amounts of an exec after its start");
-  kernel::actor::simcall_answered([this, thread_count] {
+  kernel::actor::simcall_object_access(pimpl_.get(), [this, thread_count] {
     boost::static_pointer_cast<kernel::activity::ExecImpl>(pimpl_)->set_thread_count(thread_count);
   });
   return this;
@@ -174,8 +176,8 @@ ExecPtr Exec::set_host(Host* host)
   if (state_ == State::STARTED)
     boost::static_pointer_cast<kernel::activity::ExecImpl>(pimpl_)->migrate(host);
 
-  kernel::actor::simcall_answered(
-      [this, host] { boost::static_pointer_cast<kernel::activity::ExecImpl>(pimpl_)->set_host(host); });
+  kernel::actor::simcall_object_access(
+      pimpl_.get(), [this, host] { boost::static_pointer_cast<kernel::activity::ExecImpl>(pimpl_)->set_host(host); });
 
   if (state_ == State::STARTING)
   // Setting the host may allow to start the activity, let's try
@@ -189,8 +191,9 @@ ExecPtr Exec::set_hosts(const std::vector<Host*>& hosts)
   xbt_assert(state_ == State::INITED || state_ == State::STARTING,
              "Cannot change the hosts of an exec once it's done (state: %s)", to_c_str(state_));
 
-  kernel::actor::simcall_answered(
-      [this, hosts] { boost::static_pointer_cast<kernel::activity::ExecImpl>(pimpl_)->set_hosts(hosts); });
+  kernel::actor::simcall_object_access(pimpl_.get(), [this, hosts] {
+    boost::static_pointer_cast<kernel::activity::ExecImpl>(pimpl_)->set_hosts(hosts);
+  });
   parallel_ = true;
 
   // Setting the host may allow to start the activity, let's try
index 4266d80..6f80d6e 100644 (file)
@@ -13,6 +13,7 @@
 #include <simgrid/s4u/VirtualMachine.hpp>
 #include <xbt/parse_units.hpp>
 
+#include "simgrid/simix.hpp"
 #include "src/kernel/resource/StandardLinkImpl.hpp"
 #include "src/kernel/resource/VirtualMachineImpl.hpp"
 #include "src/surf/HostImpl.hpp"
@@ -196,13 +197,13 @@ const char* Host::get_property(const std::string& key) const
 
 Host* Host::set_property(const std::string& key, const std::string& value)
 {
-  kernel::actor::simcall_answered([this, &key, &value] { this->pimpl_->set_property(key, value); });
+  kernel::actor::simcall_object_access(pimpl_, [this, &key, &value] { this->pimpl_->set_property(key, value); });
   return this;
 }
 
 Host* Host::set_properties(const std::unordered_map<std::string, std::string>& properties)
 {
-  kernel::actor::simcall_answered([this, &properties] { this->pimpl_->set_properties(properties); });
+  kernel::actor::simcall_object_access(pimpl_, [this, &properties] { this->pimpl_->set_properties(properties); });
   return this;
 }
 
@@ -210,7 +211,7 @@ Host* Host::set_properties(const std::unordered_map<std::string, std::string>& p
  * The profile must contain boolean values. */
 Host* Host::set_state_profile(kernel::profile::Profile* p)
 {
-  kernel::actor::simcall_answered([this, p] { pimpl_cpu_->set_state_profile(p); });
+  kernel::actor::simcall_object_access(pimpl_, [this, p] { pimpl_cpu_->set_state_profile(p); });
   return this;
 }
 /** Specify a profile modeling the external load according to an exhaustive list or a stochastic law.
@@ -221,7 +222,7 @@ Host* Host::set_state_profile(kernel::profile::Profile* p)
  */
 Host* Host::set_speed_profile(kernel::profile::Profile* p)
 {
-  kernel::actor::simcall_answered([this, p] { pimpl_cpu_->set_speed_profile(p); });
+  kernel::actor::simcall_object_access(pimpl_, [this, p] { pimpl_cpu_->set_speed_profile(p); });
   return this;
 }
 
@@ -246,7 +247,7 @@ double Host::get_available_speed() const
 
 Host* Host::set_sharing_policy(SharingPolicy policy, const s4u::NonLinearResourceCb& cb)
 {
-  kernel::actor::simcall_answered([this, policy, &cb] { pimpl_cpu_->set_sharing_policy(policy, cb); });
+  kernel::actor::simcall_object_access(pimpl_, [this, policy, &cb] { pimpl_cpu_->set_sharing_policy(policy, cb); });
   return this;
 }
 
@@ -262,13 +263,14 @@ int Host::get_core_count() const
 
 Host* Host::set_core_count(int core_count)
 {
-  kernel::actor::simcall_answered([this, core_count] { this->pimpl_cpu_->set_core_count(core_count); });
+  kernel::actor::simcall_object_access(pimpl_, [this, core_count] { this->pimpl_cpu_->set_core_count(core_count); });
   return this;
 }
 
 Host* Host::set_pstate_speed(const std::vector<double>& speed_per_state)
 {
-  kernel::actor::simcall_answered([this, &speed_per_state] { pimpl_cpu_->set_pstate_speed(speed_per_state); });
+  kernel::actor::simcall_object_access(pimpl_,
+                                       [this, &speed_per_state] { pimpl_cpu_->set_pstate_speed(speed_per_state); });
   return this;
 }
 
@@ -296,7 +298,7 @@ Host* Host::set_pstate_speed(const std::vector<std::string>& speed_per_state)
 /** @brief Set the pstate at which the host should run */
 Host* Host::set_pstate(unsigned long pstate_index)
 {
-  kernel::actor::simcall_answered([this, pstate_index] { this->pimpl_cpu_->set_pstate(pstate_index); });
+  kernel::actor::simcall_object_access(pimpl_, [this, pstate_index] { this->pimpl_cpu_->set_pstate(pstate_index); });
   return this;
 }
 
@@ -308,14 +310,14 @@ unsigned long Host::get_pstate() const
 
 Host* Host::set_factor_cb(const std::function<CpuFactorCb>& cb)
 {
-  kernel::actor::simcall_answered([this, &cb] { pimpl_cpu_->set_factor_cb(cb); });
+  kernel::actor::simcall_object_access(pimpl_, [this, &cb] { pimpl_cpu_->set_factor_cb(cb); });
   return this;
 }
 
 Host* Host::set_coordinates(const std::string& coords)
 {
   if (not coords.empty())
-    kernel::actor::simcall_answered([this, coords] { this->pimpl_netpoint_->set_coordinates(coords); });
+    kernel::actor::simcall_object_access(pimpl_, [this, coords] { this->pimpl_netpoint_->set_coordinates(coords); });
   return this;
 }
 std::vector<Disk*> Host::get_disks() const
index 6d34be9..a463ce1 100644 (file)
@@ -48,12 +48,11 @@ IoPtr Io::set_source(Host* from, Disk* from_disk)
 {
   xbt_assert(state_ == State::INITED || state_ == State::STARTING,
              "Cannot change the source of an IO stream once it's started (state: %s)", to_c_str(state_));
-  kernel::actor::simcall_answered(
-      [this, from, from_disk] {
-        boost::static_pointer_cast<kernel::activity::IoImpl>(pimpl_)->set_host(from);
-        if (from_disk != nullptr)
-          boost::static_pointer_cast<kernel::activity::IoImpl>(pimpl_)->set_disk(from_disk->get_impl());
-      });
+  kernel::actor::simcall_object_access(pimpl_.get(), [this, from, from_disk] {
+    boost::static_pointer_cast<kernel::activity::IoImpl>(pimpl_)->set_host(from);
+    if (from_disk != nullptr)
+      boost::static_pointer_cast<kernel::activity::IoImpl>(pimpl_)->set_disk(from_disk->get_impl());
+  });
   // Setting 'source' may allow to start the activity, let's try
   if (state_ == State::STARTING && remains_ <= 0)
     XBT_DEBUG("This IO has a size of 0 byte. It cannot start yet");
@@ -67,12 +66,11 @@ IoPtr Io::set_destination(Host* to, Disk* to_disk)
 {
   xbt_assert(state_ == State::INITED || state_ == State::STARTING,
              "Cannot change the source of an IO stream once it's started (state: %s)", to_c_str(state_));
-  kernel::actor::simcall_answered(
-      [this, to, to_disk] {
-        boost::static_pointer_cast<kernel::activity::IoImpl>(pimpl_)->set_dst_host(to);
-        if (to_disk != nullptr)
-          boost::static_pointer_cast<kernel::activity::IoImpl>(pimpl_)->set_dst_disk(to_disk->get_impl());
-      });
+  kernel::actor::simcall_object_access(pimpl_.get(), [this, to, to_disk] {
+    boost::static_pointer_cast<kernel::activity::IoImpl>(pimpl_)->set_dst_host(to);
+    if (to_disk != nullptr)
+      boost::static_pointer_cast<kernel::activity::IoImpl>(pimpl_)->set_dst_disk(to_disk->get_impl());
+  });
   // Setting 'destination' may allow to start the activity, let's try
   if (state_ == State::STARTING && remains_ <= 0)
     XBT_DEBUG("This IO has a size of 0 byte. It cannot start yet");
@@ -121,7 +119,7 @@ IoPtr Io::set_priority(double priority)
 {
   xbt_assert(state_ == State::INITED || state_ == State::STARTING,
              "Cannot change the priority of an io after its start");
-  kernel::actor::simcall_answered([this, priority] {
+  kernel::actor::simcall_object_access(pimpl_.get(), [this, priority] {
     boost::static_pointer_cast<kernel::activity::IoImpl>(pimpl_)->set_sharing_penalty(1. / priority);
   });
   return this;
@@ -130,8 +128,8 @@ IoPtr Io::set_priority(double priority)
 IoPtr Io::set_size(sg_size_t size)
 {
   xbt_assert(state_ == State::INITED || state_ == State::STARTING, "Cannot set size once the Io is started");
-  kernel::actor::simcall_answered(
-      [this, size] { boost::static_pointer_cast<kernel::activity::IoImpl>(pimpl_)->set_size(size); });
+  kernel::actor::simcall_object_access(
+      pimpl_.get(), [this, size] { boost::static_pointer_cast<kernel::activity::IoImpl>(pimpl_)->set_size(size); });
   set_remaining(size);
   return this;
 }
@@ -139,8 +137,8 @@ IoPtr Io::set_size(sg_size_t size)
 IoPtr Io::set_op_type(OpType type)
 {
   xbt_assert(state_ == State::INITED || state_ == State::STARTING, "Cannot set size once the Io is started");
-  kernel::actor::simcall_answered(
-      [this, type] { boost::static_pointer_cast<kernel::activity::IoImpl>(pimpl_)->set_type(type); });
+  kernel::actor::simcall_object_access(
+      pimpl_.get(), [this, type] { boost::static_pointer_cast<kernel::activity::IoImpl>(pimpl_)->set_type(type); });
   return this;
 }
 
@@ -155,8 +153,8 @@ IoPtr Io::update_priority(double priority)
 /** @brief Returns the amount of flops that remain to be done */
 double Io::get_remaining() const
 {
-  return kernel::actor::simcall_answered(
-      [this]() { return boost::static_pointer_cast<kernel::activity::IoImpl>(pimpl_)->get_remaining(); });
+  return kernel::actor::simcall_object_access(
+      pimpl_.get(), [this]() { return boost::static_pointer_cast<kernel::activity::IoImpl>(pimpl_)->get_remaining(); });
 }
 
 sg_size_t Io::get_performed_ioops() const
index c1d4ffb..a35cd13 100644 (file)
@@ -72,7 +72,7 @@ double Link::get_latency() const
 
 Link* Link::set_latency(double value)
 {
-  kernel::actor::simcall_answered([this, value] { pimpl_->set_latency(value); });
+  kernel::actor::simcall_object_access(pimpl_, [this, value] { pimpl_->set_latency(value); });
   return this;
 }
 
@@ -95,7 +95,7 @@ double Link::get_bandwidth() const
 
 Link* Link::set_bandwidth(double value)
 {
-  kernel::actor::simcall_answered([this, value] { pimpl_->set_bandwidth(value); });
+  kernel::actor::simcall_object_access(pimpl_, [this, value] { pimpl_->set_bandwidth(value); });
   return this;
 }
 
@@ -105,7 +105,7 @@ Link* Link::set_sharing_policy(Link::SharingPolicy policy, const NonLinearResour
     throw std::invalid_argument(std::string("Impossible to set wifi or split-duplex for the link: ") + get_name() +
                                 std::string(". Use appropriate create function in NetZone."));
 
-  kernel::actor::simcall_answered([this, policy, &cb] { pimpl_->set_sharing_policy(policy, cb); });
+  kernel::actor::simcall_object_access(pimpl_, [this, policy, &cb] { pimpl_->set_sharing_policy(policy, cb); });
   return this;
 }
 Link::SharingPolicy Link::get_sharing_policy() const
@@ -122,7 +122,7 @@ void Link::set_host_wifi_rate(const s4u::Host* host, int level) const
 
 Link* Link::set_concurrency_limit(int limit)
 {
-  kernel::actor::simcall_answered([this, limit] { pimpl_->set_concurrency_limit(limit); });
+  kernel::actor::simcall_object_access(pimpl_, [this, limit] { pimpl_->set_concurrency_limit(limit); });
   return this;
 }
 
@@ -154,21 +154,21 @@ bool Link::is_on() const
 Link* Link::set_state_profile(kernel::profile::Profile* profile)
 {
   xbt_assert(not pimpl_->is_sealed(), "Cannot set a state profile once the Link is sealed");
-  kernel::actor::simcall_answered([this, profile]() { this->pimpl_->set_state_profile(profile); });
+  kernel::actor::simcall_object_access(pimpl_, [this, profile]() { this->pimpl_->set_state_profile(profile); });
   return this;
 }
 
 Link* Link::set_bandwidth_profile(kernel::profile::Profile* profile)
 {
   xbt_assert(not pimpl_->is_sealed(), "Cannot set a bandwidth profile once the Link is sealed");
-  kernel::actor::simcall_answered([this, profile]() { this->pimpl_->set_bandwidth_profile(profile); });
+  kernel::actor::simcall_object_access(pimpl_, [this, profile]() { this->pimpl_->set_bandwidth_profile(profile); });
   return this;
 }
 
 Link* Link::set_latency_profile(kernel::profile::Profile* profile)
 {
   xbt_assert(not pimpl_->is_sealed(), "Cannot set a latency profile once the Link is sealed");
-  kernel::actor::simcall_answered([this, profile]() { this->pimpl_->set_latency_profile(profile); });
+  kernel::actor::simcall_object_access(pimpl_, [this, profile]() { this->pimpl_->set_latency_profile(profile); });
   return this;
 }
 
@@ -178,7 +178,7 @@ const char* Link::get_property(const std::string& key) const
 }
 Link* Link::set_property(const std::string& key, const std::string& value)
 {
-  kernel::actor::simcall_answered([this, &key, &value] { this->pimpl_->set_property(key, value); });
+  kernel::actor::simcall_object_access(pimpl_, [this, &key, &value] { this->pimpl_->set_property(key, value); });
   return this;
 }
 
@@ -189,7 +189,7 @@ const std::unordered_map<std::string, std::string>* Link::get_properties() const
 
 Link* Link::set_properties(const std::unordered_map<std::string, std::string>& properties)
 {
-  kernel::actor::simcall_answered([this, &properties] { this->pimpl_->set_properties(properties); });
+  kernel::actor::simcall_object_access(pimpl_, [this, &properties] { this->pimpl_->set_properties(properties); });
   return this;
 }
 
index f607ad8..46b643e 100644 (file)
@@ -3,6 +3,7 @@
 /* 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 "simgrid/simix.hpp"
 #include <simgrid/Exception.hpp>
 #include <simgrid/kernel/routing/NetPoint.hpp>
 #include <simgrid/vm.h>
index 7929e52..895bbad 100644 (file)
 /* 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 "simgrid/config.h"
+#include "simgrid/modelchecker.h"
 #include "src/kernel/EngineImpl.hpp"
 #include "src/kernel/activity/CommImpl.hpp"
 #include "src/kernel/actor/SimcallObserver.hpp"
+#include "src/mc/mc_replay.hpp"
 #include <simgrid/s4u/Activity.hpp>
 
 #define SIMIX_H_NO_DEPRECATED_WARNING // avoid deprecation warning on include (remove with XBT_ATTRIB_DEPRECATED_v335)
@@ -189,3 +192,28 @@ void simcall_run_blocking(std::function<void()> const& code, simgrid::kernel::ac
   // BUT simcall_answer IS NOT CALLED
   simcall(simgrid::kernel::actor::Simcall::Type::RUN_BLOCKING, code, observer);
 }
+
+void simcall_run_object_access(std::function<void()> const& code, simgrid::kernel::actor::ObjectAccessSimcallItem* item)
+{
+  auto self = simgrid::kernel::actor::ActorImpl::self();
+
+  // We only need a simcall if the order of the setters is important (parallel run or MC execution).
+  // Otherwise, just call the function with no simcall
+
+  if (simgrid::kernel::context::is_parallel()
+#if SIMGRID_HAVE_MC
+      || MC_is_active() || MC_record_replay_is_active()
+#endif
+  ) {
+
+    simgrid::kernel::actor::ObjectAccessSimcallObserver observer{self, item};
+    simcall(simgrid::kernel::actor::Simcall::Type::RUN_ANSWERED, code, &observer);
+    item->take_ownership();
+  } else {
+    // don't return from the context-switch we don't do
+    self->simcall_.call_     = simgrid::kernel::actor::Simcall::Type::RUN_BLOCKING;
+    self->simcall_.code_     = &code;
+    self->simcall_.observer_ = nullptr;
+    self->simcall_handle(0);
+  }
+}
\ No newline at end of file
index 13c0772..3184186 100644 (file)
@@ -39,7 +39,7 @@ public:
  * @brief SURF Host interface class
  * @details A host represents a machine with an aggregation of a Cpu, a RoutingEdge and Disk(s)
  */
-class XBT_PRIVATE HostImpl : public xbt::PropertyHolder {
+class XBT_PRIVATE HostImpl : public xbt::PropertyHolder, public actor::ObjectAccessSimcallItem {
   using ActorList =
       boost::intrusive::list<actor::ActorImpl,
                              boost::intrusive::member_hook<actor::ActorImpl, boost::intrusive::list_member_hook<>,
index f724c4d..463c56c 100644 (file)
@@ -89,9 +89,9 @@ $ ./storage_client_server ${platfdir}/hosts_with_disks.xml "--log=root.fmt:[%10.
 > [  1.207952] (server@alice)   /tmp/titi.xml size: 654 bytes
 > [  1.207952] (server@alice)   /tmp/toto.xml size: 972 bytes
 > [  1.207952] (server@alice) Disk1 is attached to alice
+> [  1.207952] (server@alice) Disk1 is attached to bob
+> [  1.207952] (server@alice) Disk2 is attached to bob
 > [  1.207952] (client@bob) *** GET/SET DATA for disk: Disk1 ***
 > [  1.207952] (client@bob) Get data: 'No User Data'
 > [  1.207952] (client@bob)   Set and get data: 'Some data'
-> [  1.207952] (server@alice) Disk1 is attached to bob
-> [  1.207952] (server@alice) Disk2 is attached to bob
 > [  1.207952] (maestro@) Simulated time: 1.20795