-/* Copyright (c) 2013-2021. The SimGrid Team. All rights reserved. */
+/* Copyright (c) 2013-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. */
#include <simgrid/Exception.hpp>
+#include <simgrid/kernel/routing/NetPoint.hpp>
#include <simgrid/kernel/routing/NetZoneImpl.hpp>
#include <simgrid/s4u/Exec.hpp>
-#include "simgrid/sg_config.hpp"
#include "src/kernel/EngineImpl.hpp"
#include "src/kernel/activity/ExecImpl.hpp"
#include "src/kernel/resource/VirtualMachineImpl.hpp"
-#include "src/surf/cpu_cas01.hpp"
-#include "src/surf/cpu_ti.hpp"
+#include "src/kernel/resource/models/cpu_cas01.hpp"
+#include "src/kernel/resource/models/cpu_ti.hpp"
+#include "src/simgrid/module.hpp"
+#include "src/simgrid/sg_config.hpp"
+
+#include <numeric>
XBT_LOG_NEW_DEFAULT_SUBCATEGORY(res_vm, ker_resource, "Virtual Machines, containing actors and mobile across hosts");
-void surf_vm_model_init_HL13(simgrid::kernel::resource::CpuModel* cpu_pm_model)
+void simgrid_vm_model_init_HL13()
{
+ auto* cpu_pm_model = simgrid::s4u::Engine::get_instance()->get_netzone_root()->get_impl()->get_cpu_pm_model().get();
auto vm_model = std::make_shared<simgrid::kernel::resource::VMModel>("VM_HL13");
auto* engine = simgrid::kernel::EngineImpl::get_instance();
engine->add_model(vm_model, {cpu_pm_model});
std::shared_ptr<simgrid::kernel::resource::CpuModel> cpu_model_vm;
- auto cpu_optim = simgrid::config::get_value<std::string>("cpu/optim");
- if (cpu_optim == "TI") {
+ if (simgrid::config::get_value<std::string>("cpu/optim") == "TI") {
cpu_model_vm = std::make_shared<simgrid::kernel::resource::CpuTiModel>("VmCpu_TI");
} else {
cpu_model_vm = std::make_shared<simgrid::kernel::resource::CpuCas01Model>("VmCpu_Cas01");
namespace simgrid {
template class xbt::Extendable<kernel::resource::VirtualMachineImpl>;
-namespace kernel {
-namespace resource {
+namespace kernel::resource {
/*********
* Model *
*/
const double virt_overhead = 1; // 0.95
-static void host_state_change(s4u::Host const& host)
+static void host_onoff(s4u::Host const& host)
{
if (not host.is_on()) { // just turned off.
std::vector<s4u::VirtualMachine*> trash;
/* Find all VMs living on that host */
- for (s4u::VirtualMachine* const& vm : VirtualMachineImpl::allVms_)
+ for (auto* vm : VirtualMachineImpl::allVms_)
if (vm->get_pm() == &host)
trash.push_back(vm);
- for (s4u::VirtualMachine* vm : trash)
+ for (auto* vm : trash)
vm->shutdown();
}
}
const s4u::VirtualMachine* vm = dynamic_cast<s4u::VirtualMachine*>(task.get_host());
if (vm != nullptr) {
VirtualMachineImpl* vm_impl = vm->get_vm_impl();
- vm_impl->add_active_exec();
+ for (int i = 1; i <= task.get_thread_count(); i++)
+ vm_impl->add_active_exec();
vm_impl->update_action_weight();
}
}
-static void remove_active_exec(s4u::Activity& task)
+static void remove_active_exec(s4u::Exec const& exec)
{
- const auto* exec = dynamic_cast<s4u::Exec*>(&task);
- if (exec == nullptr)
- return;
- if (not exec->is_assigned())
+ if (not exec.is_assigned())
return;
- const s4u::VirtualMachine* vm = dynamic_cast<s4u::VirtualMachine*>(exec->get_host());
+ const s4u::VirtualMachine* vm = dynamic_cast<s4u::VirtualMachine*>(exec.get_host());
if (vm != nullptr) {
VirtualMachineImpl* vm_impl = vm->get_vm_impl();
- vm_impl->remove_active_exec();
+ for (int i = 1; i <= exec.get_thread_count(); i++)
+ vm_impl->remove_active_exec();
vm_impl->update_action_weight();
}
}
-static s4u::VirtualMachine* get_vm_from_activity(kernel::activity::ActivityImpl const& act)
+static s4u::VirtualMachine* get_vm_from_activity(s4u::Activity const& act)
{
- auto* exec = dynamic_cast<kernel::activity::ExecImpl const*>(&act);
+ auto* exec = dynamic_cast<kernel::activity::ExecImpl const*>(act.get_impl());
return exec != nullptr ? dynamic_cast<s4u::VirtualMachine*>(exec->get_host()) : nullptr;
}
-static void add_active_activity(kernel::activity::ActivityImpl const& act)
+static void add_active_activity(s4u::Activity const& act)
{
const s4u::VirtualMachine* vm = get_vm_from_activity(act);
if (vm != nullptr) {
}
}
-static void remove_active_activity(kernel::activity::ActivityImpl const& act)
+static void remove_active_activity(s4u::Activity const& act)
{
const s4u::VirtualMachine* vm = get_vm_from_activity(act);
if (vm != nullptr) {
VMModel::VMModel(const std::string& name) : HostModel(name)
{
- s4u::Host::on_state_change_cb(host_state_change);
+ s4u::Host::on_onoff_cb(host_onoff);
s4u::Exec::on_start_cb(add_active_exec);
- s4u::Activity::on_completion_cb(remove_active_exec);
- activity::ActivityImpl::on_resumed.connect(add_active_activity);
- activity::ActivityImpl::on_suspended.connect(remove_active_activity);
+ s4u::Exec::on_completion_cb(remove_active_exec);
+ s4u::Exec::on_resume_cb(add_active_activity);
+ s4u::Exec::on_suspend_cb(remove_active_activity);
}
double VMModel::next_occurring_event(double now)
**/
/* iterate for all virtual machines */
- for (s4u::VirtualMachine* const& ws_vm : VirtualMachineImpl::allVms_) {
+ for (auto const* ws_vm : VirtualMachineImpl::allVms_) {
if (ws_vm->get_state() == s4u::VirtualMachine::State::SUSPENDED) // Ignore suspended VMs
continue;
return -1.0;
}
+Action* VMModel::execute_thread(const s4u::Host* host, double flops_amount, int thread_count)
+{
+ auto cpu = host->get_cpu();
+ return cpu->execution_start(thread_count * flops_amount, thread_count, -1);
+}
+
/************
* Resource *
************/
VirtualMachineImpl::VirtualMachineImpl(const std::string& name, s4u::VirtualMachine* piface,
simgrid::s4u::Host* host_PM, int core_amount, size_t ramsize)
- : HostImpl(name, piface), piface_(piface), physical_host_(host_PM), core_amount_(core_amount), ramsize_(ramsize)
+ : VirtualMachineImpl(name, host_PM, core_amount, ramsize)
+{
+ set_piface(piface);
+}
+
+VirtualMachineImpl::VirtualMachineImpl(const std::string& name, simgrid::s4u::Host* host_PM, int core_amount,
+ size_t ramsize)
+ : HostImpl(name), physical_host_(host_PM), core_amount_(core_amount), ramsize_(ramsize)
{
- /* Register this VM to the list of all VMs */
- allVms_.push_back(piface);
/* We create cpu_action corresponding to a VM process on the host operating system. */
/* TODO: we have to periodically input GUESTOS_NOISE to the system? how ?
* The value for GUESTOS_NOISE corresponds to the cost of the global action associated to the VM. It corresponds to
* the cost of a VM running no tasks.
*/
- action_ = physical_host_->get_cpu()->execution_start(0, core_amount_);
+ action_ = physical_host_->get_cpu()->execution_start(0, core_amount_, 0);
// It's empty for now, so it should not request resources in the PM
update_action_weight();
-
XBT_VERB("Create VM(%s)@PM(%s)", name.c_str(), physical_host_->get_cname());
}
+void VirtualMachineImpl::set_piface(s4u::VirtualMachine* piface)
+{
+ xbt_assert(not piface_, "Pointer to interface already configured for this VM (%s)", get_cname());
+ piface_ = piface;
+ /* Register this VM to the list of all VMs */
+ allVms_.push_back(piface);
+}
+
/** @brief A physical host does not disappear in the current SimGrid code, but a VM may disappear during a simulation */
void VirtualMachineImpl::vm_destroy()
{
- s4u::VirtualMachine::on_destruction(*piface_);
/* I was already removed from the allVms set if the VM was destroyed cleanly */
- auto iter = find(allVms_.begin(), allVms_.end(), piface_);
- if (iter != allVms_.end())
+ if (auto iter = find(allVms_.begin(), allVms_.end(), piface_); iter != allVms_.end())
allVms_.erase(iter);
/* Free the cpu_action of the VM. */
XBT_ATTRIB_UNUSED bool ret = action_->unref();
xbt_assert(ret, "Bug: some resource still remains");
+
+ // VM uses the host's netpoint, clean but don't destroy it
+ get_iface()->set_netpoint(nullptr);
+ // Take a temporary copy to delete iface safely after impl is destroy'ed
+ const auto* iface = get_iface();
+ // calls the HostImpl() destroy, it'll delete the impl object
+ destroy();
+
+ delete iface;
}
-void VirtualMachineImpl::suspend(smx_actor_t issuer)
+void VirtualMachineImpl::start()
{
+ s4u::VirtualMachine::on_start(*get_iface());
+ get_iface()->on_this_start(*get_iface());
+ s4u::VmHostExt::ensureVmExtInstalled();
+
+ if (physical_host_->extension<s4u::VmHostExt>() == nullptr)
+ physical_host_->extension_set(new s4u::VmHostExt());
+
+ if (size_t pm_ramsize = physical_host_->extension<s4u::VmHostExt>()->ramsize;
+ pm_ramsize &&
+ not physical_host_->extension<s4u::VmHostExt>()->overcommit) { /* Need to verify that we don't overcommit */
+ /* Retrieve the memory occupied by the VMs on that host. Yep, we have to traverse all VMs of all hosts for that */
+ size_t total_ramsize_of_vms = 0;
+ for (auto const* ws_vm : allVms_)
+ if (physical_host_ == ws_vm->get_pm())
+ total_ramsize_of_vms += ws_vm->get_ramsize();
+
+ if (total_ramsize_of_vms + get_ramsize() > pm_ramsize) {
+ XBT_WARN("cannot start %s@%s due to memory shortage: get_ramsize() %zu, free %zu, pm_ramsize %zu (bytes).",
+ get_cname(), physical_host_->get_cname(), get_ramsize(), pm_ramsize - total_ramsize_of_vms, pm_ramsize);
+ throw VmFailureException(XBT_THROW_POINT,
+ xbt::string_printf("Memory shortage on host '%s', VM '%s' cannot be started",
+ physical_host_->get_cname(), get_cname()));
+ }
+ }
+ vm_state_ = s4u::VirtualMachine::State::RUNNING;
+
+ s4u::VirtualMachine::on_started(*get_iface());
+ get_iface()->on_this_started(*get_iface());
+}
+
+void VirtualMachineImpl::suspend(const actor::ActorImpl* issuer)
+{
+ s4u::VirtualMachine::on_suspend(*get_iface());
+ get_iface()->on_this_suspend(*get_iface());
+
if (vm_state_ != s4u::VirtualMachine::State::RUNNING)
throw VmFailureException(XBT_THROW_POINT,
xbt::string_printf("Cannot suspend VM %s: it is not running.", piface_->get_cname()));
});
vm_state_ = s4u::VirtualMachine::State::RUNNING;
+ s4u::VirtualMachine::on_resume(*get_iface());
+ get_iface()->on_this_resume(*get_iface());
}
/** @brief Power off a VM.
*
* @param issuer the actor requesting the shutdown
*/
-void VirtualMachineImpl::shutdown(smx_actor_t issuer)
+void VirtualMachineImpl::shutdown(actor::ActorImpl* issuer)
{
if (vm_state_ != s4u::VirtualMachine::State::RUNNING)
XBT_VERB("Shutting down the VM %s even if it's not running but in state %s", piface_->get_cname(),
set_state(s4u::VirtualMachine::State::DESTROYED);
- /* FIXME: we may have to do something at the surf layer, e.g., vcpu action */
+ s4u::VirtualMachine::on_shutdown(*get_iface());
+ get_iface()->on_this_shutdown(*get_iface());
}
/** @brief Change the physical host on which the given VM is running
/* update net_elm with that of the destination physical host */
piface_->set_netpoint(destination->get_netpoint());
+ physical_host_->get_impl()->move_vm(this, destination->get_impl());
/* Adapt the speed, pstate and other physical characteristics to the one of our new physical CPU */
piface_->get_cpu()->reset_vcpu(destination->get_cpu());
XBT_CRITICAL("FIXME: need copy the state(?), %f", action_->get_remains_no_update());
/* keep the bound value of the cpu action of the VM. */
- double old_bound = action_->get_bound();
- if (old_bound > 0) {
+ if (double old_bound = action_->get_bound(); old_bound > 0) {
XBT_DEBUG("migrate VM(%s): set bound (%f) at %s", vm_name.c_str(), old_bound, pm_name_dst.c_str());
new_cpu_action->set_bound(old_bound);
}
action_->set_bound(std::min(impact * physical_host_->get_speed(), user_bound_));
}
-} // namespace resource
-} // namespace kernel
+void VirtualMachineImpl::start_migration()
+{
+ is_migrating_ = true;
+ s4u::VirtualMachine::on_migration_start(*get_iface());
+ get_iface()->on_this_migration_start(*get_iface());
+}
+
+void VirtualMachineImpl::end_migration()
+{
+ is_migrating_ = false;
+ s4u::VirtualMachine::on_migration_end(*get_iface());
+ get_iface()->on_this_migration_end(*get_iface());
+}
+
+void VirtualMachineImpl::seal()
+{
+ HostImpl::seal();
+ s4u::VirtualMachine::on_vm_creation(*get_iface());
+}
+
+} // namespace kernel::resource
} // namespace simgrid