Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Update copyright lines for 2023.
[simgrid.git] / src / kernel / resource / VirtualMachineImpl.cpp
index 16607a0..8a3365a 100644 (file)
@@ -1,9 +1,10 @@
-/* Copyright (c) 2013-2022. 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>
 
@@ -14,6 +15,8 @@
 #include "src/surf/cpu_cas01.hpp"
 #include "src/surf/cpu_ti.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)
@@ -24,8 +27,7 @@ void surf_vm_model_init_HL13(simgrid::kernel::resource::CpuModel* cpu_pm_model)
   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");
@@ -37,8 +39,7 @@ void surf_vm_model_init_HL13(simgrid::kernel::resource::CpuModel* cpu_pm_model)
 namespace simgrid {
 template class xbt::Extendable<kernel::resource::VirtualMachineImpl>;
 
-namespace kernel {
-namespace resource {
+namespace kernel::resource {
 
 /*********
  * Model *
@@ -70,14 +71,15 @@ static void add_active_exec(s4u::Exec const& task)
   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::Activity const& task)
 {
-  const auto* exec = dynamic_cast<s4u::Exec*>(&task);
+  const auto* exec = dynamic_cast<s4u::Exec const*>(&task);
   if (exec == nullptr)
     return;
   if (not exec->is_assigned())
@@ -85,18 +87,19 @@ static void remove_active_exec(s4u::Activity& task)
   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) {
@@ -106,7 +109,7 @@ static void add_active_activity(kernel::activity::ActivityImpl const& act)
   }
 }
 
-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) {
@@ -121,8 +124,8 @@ VMModel::VMModel(const std::string& name) : HostModel(name)
   s4u::Host::on_state_change_cb(host_state_change);
   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::Activity::on_resumed_cb(add_active_activity);
+  s4u::Activity::on_suspended_cb(remove_active_activity);
 }
 
 double VMModel::next_occurring_event(double now)
@@ -169,44 +172,102 @@ double VMModel::next_occurring_event(double now)
   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()
 {
   /* 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());
+  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());
+}
+
+void VirtualMachineImpl::suspend(const actor::ActorImpl* issuer)
+{
+  s4u::VirtualMachine::on_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()));
@@ -244,6 +305,7 @@ void VirtualMachineImpl::resume()
   });
 
   vm_state_ = s4u::VirtualMachine::State::RUNNING;
+  s4u::VirtualMachine::on_resume(*get_iface());
 }
 
 /** @brief Power off a VM.
@@ -253,7 +315,7 @@ void VirtualMachineImpl::resume()
  *
  * @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(),
@@ -269,6 +331,7 @@ void VirtualMachineImpl::shutdown(smx_actor_t issuer)
 
   set_state(s4u::VirtualMachine::State::DESTROYED);
 
+  s4u::VirtualMachine::on_shutdown(*get_iface());
   /* FIXME: we may have to do something at the surf layer, e.g., vcpu action */
 }
 
@@ -284,6 +347,7 @@ void VirtualMachineImpl::set_physical_host(s4u::Host* destination)
 
   /* 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());
@@ -298,8 +362,7 @@ void VirtualMachineImpl::set_physical_host(s4u::Host* destination)
     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);
   }
@@ -334,6 +397,23 @@ void VirtualMachineImpl::update_action_weight()
   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());
+}
+
+void VirtualMachineImpl::end_migration()
+{
+  is_migrating_ = false;
+  s4u::VirtualMachine::on_migration_end(*get_iface());
+}
+
+void VirtualMachineImpl::seal()
+{
+  HostImpl::seal();
+  s4u::VirtualMachine::on_vm_creation(*get_iface());
+}
+
+} // namespace kernel::resource
 } // namespace simgrid