Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Hosts and VMs internal refactor.
authorBruno Donassolo <bruno.donassolo@inria.fr>
Fri, 8 Apr 2022 08:15:36 +0000 (10:15 +0200)
committerBruno Donassolo <bruno.donassolo@inria.fr>
Mon, 11 Apr 2022 08:56:16 +0000 (10:56 +0200)
Main changes:
- Netzones contains their hosts.
- Hosts saves their VMs.
- Remove "global" Engine::hosts_.

Possible mapped impacts:
- Hosts destruction order: it was global in the past, now it depends on
the netzones. However, no test affected

Other changes:
- Move code from VirtualMachine interface to VirtualMachineImpl
- Add a HostImpl::create_vm to create VMs: similar to create_host for
NetZoneImpl

12 files changed:
include/simgrid/kernel/routing/NetZoneImpl.hpp
include/simgrid/s4u/VirtualMachine.hpp
src/kernel/EngineImpl.cpp
src/kernel/EngineImpl.hpp
src/kernel/resource/VirtualMachineImpl.cpp
src/kernel/resource/VirtualMachineImpl.hpp
src/kernel/routing/NetZoneImpl.cpp
src/s4u/s4u_Engine.cpp
src/s4u/s4u_Host.cpp
src/s4u/s4u_VirtualMachine.cpp
src/surf/HostImpl.cpp
src/surf/HostImpl.hpp

index 72a09c6..65e37e0 100644 (file)
@@ -79,14 +79,15 @@ class XBT_PUBLIC NetZoneImpl : public xbt::PropertyHolder {
   std::vector<kernel::routing::NetPoint*> vertices_;
   // would like to use the one defined in the StandardLinkImpl file, but for some reason
   // this hpp is exported to the users and so cannot include the other internal hpp.
-  class LinkDeleter {
+  class ResourceDeleter {
   public:
-    void operator()(resource::StandardLinkImpl* link) const;
+    template <typename Resource> void operator()(Resource* res) const;
   };
-  std::map<std::string, std::unique_ptr<resource::StandardLinkImpl, LinkDeleter>, std::less<>> links_;
+  std::map<std::string, std::unique_ptr<resource::StandardLinkImpl, ResourceDeleter>, std::less<>> links_;
   /* save split-duplex links separately, keep links_ with only LinkImpl* seen by the user
    * members of a split-duplex are saved in the links_ */
   std::map<std::string, std::unique_ptr<resource::SplitDuplexLinkImpl>, std::less<>> split_duplex_links_;
+  std::map<std::string, resource::HostImpl*, std::less<>> hosts_;
 
   NetZoneImpl* parent_ = nullptr;
   std::vector<NetZoneImpl*> children_; // sub-netzones
@@ -184,7 +185,7 @@ public:
 
   /**
    * @brief Searches by the link by its name inside this netzone.
-   * Recursively searches in child netzones
+   * Recursively searches in children netzones
    *
    * @param name Link name
    * @return Link object or nullptr if not found
@@ -200,6 +201,25 @@ public:
    */
   resource::SplitDuplexLinkImpl* get_split_duplex_link_by_name_or_null(const std::string& name) const;
 
+  /**
+   * @brief Searches for a host by its name (recursively)
+   * Including children netzones and VMs on physival hosts
+   *
+   * @param name Host (or VM) name
+   * @return HostImpl pointer
+   */
+  resource::HostImpl* get_host_by_name_or_null(const std::string& name) const;
+
+  /**
+   * @brief Gets list of hosts on this netzone recursively.
+   *
+   * Note: This includes hosts on children netzones and VMs on physical hosts.
+   *
+   * @param filter Filter function to select specific nodes
+   * @return List of hosts
+   */
+  std::vector<s4u::Host*> get_filtered_hosts(const std::function<bool(s4u::Host*)>& filter) const;
+
   /** @brief Make a host within that NetZone */
   s4u::Host* create_host(const std::string& name, const std::vector<double>& speed_per_pstate);
   /** @brief Create a disk with the disk model from this NetZone */
index f902d64..c4e7dd3 100644 (file)
@@ -45,8 +45,12 @@ class XBT_PUBLIC VirtualMachine : public s4u::Host {
   static xbt::signal<void(VirtualMachine const&)> on_migration_end;
   static xbt::signal<void(VirtualMachine const&)> on_destruction;
 
+#ifndef DOXYGEN
+  friend kernel::resource::VirtualMachineImpl; // calls signals from Impl
+#endif
+
 public:
-  explicit VirtualMachine(const std::string& name, Host* physical_host, int core_amount, size_t ramsize = 1024);
+  explicit VirtualMachine(const std::string& name, Host* physical_host, int core_amount, size_t ramsize);
 
 #ifndef DOXYGEN
   // No copy/move
index b147a66..3d4b00e 100644 (file)
@@ -165,12 +165,6 @@ namespace kernel {
 
 EngineImpl::~EngineImpl()
 {
-  /* Since hosts_ is a std::map, the hosts are destroyed in the lexicographic order, which ensures that the output is
-   * reproducible.
-   */
-  while (not hosts_.empty())
-    hosts_.begin()->second->destroy();
-
   /* Also delete the other data */
   delete netzone_root_;
   for (auto const& kv : netpoints_)
index f02256c..8a8f973 100644 (file)
@@ -33,7 +33,6 @@ namespace simgrid {
 namespace kernel {
 
 class EngineImpl {
-  std::map<std::string, s4u::Host*, std::less<>> hosts_;
   std::unordered_map<std::string, routing::NetPoint*> netpoints_;
   std::unordered_map<std::string, activity::MailboxImpl*> mailboxes_;
 
index 2c36cac..521b1d7 100644 (file)
@@ -4,6 +4,7 @@
  * 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>
 
@@ -183,7 +184,7 @@ Action* VMModel::execute_thread(const s4u::Host* host, double flops_amount, int
 
 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)
+    : HostImpl(name), piface_(piface), physical_host_(host_PM), core_amount_(core_amount), ramsize_(ramsize)
 {
   /* Register this VM to the list of all VMs */
   allVms_.push_back(piface);
@@ -196,7 +197,6 @@ VirtualMachineImpl::VirtualMachineImpl(const std::string& name, s4u::VirtualMach
 
   // 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());
 }
 
@@ -211,10 +211,49 @@ void VirtualMachineImpl::vm_destroy()
   /* 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);
+  // calls the HostImpl() destroy, it'll delete the impl object
+  destroy();
+
+  delete piface_;
+}
+
+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());
+
+  size_t pm_ramsize = physical_host_->extension<s4u::VmHostExt>()->ramsize;
+  if (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()));
@@ -252,6 +291,7 @@ void VirtualMachineImpl::resume()
   });
 
   vm_state_ = s4u::VirtualMachine::State::RUNNING;
+  s4u::VirtualMachine::on_resume(*get_iface());
 }
 
 /** @brief Power off a VM.
@@ -277,6 +317,7 @@ void VirtualMachineImpl::shutdown(actor::ActorImpl* 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 */
 }
 
@@ -292,6 +333,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());
@@ -342,6 +384,24 @@ void VirtualMachineImpl::update_action_weight()
   action_->set_bound(std::min(impact * physical_host_->get_speed(), user_bound_));
 }
 
+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_creation(*get_iface());
+}
+
 } // namespace resource
 } // namespace kernel
 } // namespace simgrid
index 30355aa..c5a4bc0 100644 (file)
@@ -32,6 +32,7 @@ public:
   explicit VirtualMachineImpl(const std::string& name, s4u::VirtualMachine* piface, s4u::Host* host, int core_amount,
                               size_t ramsize);
 
+  void start();
   void suspend(const actor::ActorImpl* issuer);
   void resume();
   void shutdown(kernel::actor::ActorImpl* issuer);
@@ -42,8 +43,8 @@ public:
   /** @brief Get the physical host on which the given VM is running */
   s4u::Host* get_physical_host() const { return physical_host_; }
 
-  sg_size_t get_ramsize() const { return ramsize_; }
-  void set_ramsize(sg_size_t ramsize) { ramsize_ = ramsize; }
+  size_t get_ramsize() const { return ramsize_; }
+  void set_ramsize(size_t ramsize) { ramsize_ = ramsize; }
 
   s4u::VirtualMachine::State get_state() const { return vm_state_; }
   void set_state(s4u::VirtualMachine::State state) { vm_state_ = state; }
@@ -61,9 +62,10 @@ public:
   void add_active_exec() { active_execs_++; }
   void remove_active_exec() { active_execs_--; }
 
-  void start_migration() { is_migrating_ = true; }
-  void end_migration() { is_migrating_ = false; }
+  void start_migration();
+  void end_migration();
   bool is_migrating() const { return is_migrating_; }
+  void seal() override;
 
 private:
   s4u::VirtualMachine* piface_;
index a63f8a4..c9bdedd 100644 (file)
@@ -7,6 +7,7 @@
 #include <simgrid/kernel/routing/NetZoneImpl.hpp>
 #include <simgrid/s4u/Engine.hpp>
 #include <simgrid/s4u/Host.hpp>
+#include <simgrid/s4u/VirtualMachine.hpp>
 
 #include "src/include/simgrid/sg_config.hpp"
 #include "src/kernel/EngineImpl.hpp"
@@ -15,6 +16,7 @@
 #include "src/kernel/resource/NetworkModel.hpp"
 #include "src/kernel/resource/SplitDuplexLinkImpl.hpp"
 #include "src/kernel/resource/StandardLinkImpl.hpp"
+#include "src/kernel/resource/VirtualMachineImpl.hpp"
 #include "src/surf/HostImpl.hpp"
 
 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(ker_routing, kernel, "Kernel routing-related information");
@@ -71,9 +73,9 @@ xbt::signal<void(bool symmetrical, kernel::routing::NetPoint* src, kernel::routi
                  std::vector<kernel::resource::StandardLinkImpl*> const& link_list)>
     NetZoneImpl::on_route_creation;
 
-void NetZoneImpl::LinkDeleter::operator()(resource::StandardLinkImpl* link) const
+template <typename Resource> void NetZoneImpl::ResourceDeleter::operator()(Resource* res) const
 {
-  link->destroy();
+  res->destroy();
 }
 
 NetZoneImpl::NetZoneImpl(const std::string& name) : piface_(this), name_(name)
@@ -112,6 +114,14 @@ NetZoneImpl::~NetZoneImpl()
   for (auto const& nz : children_)
     delete nz;
 
+  /* Since hosts_ is a std::map, the hosts are destroyed in the lexicographic order, which ensures that the output is
+   * reproducible.
+   */
+  for (auto& host : hosts_) {
+    host.second->destroy();
+  }
+  hosts_.clear();
+
   for (auto const& kv : bypass_routes_)
     delete kv.second;
 
@@ -178,12 +188,13 @@ s4u::Host* NetZoneImpl::create_host(const std::string& name, const std::vector<d
              "Impossible to create host: %s. Invalid CPU model: nullptr. Have you set the parent of this NetZone: %s?",
              name.c_str(), get_cname());
   xbt_assert(not sealed_, "Impossible to create host: %s. NetZone %s already sealed", name.c_str(), get_cname());
-  auto* res = (new resource::HostImpl(name))->set_englobing_zone(this)->get_iface();
-  res->set_netpoint((new NetPoint(name, NetPoint::Type::Host))->set_englobing_zone(this));
+  auto* host   = (new resource::HostImpl(name))->set_englobing_zone(this);
+  hosts_[name] = host;
+  host->get_iface()->set_netpoint((new NetPoint(name, NetPoint::Type::Host))->set_englobing_zone(this));
 
-  cpu_model_pm_->create_cpu(res, speed_per_pstate);
+  cpu_model_pm_->create_cpu(host->get_iface(), speed_per_pstate);
 
-  return res;
+  return host->get_iface();
 }
 
 resource::StandardLinkImpl* NetZoneImpl::do_create_link(const std::string& name, const std::vector<double>& bandwidths)
@@ -310,6 +321,50 @@ resource::SplitDuplexLinkImpl* NetZoneImpl::get_split_duplex_link_by_name_or_nul
   return nullptr;
 }
 
+resource::HostImpl* NetZoneImpl::get_host_by_name_or_null(const std::string& name) const
+{
+  for (auto const& kv : hosts_) {
+    auto* host = kv.second;
+    if (host->get_name() == name)
+      return host;
+    /* keep old behavior where host and VMs were saved together on EngineImpl::hosts_
+     * get hosts returns VMs too */
+    auto* vm = host->get_vm_by_name_or_null(name);
+    if (vm)
+      return vm;
+  }
+
+  for (const auto* child : children_) {
+    auto* host = child->get_host_by_name_or_null(name);
+    if (host)
+      return host;
+  }
+
+  return nullptr;
+}
+
+std::vector<s4u::Host*> NetZoneImpl::get_filtered_hosts(const std::function<bool(s4u::Host*)>& filter) const
+{
+  std::vector<s4u::Host*> filtered_list;
+  for (auto const& kv : hosts_) {
+    s4u::Host* h = kv.second->get_iface();
+    if (filter(h))
+      filtered_list.push_back(h);
+    /* Engine::get_hosts returns the VMs too */
+    for (auto* vm : h->get_impl()->get_vms()) {
+      if (filter(vm))
+        filtered_list.push_back(vm);
+    }
+  }
+
+  for (const auto* child : children_) {
+    auto child_links = child->get_filtered_hosts(filter);
+    filtered_list.insert(filtered_list.end(), std::make_move_iterator(child_links.begin()),
+                         std::make_move_iterator(child_links.end()));
+  }
+  return filtered_list;
+}
+
 void NetZoneImpl::add_route(NetPoint* /*src*/, NetPoint* /*dst*/, NetPoint* /*gw_src*/, NetPoint* /*gw_dst*/,
                             const std::vector<s4u::LinkInRoute>& /*link_list_*/, bool /*symmetrical*/)
 {
index c5a656a..858ee1f 100644 (file)
@@ -19,6 +19,7 @@
 #include "src/kernel/resource/SplitDuplexLinkImpl.hpp"
 #include "src/kernel/resource/StandardLinkImpl.hpp"
 #include "src/mc/mc_replay.hpp"
+#include "src/surf/HostImpl.hpp"
 #include "xbt/config.hpp"
 
 #include <algorithm>
@@ -182,55 +183,49 @@ void Engine::load_deployment(const std::string& deploy) const
 /** Returns the amount of hosts in the platform */
 size_t Engine::get_host_count() const
 {
-  return pimpl->hosts_.size();
+  return get_all_hosts().size();
 }
 
 std::vector<Host*> Engine::get_all_hosts() const
 {
-  std::vector<Host*> res;
-  for (auto const& kv : pimpl->hosts_)
-    res.push_back(kv.second);
-  return res;
+  return get_filtered_hosts([](const Host*) { return true; });
 }
 
 std::vector<Host*> Engine::get_filtered_hosts(const std::function<bool(Host*)>& filter) const
 {
   std::vector<Host*> hosts;
-  for (auto const& kv : pimpl->hosts_) {
-    if (filter(kv.second))
-      hosts.push_back(kv.second);
+  if (pimpl->netzone_root_) {
+    hosts = pimpl->netzone_root_->get_filtered_hosts(filter);
   }
+  /* Sort hosts in lexicographical order: keep same behavior when the hosts were saved on Engine
+   * Some tests do a get_all_hosts() and selects hosts in this order */
+  std::sort(hosts.begin(), hosts.end(), [](const auto* h1, const auto* h2) { return h1->get_name() < h2->get_name(); });
 
   return hosts;
 }
 
-void Engine::host_register(const std::string& name, Host* host)
-{
-  pimpl->hosts_[name] = host;
-}
-
-void Engine::host_unregister(const std::string& name)
-{
-  pimpl->hosts_.erase(name);
-}
-
 /** @brief Find a host from its name.
  *
  *  @throw std::invalid_argument if the searched host does not exist.
  */
 Host* Engine::host_by_name(const std::string& name) const
 {
-  auto host = pimpl->hosts_.find(name);
-  if (host == pimpl->hosts_.end())
+  auto* host = host_by_name_or_null(name);
+  if (not host)
     throw std::invalid_argument(std::string("Host not found: '") + name + std::string("'"));
-  return host->second;
+  return host;
 }
 
 /** @brief Find a host from its name (or nullptr if that host does not exist) */
 Host* Engine::host_by_name_or_null(const std::string& name) const
 {
-  auto host = pimpl->hosts_.find(name);
-  return host == pimpl->hosts_.end() ? nullptr : host->second;
+  Host* host = nullptr;
+  if (pimpl->netzone_root_) {
+    auto* host_impl = pimpl->netzone_root_->get_host_by_name_or_null(name);
+    if (host_impl)
+      host = host_impl->get_iface();
+  }
+  return host;
 }
 
 /** @brief Find a link from its name.
index d84f23e..9c0ab22 100644 (file)
@@ -111,11 +111,6 @@ void Host::turn_off()
   if (is_on()) {
     const kernel::actor::ActorImpl* self = kernel::actor::ActorImpl::self();
     kernel::actor::simcall_answered([this, self] {
-      for (VirtualMachine* const& vm : kernel::resource::VirtualMachineImpl::allVms_)
-        if (vm->get_pm() == this) {
-          vm->shutdown();
-          vm->turn_off();
-        }
       this->pimpl_cpu_->turn_off();
       this->pimpl_->turn_off(self);
 
@@ -368,12 +363,14 @@ void Host::remove_disk(const std::string& disk_name)
 
 VirtualMachine* Host::create_vm(const std::string& name, int core_amount)
 {
-  return new VirtualMachine(name, this, core_amount);
+  return kernel::actor::simcall_answered(
+      [this, &name, core_amount] { return this->pimpl_->create_vm(name, core_amount); });
 }
 
 VirtualMachine* Host::create_vm(const std::string& name, int core_amount, size_t ramsize)
 {
-  return new VirtualMachine(name, this, core_amount, ramsize);
+  return kernel::actor::simcall_answered(
+      [this, &name, core_amount, ramsize] { return this->pimpl_->create_vm(name, core_amount, ramsize); });
 }
 
 ExecPtr Host::exec_init(double flops) const
index b53de10..b0bb757 100644 (file)
@@ -36,66 +36,15 @@ VirtualMachine::VirtualMachine(const std::string& name, s4u::Host* physical_host
     : Host(new kernel::resource::VirtualMachineImpl(name, this, physical_host, core_amount, ramsize))
     , pimpl_vm_(dynamic_cast<kernel::resource::VirtualMachineImpl*>(Host::get_impl()))
 {
-  XBT_DEBUG("Create VM %s", get_cname());
-
-  /* Currently, a VM uses the network resource of its physical host */
-  set_netpoint(physical_host->get_netpoint());
-
-  // Create a VCPU for this VM
-  std::vector<double> speeds;
-  for (unsigned long i = 0; i < physical_host->get_pstate_count(); i++)
-    speeds.push_back(physical_host->get_pstate_speed(i));
-
-  physical_host->get_netpoint()
-      ->get_englobing_zone()
-      ->get_cpu_vm_model()
-      ->create_cpu(this, speeds)
-      ->set_core_count(core_amount)
-      ->seal();
-
-  if (physical_host->get_pstate() != 0)
-    set_pstate(physical_host->get_pstate());
-
-  seal(); // seal this host
-  s4u::VirtualMachine::on_creation(*this);
 }
 
 void VirtualMachine::start()
 {
-  on_start(*this);
-
-  VmHostExt::ensureVmExtInstalled();
-
-  kernel::actor::simcall_answered([this]() {
-    Host* pm = this->pimpl_vm_->get_physical_host();
-    if (pm->extension<VmHostExt>() == nullptr)
-      pm->extension_set(new VmHostExt());
-
-    size_t pm_ramsize = pm->extension<VmHostExt>()->ramsize;
-    if (pm_ramsize && not pm->extension<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 (VirtualMachine* const& ws_vm : kernel::resource::VirtualMachineImpl::allVms_)
-        if (pm == 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(), pm->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",
-                                                    pm->get_cname(), get_cname()));
-      }
-    }
-    this->pimpl_vm_->set_state(State::RUNNING);
-  });
-
-  on_started(*this);
+  kernel::actor::simcall_answered([this]() { pimpl_vm_->start(); });
 }
 
 void VirtualMachine::suspend()
 {
-  on_suspend(*this);
   const kernel::actor::ActorImpl* issuer = kernel::actor::ActorImpl::self();
   kernel::actor::simcall_answered([this, issuer]() { pimpl_vm_->suspend(issuer); });
 }
@@ -103,14 +52,12 @@ void VirtualMachine::suspend()
 void VirtualMachine::resume()
 {
   pimpl_vm_->resume();
-  on_resume(*this);
 }
 
 void VirtualMachine::shutdown()
 {
   kernel::actor::ActorImpl* issuer = kernel::actor::ActorImpl::self();
   kernel::actor::simcall_answered([this, issuer]() { pimpl_vm_->shutdown(issuer); });
-  on_shutdown(*this);
 }
 
 void VirtualMachine::destroy()
@@ -122,14 +69,8 @@ void VirtualMachine::destroy()
     XBT_DEBUG("destroy %s", get_cname());
     on_destruction(*this);
     /* Then, destroy the VM object */
-    kernel::actor::simcall_answered([this]() {
-      get_vm_impl()->vm_destroy();
-      get_impl()->destroy();
-
-      /* Don't free these things twice: they are the ones of my physical host */
-      set_netpoint(nullptr);
-      delete this;
-    });
+    kernel::actor::simcall_answered(
+        [this]() { get_vm_impl()->get_physical_host()->get_impl()->destroy_vm(get_name()); });
   };
 
   if (not this_actor::is_maestro() && this_actor::get_host() == this) {
@@ -204,13 +145,11 @@ VirtualMachine* VirtualMachine::set_bound(double bound)
 void VirtualMachine::start_migration() const
 {
   pimpl_vm_->start_migration();
-  on_migration_start(*this);
 }
 
 void VirtualMachine::end_migration() const
 {
   pimpl_vm_->end_migration();
-  on_migration_end(*this);
 }
 
 } // namespace s4u
index 0b28ab2..3e763b5 100644 (file)
@@ -28,16 +28,9 @@ namespace resource {
 /************
  * Resource *
  ************/
-HostImpl::HostImpl(const std::string& name, s4u::Host* piface) : piface_(this), name_(name)
-{
-  xbt_assert(s4u::Host::by_name_or_null(name_) == nullptr, "Refusing to create a second host named '%s'.", get_cname());
-  s4u::Engine::get_instance()->host_register(name_, piface);
-}
-
 HostImpl::HostImpl(const std::string& name) : piface_(this), name_(name)
 {
   xbt_assert(s4u::Host::by_name_or_null(name_) == nullptr, "Refusing to create a second host named '%s'.", get_cname());
-  s4u::Engine::get_instance()->host_register(name_, &piface_);
 }
 
 HostImpl::~HostImpl()
@@ -57,6 +50,9 @@ HostImpl::~HostImpl()
 
   for (auto const& d : disks_)
     d.second->destroy();
+
+  for (auto const& vm : vms_)
+    vm.second->vm_destroy();
 }
 
 /** @brief Fire the required callbacks and destroy the object
@@ -66,7 +62,6 @@ HostImpl::~HostImpl()
 void HostImpl::destroy()
 {
   s4u::Host::on_destruction(*this->get_iface());
-  s4u::Engine::get_instance()->host_unregister(std::string(name_));
   delete this;
 }
 
@@ -85,6 +80,12 @@ void HostImpl::turn_on() const
 /** Kill all actors hosted here */
 void HostImpl::turn_off(const actor::ActorImpl* issuer)
 {
+  /* turn_off VMs running on host */
+  for (const auto& kv : vms_) {
+    auto* actor = kernel::actor::ActorImpl::self();
+    kv.second->shutdown(actor);
+    kv.second->turn_off(actor);
+  }
   for (auto& actor : actor_list_) {
     XBT_DEBUG("Killing Actor %s@%s on behalf of %s which turned off that host.", actor.get_cname(),
               actor.get_host()->get_cname(), issuer->get_cname());
@@ -137,6 +138,63 @@ std::vector<s4u::Disk*> HostImpl::get_disks() const
   return disks;
 }
 
+s4u::VirtualMachine* HostImpl::create_vm(const std::string& name, int core_amount, size_t ramsize)
+{
+  auto* vm   = new s4u::VirtualMachine(name, get_iface(), core_amount, ramsize);
+  vms_[name] = vm->get_vm_impl();
+
+  // Create a VCPU for this VM
+  std::vector<double> speeds;
+  for (unsigned long i = 0; i < get_iface()->get_pstate_count(); i++)
+    speeds.push_back(get_iface()->get_pstate_speed(i));
+
+  auto* cpu = englobing_zone_->get_cpu_vm_model()->create_cpu(vm, speeds)->set_core_count(core_amount);
+
+  if (get_iface()->get_pstate() != 0)
+    cpu->set_pstate(get_iface()->get_pstate());
+
+  cpu->seal();
+
+  /* Currently, a VM uses the network resource of its physical host */
+  vm->set_netpoint(get_iface()->get_netpoint());
+
+  vm->seal();
+
+  return vm;
+}
+
+void HostImpl::move_vm(VirtualMachineImpl* vm, HostImpl* destination)
+{
+  xbt_assert(vm && destination);
+
+  vms_.erase(vm->get_name());
+  destination->vms_[vm->get_name()] = vm;
+}
+
+void HostImpl::destroy_vm(const std::string& name)
+{
+  auto* vm = vms_[name];
+  vms_.erase(name);
+  vm->vm_destroy();
+}
+
+VirtualMachineImpl* HostImpl::get_vm_by_name_or_null(const std::string& name) const
+{
+  auto vm_it = vms_.find(name);
+  if (vm_it != vms_.end())
+    return vm_it->second;
+  return nullptr;
+}
+
+std::vector<s4u::VirtualMachine*> HostImpl::get_vms() const
+{
+  std::vector<s4u::VirtualMachine*> vms;
+  for (const auto& kv : vms_) {
+    vms.push_back(kv.second->get_iface());
+  }
+  return vms;
+}
+
 s4u::Disk* HostImpl::create_disk(const std::string& name, double read_bandwidth, double write_bandwidth)
 {
   auto disk = piface_.get_netpoint()->get_englobing_zone()->get_disk_model()->create_disk(name, read_bandwidth,
@@ -166,6 +224,10 @@ void HostImpl::seal()
   /* seal its disks */
   for (auto const& disk : disks_)
     disk.second->seal();
+
+  /* seal its VMs */
+  for (auto const& vm : vms_)
+    vm.second->seal();
 }
 } // namespace resource
 } // namespace kernel
index c5de6ec..944844b 100644 (file)
@@ -50,13 +50,13 @@ class XBT_PRIVATE HostImpl : public xbt::PropertyHolder {
   std::vector<actor::ProcessArg*> actors_at_boot_;
   s4u::Host piface_;
   std::map<std::string, DiskImpl*, std::less<>> disks_;
+  std::map<std::string, VirtualMachineImpl*, std::less<>> vms_;
   xbt::string name_{"noname"};
   routing::NetZoneImpl* englobing_zone_ = nullptr;
   bool sealed_ = false;
 
 protected:
   virtual ~HostImpl(); // Use destroy() instead of this destructor.
-  HostImpl(const std::string& name, s4u::Host* piface);
 
 public:
   friend VirtualMachineImpl;
@@ -66,8 +66,14 @@ public:
 
   std::vector<s4u::Disk*> get_disks() const;
   s4u::Disk* create_disk(const std::string& name, double read_bandwidth, double write_bandwidth);
+  s4u::VirtualMachine* create_vm(const std::string& name, int core_amount, size_t ramsize = 1024);
+  void destroy_vm(const std::string& name);
   void add_disk(const s4u::Disk* disk);
   void remove_disk(const std::string& name);
+  /** @brief Moves VM from this host to destination. Only sets the vm_ accordingly */
+  void move_vm(VirtualMachineImpl* vm, HostImpl* destination);
+  std::vector<s4u::VirtualMachine*> get_vms() const;
+  VirtualMachineImpl* get_vm_by_name_or_null(const std::string& name) const;
 
   virtual const s4u::Host* get_iface() const { return &piface_; }
   virtual s4u::Host* get_iface() { return &piface_; }
@@ -89,7 +95,7 @@ public:
   void remove_actor(actor::ActorImpl* actor) { xbt::intrusive_erase(actor_list_, *actor); }
   void add_actor_at_boot(actor::ProcessArg* arg) { actors_at_boot_.emplace_back(arg); }
 
-  void seal();
+  virtual void seal();
 
   template <class F> void foreach_actor(F function)
   {