> [ 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
> [ 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
> [ 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
> [ 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
> [ 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
> [ 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
class Simcall;
class SimcallObserver;
+class ObjectAccessSimcallObserver;
+class ObjectAccessSimcallItem;
} // namespace actor
namespace activity {
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,
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
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
#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;
#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>
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)) {
/* 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"
return to_c_str(call_);
}
}
+ObjectAccessSimcallItem::ObjectAccessSimcallItem()
+{
+ take_ownership();
+}
+void ObjectAccessSimcallItem::take_ownership()
+{
+ simcall_owner_ = ActorImpl::self();
+}
} // namespace simgrid::kernel::actor
/* 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. */
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
{
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
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
#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"
* @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;
#include "src/mc/mc_config.hpp"
#include "src/mc/mc_private.hpp"
#include "src/mc/sosp/Snapshot.hpp"
+#include "xbt/ex.h"
#include <algorithm>
* 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>
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_* */
#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"
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;
}
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;
}
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;
}
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;
}
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;
}
/* 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>
{
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;
}
{
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;
{
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);
{
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;
{
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;
{
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;
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
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
#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"
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;
}
* 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.
*/
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;
}
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;
}
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;
}
/** @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;
}
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
{
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");
{
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");
{
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;
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;
}
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;
}
/** @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
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;
}
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;
}
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
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;
}
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;
}
}
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;
}
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;
}
/* 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>
/* 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)
// 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
* @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<>,
> [ 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