Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
vm_migrate is now part of the live_migration plugin \o/
authorFrederic Suter <frederic.suter@cc.in2p3.fr>
Tue, 26 Dec 2017 09:23:47 +0000 (10:23 +0100)
committerFrederic Suter <frederic.suter@cc.in2p3.fr>
Tue, 26 Dec 2017 09:23:47 +0000 (10:23 +0100)
there are still some cleanups to do to complete the plugin
 - is_migrating in VirtualMachineImpl and related functions
 - the vm_params_t are only used by the migration
 - some factoring in VmLiveMigration.hpp
 - See if the final ack can be spared
 - check valgrind and sonar feedback

13 files changed:
examples/msg/cloud-masterworker/cloud-masterworker.tesh
examples/msg/cloud-migration/cloud-migration.tesh
examples/s4u/cloud-simple/s4u-cloud-simple.cpp
examples/s4u/cloud-simple/s4u-cloud-simple.tesh
include/simgrid/msg.h
include/simgrid/plugins/live_migration.h
src/bindings/java/jmsg_vm.cpp
src/msg/msg_vm.cpp
src/plugins/vm/VmLiveMigration.cpp [new file with mode: 0644]
src/plugins/vm/VmLiveMigration.hpp [new file with mode: 0644]
src/plugins/vm/s4u_VirtualMachine.cpp
teshsuite/msg/cloud-simple/cloud-simple.tesh
tools/cmake/DefinePackages.cmake

index 12e3506..a83825c 100644 (file)
@@ -41,12 +41,12 @@ $ $SG_TEST_EXENV ${bindir:=.}/cloud-masterworker$EXEEXT --log=no_loc ${platfdir}
 > [VM00:WRK02:(4) 10.280841] [msg_test/INFO] WRK02 executed task(Task02)
 > [VM01:WRK03:(5) 10.361121] [msg_test/INFO] WRK03 received task(Task03) from mailbox(MBOX:WRK03)
 > [node-0.acme.org:master:(1) 10.361121] [msg_test/INFO] # Migrate all VMs to PM(node-1.acme.org)
-> [node-1.acme.org:__pr_mig_tx:VM00(node-1.acme.org-node-1.acme.org):(7) 10.361121] [msg_vm/WARNING] use the default max_downtime value 30ms
+> [node-1.acme.org:__pr_mig_tx:VM00(node-1.acme.org-node-1.acme.org):(7) 10.361121] [vm_live_migration/WARNING] use the default max_downtime value 30ms
 > [VM01:WRK03:(5) 10.371121] [msg_test/INFO] WRK03 executed task(Task03)
-> [node-10.acme.org:__pr_mig_tx:VM01(node-10.acme.org-node-1.acme.org):(9) 19.682922] [msg_vm/WARNING] use the default max_downtime value 30ms
+> [node-10.acme.org:__pr_mig_tx:VM01(node-10.acme.org-node-1.acme.org):(9) 19.682922] [vm_live_migration/WARNING] use the default max_downtime value 30ms
 > [node-0.acme.org:master:(1) 28.561942] [msg_test/INFO] # Migrate all VMs to PM(node-10.acme.org)
-> [node-1.acme.org:__pr_mig_tx:VM00(node-1.acme.org-node-10.acme.org):(11) 28.561942] [msg_vm/WARNING] use the default max_downtime value 30ms
-> [node-1.acme.org:__pr_mig_tx:VM01(node-1.acme.org-node-10.acme.org):(13) 37.440963] [msg_vm/WARNING] use the default max_downtime value 30ms
+> [node-1.acme.org:__pr_mig_tx:VM00(node-1.acme.org-node-10.acme.org):(11) 28.561942] [vm_live_migration/WARNING] use the default max_downtime value 30ms
+> [node-1.acme.org:__pr_mig_tx:VM01(node-1.acme.org-node-10.acme.org):(13) 37.440963] [vm_live_migration/WARNING] use the default max_downtime value 30ms
 > [node-0.acme.org:master:(1) 46.319984] [msg_test/INFO] # Shutdown the half of worker processes gracefully. The remaining half will be forcibly killed.
 > [VM00:WRK00:(2) 46.327790] [msg_test/INFO] WRK00 received task(finalize) from mailbox(MBOX:WRK00)
 > [VM01:WRK01:(3) 46.335596] [msg_test/INFO] WRK01 received task(finalize) from mailbox(MBOX:WRK01)
index 8eecba2..f766852 100644 (file)
@@ -6,13 +6,13 @@ $ $SG_TEST_EXENV ${bindir:=.}/cloud-migration ${platfdir}/small_platform.xml --l
 > [132.765801] (5:__pr_mig_tx:VM0(Fafard-Tremblay)@Fafard) use the default max_downtime value 30ms
 > [146.111793] (1:master_@Fafard) VM0 migrated: Fafard->Tremblay in 13.346 s
 > [146.111793] (1:master_@Fafard) Test: Migrate two VMs at once from PM0 to PM1
-> [146.111793] (9:__pr_mig_tx:VM0(Fafard-Tremblay)@Fafard) use the default max_downtime value 30ms
+> [146.111793] (8:__pr_mig_tx:VM0(Fafard-Tremblay)@Fafard) use the default max_downtime value 30ms
 > [146.111793] (11:__pr_mig_tx:VM1(Fafard-Tremblay)@Fafard) use the default max_downtime value 30ms
-> [411.566271] (8:mig_wrk@Fafard) VM1 migrated: Fafard->Tremblay in 265.454 s
+> [411.566271] (9:mig_wrk@Fafard) VM1 migrated: Fafard->Tremblay in 265.454 s
 > [411.566271] (6:mig_wrk@Fafard) VM0 migrated: Fafard->Tremblay in 265.454 s
 > [10146.111793] (1:master_@Fafard) Test: Migrate two VMs at once to different PMs
-> [10146.111793] (15:__pr_mig_tx:VM0(Fafard-Tremblay)@Fafard) use the default max_downtime value 30ms
+> [10146.111793] (14:__pr_mig_tx:VM0(Fafard-Tremblay)@Fafard) use the default max_downtime value 30ms
 > [10146.111793] (17:__pr_mig_tx:VM1(Fafard-Bourassa)@Fafard) use the default max_downtime value 30ms
-> [10362.620589] (14:mig_wrk@Fafard) VM1 migrated: Fafard->Bourassa in 216.509 s
+> [10362.620589] (15:mig_wrk@Fafard) VM1 migrated: Fafard->Bourassa in 216.509 s
 > [10411.547334] (12:mig_wrk@Fafard) VM0 migrated: Fafard->Tremblay in 265.436 s
 > [20146.111793] (0:maestro@) Bye (simulation time 20146.1)
index 5dfa312..61f0bd7 100644 (file)
@@ -4,7 +4,9 @@
  * under the terms of the license (GNU LGPL) which comes with this package. */
 
 #include "simgrid/s4u.hpp"
+#include "simgrid/plugins/live_migration.h"
 #include "simgrid/s4u/VirtualMachine.hpp"
+
 XBT_LOG_NEW_DEFAULT_CATEGORY(s4u_test, "Messages specific for this s4u example");
 
 static void computation_fun()
@@ -69,6 +71,7 @@ static void master_main()
 {
   s4u_Host* pm0 = simgrid::s4u::Host::by_name("Fafard");
   s4u_Host* pm1 = simgrid::s4u::Host::by_name("Tremblay");
+  s4u_Host* pm2 = simgrid::s4u::Host::by_name("Bourassa");
 
   XBT_INFO("## Test 1 (started): check computation on normal PMs");
 
@@ -186,11 +189,30 @@ static void master_main()
   vm1->destroy();
 
   XBT_INFO("## Test 5 (ended)");
+  XBT_INFO("## Test 6 (started): Check migration impact (not yet implemented neither on the CPU resource nor on the"
+           " network one");
+  XBT_INFO("### Relocate VM0 between PM0 and PM1");
+  vm0 = new simgrid::s4u::VirtualMachine("VM0", pm0, 1);
+  s_vm_params_t params;
+  memset(&params, 0, sizeof(params));
+  vm0->setParameters(&params);
+  vm0->setRamsize(1L * 1024 * 1024 * 1024); // 1GiB
+
+  vm0->start();
+  launch_communication_worker(vm0, pm2);
+  simgrid::s4u::this_actor::sleep_for(0.01);
+  sg_vm_migrate(vm0, pm1);
+  simgrid::s4u::this_actor::sleep_for(0.01);
+  sg_vm_migrate(vm0, pm0);
+  simgrid::s4u::this_actor::sleep_for(5);
+  vm0->destroy();
+  XBT_INFO("## Test 6 (ended)");
 }
 
 int main(int argc, char* argv[])
 {
   simgrid::s4u::Engine e(&argc, argv);
+  sg_vm_live_migration_plugin_init();
   e.loadPlatform(argv[1]); /* - Load the platform description */
 
   simgrid::s4u::Actor::createActor("master_", simgrid::s4u::Host::by_name("Fafard"), master_main);
index 595d3f8..8717fff 100644 (file)
@@ -49,4 +49,10 @@ $ $SG_TEST_EXENV ${bindir:=.}/s4u-cloud-simple$EXEEXT --log=no_loc ${platfdir:=.
 > [VM1:comm_rx:(34) 44.291085] [s4u_test/INFO] VM0:comm_tx to VM1:comm_rx => 0.291085 sec
 > [VM1:comm_rx:(32) 44.291085] [s4u_test/INFO] VM0:comm_tx to VM1:comm_rx => 0.291085 sec
 > [Fafard:master_:(1) 49.000000] [s4u_test/INFO] ## Test 5 (ended)
-> [49.000000] [s4u_test/INFO] Simulation time 49
+> [Fafard:master_:(1) 49.000000] [s4u_test/INFO] ## Test 6 (started): Check migration impact (not yet implemented neither on the CPU resource nor on the network one
+> [Fafard:master_:(1) 49.000000] [s4u_test/INFO] ### Relocate VM0 between PM0 and PM1
+> [Fafard:__pr_mig_tx:VM0(Fafard-Tremblay):(38) 49.010000] [vm_live_migration/WARNING] use the default max_downtime value 30ms
+> [Bourassa:comm_rx:(36) 49.204993] [s4u_test/INFO] VM0:comm_tx to Bourassa:comm_rx => 0.204993 sec
+> [Tremblay:__pr_mig_tx:VM0(Tremblay-Fafard):(40) 191.674258] [vm_live_migration/WARNING] use the default max_downtime value 30ms
+> [Fafard:master_:(1) 339.199251] [s4u_test/INFO] ## Test 6 (ended)
+> [339.199251] [s4u_test/INFO] Simulation time 339.199
index a5389f8..dde5077 100644 (file)
@@ -481,8 +481,6 @@ XBT_PUBLIC(void) MSG_vm_start(msg_vm_t vm);
 /* Shutdown the guest operating system. */
 XBT_PUBLIC(void) MSG_vm_shutdown(msg_vm_t vm);
 
-XBT_PUBLIC(void) MSG_vm_migrate(msg_vm_t vm, msg_host_t destination);
-
 /* Suspend the execution of the VM, but keep its state on memory. */
 XBT_PUBLIC(void) MSG_vm_suspend(msg_vm_t vm);
 XBT_PUBLIC(void) MSG_vm_resume(msg_vm_t vm);
index e61bdb7..8fa1b7b 100644 (file)
@@ -16,8 +16,10 @@ XBT_PUBLIC(void) sg_vm_live_migration_plugin_init();
 XBT_PUBLIC(void) sg_vm_start_dirty_page_tracking(sg_vm_t vm);
 XBT_PUBLIC(void) sg_vm_stop_dirty_page_tracking(sg_vm_t vm);
 XBT_PUBLIC(double) sg_vm_lookup_computed_flops(sg_vm_t vm);
+XBT_PUBLIC(void) sg_vm_migrate(sg_vm_t vm, sg_host_t dst_pm);
 
 #define MSG_vm_live_migration_plugin_init() sg_vm_live_migration_plugin_init()
+#define MSG_vm_migrate(vm, dst_pm) sg_vm_migrate(vm, dst_pm)
 
 SG_END_DECL()
 
index 70dc62c..f108bf2 100644 (file)
@@ -8,6 +8,7 @@
 #include "jmsg_vm.h"
 #include "jmsg_host.h"
 #include "jxbt_utilities.hpp"
+#include "simgrid/plugins/live_migration.h"
 #include "src/plugins/vm/VirtualMachineImpl.hpp"
 #include "xbt/ex.hpp"
 
index 3fc0bf9..c43ab8d 100644 (file)
@@ -250,424 +250,4 @@ void MSG_vm_destroy(msg_vm_t vm)
   }
 }
 
-static std::string get_mig_process_tx_name(msg_vm_t vm, msg_host_t src_pm, msg_host_t dst_pm)
-{
-  return std::string("__pr_mig_tx:") + vm->getCname() + "(" + src_pm->getCname() + "-" + dst_pm->getCname() + ")";
-}
-
-static std::string get_mig_process_rx_name(msg_vm_t vm, msg_host_t src_pm, msg_host_t dst_pm)
-{
-  return std::string("__pr_mig_rx:") + vm->getCname() + "(" + src_pm->getCname() + "-" + dst_pm->getCname() + ")";
-}
-
-static std::string get_mig_task_name(msg_vm_t vm, msg_host_t src_pm, msg_host_t dst_pm, int stage)
-{
-  return std::string("__task_mig_stage") + std::to_string(stage) + ":" + vm->getCname() + "(" + src_pm->getCname() +
-         "-" + dst_pm->getCname() + ")";
-}
-
-struct migration_session {
-  msg_vm_t vm;
-  msg_host_t src_pm;
-  msg_host_t dst_pm;
-
-  /* The miration_rx process uses mbox_ctl to let the caller of do_migration()
-   * know the completion of the migration. */
-  std::string mbox_ctl;
-  /* The migration_rx and migration_tx processes use mbox to transfer migration data. */
-  std::string mbox;
-};
-
-static int migration_rx_fun(int argc, char *argv[])
-{
-  XBT_DEBUG("mig: rx_start");
-
-  // The structure has been created in the do_migration function and should only be freed in the same place ;)
-  migration_session* ms = static_cast<migration_session*>(MSG_process_get_data(MSG_process_self()));
-
-  bool received_finalize = false;
-
-  std::string finalize_task_name = get_mig_task_name(ms->vm, ms->src_pm, ms->dst_pm, 3);
-  while (not received_finalize) {
-    msg_task_t task = nullptr;
-    int ret         = MSG_task_recv(&task, ms->mbox.c_str());
-
-    if (ret != MSG_OK) {
-      // An error occurred, clean the code and return
-      // The owner did not change, hence the task should be only destroyed on the other side
-      return 0;
-    }
-
-    if (finalize_task_name == task->name)
-      received_finalize = 1;
-
-    MSG_task_destroy(task);
-  }
-
-  // Here Stage 1, 2  and 3 have been performed.
-  // Hence complete the migration
-
-  // Copy the reference to the vm (if SRC crashes now, do_migration will free ms)
-  // This is clearly ugly but I (Adrien) need more time to do something cleaner (actually we should copy the whole ms
-  // structure at the beginning and free it at the end of each function)
-  simgrid::s4u::VirtualMachine* vm = ms->vm;
-  msg_host_t dst_pm                = ms->dst_pm;
-
-  // Make sure that we cannot get interrupted between the migrate and the resume to not end in an inconsistent state
-  simgrid::simix::kernelImmediate([vm, dst_pm]() {
-    /* Update the vm location */
-    /* precopy migration makes the VM temporally paused */
-    xbt_assert(vm->getState() == SURF_VM_STATE_SUSPENDED);
-
-    /* Update the vm location and resume it */
-    vm->pimpl_vm_->setPm(dst_pm);
-    vm->resume();
-  });
-
-
-  // Now the VM is running on the new host (the migration is completed) (even if the SRC crash)
-  vm->pimpl_vm_->isMigrating = false;
-  XBT_DEBUG("VM(%s) moved from PM(%s) to PM(%s)", ms->vm->getCname(), ms->src_pm->getCname(), ms->dst_pm->getCname());
-
-  if (TRACE_msg_vm_is_enabled()) {
-    static long long int counter = 0;
-    std::string key              = std::to_string(counter);
-    counter++;
-
-    // start link
-    container_t msg = simgrid::instr::Container::byName(vm->getName());
-    simgrid::instr::Container::getRoot()->getLink("MSG_VM_LINK")->startEvent(msg, "M", key);
-
-    // destroy existing container of this vm
-    container_t existing_container = simgrid::instr::Container::byName(vm->getName());
-    existing_container->removeFromParent();
-    delete existing_container;
-
-    // create new container on the new_host location
-    new simgrid::instr::Container(vm->getCname(), "MSG_VM", simgrid::instr::Container::byName(ms->dst_pm->getName()));
-
-    // end link
-    msg  = simgrid::instr::Container::byName(vm->getName());
-    simgrid::instr::Container::getRoot()->getLink("MSG_VM_LINK")->endEvent(msg, "M", key);
-  }
-
-  // Inform the SRC that the migration has been correctly performed
-  std::string task_name = get_mig_task_name(ms->vm, ms->src_pm, ms->dst_pm, 4);
-  msg_task_t task       = MSG_task_create(task_name.c_str(), 0, 0, nullptr);
-  msg_error_t ret       = MSG_task_send(task, ms->mbox_ctl.c_str());
-  if(ret == MSG_HOST_FAILURE){
-    // The DST has crashed, this is a problem has the VM since we are not sure whether SRC is considering that the VM
-    // has been correctly migrated on the DST node
-    // TODO What does it mean ? What should we do ?
-    MSG_task_destroy(task);
-  } else if(ret == MSG_TRANSFER_FAILURE){
-    // The SRC has crashed, this is not a problem has the VM has been correctly migrated on the DST node
-    MSG_task_destroy(task);
-  }
-
-  XBT_DEBUG("mig: rx_done");
-  return 0;
-}
-
-static sg_size_t send_migration_data(msg_vm_t vm, msg_host_t src_pm, msg_host_t dst_pm, sg_size_t size,
-                                     const std::string& mbox, int stage, int stage2_round, double mig_speed,
-                                     double timeout)
-{
-  sg_size_t sent = 0;
-  std::string task_name = get_mig_task_name(vm, src_pm, dst_pm, stage);
-  msg_task_t task       = MSG_task_create(task_name.c_str(), 0, static_cast<double>(size), nullptr);
-
-  double clock_sta = MSG_get_clock();
-
-  msg_error_t ret;
-  if (mig_speed > 0)
-    ret = MSG_task_send_with_timeout_bounded(task, mbox.c_str(), timeout, mig_speed);
-  else
-    ret = MSG_task_send(task, mbox.c_str());
-
-  if (ret == MSG_OK) {
-    sent = size;
-  } else if (ret == MSG_TIMEOUT) {
-    sg_size_t remaining = static_cast<sg_size_t>(MSG_task_get_remaining_communication(task));
-    sent = size - remaining;
-    XBT_VERB("timeout (%lf s) in sending_migration_data, remaining %llu bytes of %llu", timeout, remaining, size);
-  }
-
-  /* FIXME: why try-and-catch is used here? */
-  if(ret == MSG_HOST_FAILURE){
-    XBT_DEBUG("SRC host failed during migration of %s (stage %d)", vm->getCname(), stage);
-    MSG_task_destroy(task);
-    THROWF(host_error, 0, "SRC host failed during migration of %s (stage %d)", vm->getCname(), stage);
-  }else if(ret == MSG_TRANSFER_FAILURE){
-    XBT_DEBUG("DST host failed during migration of %s (stage %d)", vm->getCname(), stage);
-    MSG_task_destroy(task);
-    THROWF(host_error, 0, "DST host failed during migration of %s (stage %d)", vm->getCname(), stage);
-  }
-
-  double clock_end = MSG_get_clock();
-  double duration = clock_end - clock_sta;
-  double actual_speed = size / duration;
-
-  if (stage == 2)
-    XBT_DEBUG("mig-stage%d.%d: sent %llu duration %f actual_speed %f (target %f)", stage, stage2_round, size, duration,
-              actual_speed, mig_speed);
-  else
-    XBT_DEBUG("mig-stage%d: sent %llu duration %f actual_speed %f (target %f)", stage, size, duration, actual_speed,
-              mig_speed);
-
-  return sent;
-}
-
-static sg_size_t get_updated_size(double computed, double dp_rate, double dp_cap)
-{
-  double updated_size = computed * dp_rate;
-  XBT_DEBUG("updated_size %f dp_rate %f", updated_size, dp_rate);
-  if (updated_size > dp_cap) {
-    updated_size = dp_cap;
-  }
-
-  return static_cast<sg_size_t>(updated_size);
-}
-
-static int migration_tx_fun(int argc, char *argv[])
-{
-  XBT_DEBUG("mig: tx_start");
-
-  // Note that the ms structure has been allocated in do_migration and hence should be freed in the same function ;)
-  migration_session* ms = static_cast<migration_session*>(MSG_process_get_data(MSG_process_self()));
-
-  double host_speed = ms->vm->getPm()->getSpeed();
-  s_vm_params_t params;
-  ms->vm->getParameters(&params);
-  const sg_size_t ramsize   = ms->vm->getRamsize();
-  const double dp_rate      = host_speed ? (params.mig_speed * params.dp_intensity) / host_speed : 1;
-  const double dp_cap       = params.dp_cap;
-  const double mig_speed    = params.mig_speed;
-  double max_downtime       = params.max_downtime;
-
-  double mig_timeout = 10000000.0;
-  bool skip_stage2   = false;
-
-  size_t remaining_size = ramsize;
-  size_t threshold      = 0.0;
-
-  /* check parameters */
-  if (ramsize == 0)
-    XBT_WARN("migrate a VM, but ramsize is zero");
-
-  if (max_downtime <= 0) {
-    XBT_WARN("use the default max_downtime value 30ms");
-    max_downtime = 0.03;
-  }
-
-  /* Stage1: send all memory pages to the destination. */
-  XBT_DEBUG("mig-stage1: remaining_size %zu", remaining_size);
-  sg_vm_start_dirty_page_tracking(ms->vm);
-
-  double computed_during_stage1 = 0;
-  double clock_prev_send        = MSG_get_clock();
-
-  try {
-    /* At stage 1, we do not need timeout. We have to send all the memory pages even though the duration of this
-     * transfer exceeds the timeout value. */
-    XBT_VERB("Stage 1: Gonna send %llu bytes", ramsize);
-    sg_size_t sent = send_migration_data(ms->vm, ms->src_pm, ms->dst_pm, ramsize, ms->mbox, 1, 0, mig_speed, -1);
-    remaining_size -= sent;
-    computed_during_stage1 = sg_vm_lookup_computed_flops(ms->vm);
-
-    if (sent < ramsize) {
-      XBT_VERB("mig-stage1: timeout, force moving to stage 3");
-      skip_stage2 = true;
-    } else if (sent > ramsize)
-      XBT_CRITICAL("bug");
-
-  } catch (xbt_ex& e) {
-    // hostfailure (if you want to know whether this is the SRC or the DST check directly in send_migration_data code)
-    // Stop the dirty page tracking an return (there is no memory space to release)
-    sg_vm_stop_dirty_page_tracking(ms->vm);
-    return 0;
-  }
-
-  double clock_post_send = MSG_get_clock();
-  mig_timeout -= (clock_post_send - clock_prev_send);
-  if (mig_timeout < 0) {
-    XBT_VERB("The duration of stage 1 exceeds the timeout value, skip stage 2");
-    skip_stage2 = true;
-  }
-
-  /* estimate bandwidth */
-  double bandwidth = ramsize / (clock_post_send - clock_prev_send);
-  threshold        = bandwidth * max_downtime;
-  XBT_DEBUG("actual bandwidth %f (MB/s), threshold %zu", bandwidth / 1024 / 1024, threshold);
-
-  /* Stage2: send update pages iteratively until the size of remaining states becomes smaller than threshold value. */
-  if (not skip_stage2) {
-
-    int stage2_round = 0;
-    for (;;) {
-
-      sg_size_t updated_size = 0;
-      if (stage2_round == 0) {
-        /* just after stage1, nothing has been updated. But, we have to send the data updated during stage1 */
-        updated_size = get_updated_size(computed_during_stage1, dp_rate, dp_cap);
-      } else {
-        double computed = sg_vm_lookup_computed_flops(ms->vm);
-        updated_size    = get_updated_size(computed, dp_rate, dp_cap);
-      }
-
-      XBT_DEBUG("mig-stage 2:%d updated_size %llu computed_during_stage1 %f dp_rate %f dp_cap %f", stage2_round,
-                updated_size, computed_during_stage1, dp_rate, dp_cap);
-
-      /* Check whether the remaining size is below the threshold value. If so, move to stage 3. */
-      remaining_size += updated_size;
-      XBT_DEBUG("mig-stage2.%d: remaining_size %zu (%s threshold %zu)", stage2_round, remaining_size,
-                (remaining_size < threshold) ? "<" : ">", threshold);
-      if (remaining_size < threshold)
-        break;
-
-      sg_size_t sent         = 0;
-      double clock_prev_send = MSG_get_clock();
-      try {
-        XBT_DEBUG("Stage 2, gonna send %llu", updated_size);
-        sent = send_migration_data(ms->vm, ms->src_pm, ms->dst_pm, updated_size, ms->mbox, 2, stage2_round, mig_speed,
-                                   mig_timeout);
-      } catch (xbt_ex& e) {
-        // hostfailure (if you want to know whether this is the SRC or the DST check directly in send_migration_data
-        // code)
-        // Stop the dirty page tracking an return (there is no memory space to release)
-        sg_vm_stop_dirty_page_tracking(ms->vm);
-        return 0;
-      }
-      double clock_post_send = MSG_get_clock();
-
-      if (sent == updated_size) {
-        /* timeout did not happen */
-        double bandwidth = updated_size / (clock_post_send - clock_prev_send);
-        threshold        = bandwidth * max_downtime;
-        XBT_DEBUG("actual bandwidth %f, threshold %zu", bandwidth / 1024 / 1024, threshold);
-        remaining_size -= sent;
-        stage2_round += 1;
-        mig_timeout -= (clock_post_send - clock_prev_send);
-        xbt_assert(mig_timeout > 0);
-
-      } else if (sent < updated_size) {
-        /* When timeout happens, we move to stage 3. The size of memory pages
-         * updated before timeout must be added to the remaining size. */
-        XBT_VERB("mig-stage2.%d: timeout, force moving to stage 3. sent %llu / %llu, eta %lf", stage2_round, sent,
-                 updated_size, (clock_post_send - clock_prev_send));
-        remaining_size -= sent;
-
-        double computed = sg_vm_lookup_computed_flops(ms->vm);
-        updated_size    = get_updated_size(computed, dp_rate, dp_cap);
-        remaining_size += updated_size;
-        break;
-      } else
-        XBT_CRITICAL("bug");
-    }
-  }
-
-  /* Stage3: stop the VM and copy the rest of states. */
-  XBT_DEBUG("mig-stage3: remaining_size %zu", remaining_size);
-  simgrid::vm::VirtualMachineImpl* pimpl = ms->vm->pimpl_vm_;
-  pimpl->setState(SURF_VM_STATE_RUNNING); // FIXME: this bypass of the checks in suspend() is not nice
-  pimpl->isMigrating = false;             // FIXME: this bypass of the checks in suspend() is not nice
-  pimpl->suspend(SIMIX_process_self());
-  sg_vm_stop_dirty_page_tracking(ms->vm);
-
-  try {
-    XBT_DEBUG("Stage 3: Gonna send %zu bytes", remaining_size);
-    send_migration_data(ms->vm, ms->src_pm, ms->dst_pm, remaining_size, ms->mbox, 3, 0, mig_speed, -1);
-  }
-  catch(xbt_ex& e) {
-    //hostfailure (if you want to know whether this is the SRC or the DST check directly in send_migration_data code)
-    // Stop the dirty page tracking an return (there is no memory space to release)
-    ms->vm->resume();
-    return 0;
-  }
-
-  // At that point the Migration is considered valid for the SRC node but remind that the DST side should relocate
-  // effectively the VM on the DST node.
-  XBT_DEBUG("mig: tx_done");
-
-  return 0;
-}
-
-/** @brief Migrate the VM to the given host.
- *  @ingroup msg_VMs
- */
-void MSG_vm_migrate(msg_vm_t vm, msg_host_t dst_pm)
-{
-  /* some thoughts:
-   * - One approach is ...
-   *   We first create a new VM (i.e., destination VM) on the destination   physical host. The destination VM will
-   *   receive the state of the source
-   *   VM over network. We will finally destroy the source VM.
-   *   - This behavior is similar to the way of migration in the real world.
-   *     Even before a migration is completed, we will see a destination VM, consuming resources.
-   *   - We have to relocate all processes. The existing process migration code will work for this?
-   *   - The name of the VM is a somewhat unique ID in the code. It is tricky for the destination VM?
-   *
-   * - Another one is ...
-   *   We update the information of the given VM to place it to the destination physical host.
-   *
-   * The second one would be easier.
-   */
-
-  msg_host_t src_pm = vm->getPm();
-
-  if (src_pm->isOff())
-    THROWF(vm_error, 0, "Cannot migrate VM '%s' from host '%s', which is offline.", vm->getCname(), src_pm->getCname());
-  if (dst_pm->isOff())
-    THROWF(vm_error, 0, "Cannot migrate VM '%s' to host '%s', which is offline.", vm->getCname(), dst_pm->getCname());
-  if (not MSG_vm_is_running(vm))
-    THROWF(vm_error, 0, "Cannot migrate VM '%s' that is not running yet.", vm->getCname());
-  if (vm->isMigrating())
-    THROWF(vm_error, 0, "Cannot migrate VM '%s' that is already migrating.", vm->getCname());
-
-  vm->pimpl_vm_->isMigrating = true;
-
-  migration_session ms;
-  ms.vm     = vm;
-  ms.src_pm = src_pm;
-  ms.dst_pm = dst_pm;
-
-  /* We have two mailboxes. mbox is used to transfer migration data between source and destination PMs. mbox_ctl is used
-   * to detect the completion of a migration. The names of these mailboxes must not conflict with others. */
-  ms.mbox_ctl =
-      simgrid::xbt::string_printf("__mbox_mig_ctl:%s(%s-%s)", vm->getCname(), src_pm->getCname(), dst_pm->getCname());
-  ms.mbox = simgrid::xbt::string_printf("__mbox_mig_src_dst:%s(%s-%s)", vm->getCname(), src_pm->getCname(),
-                                        dst_pm->getCname());
-
-  std::string pr_rx_name = get_mig_process_rx_name(vm, src_pm, dst_pm);
-  std::string pr_tx_name = get_mig_process_tx_name(vm, src_pm, dst_pm);
-
-  MSG_process_create(pr_rx_name.c_str(), migration_rx_fun, &ms, dst_pm);
-
-  MSG_process_create(pr_tx_name.c_str(), migration_tx_fun, &ms, src_pm);
-
-  /* wait until the migration have finished or on error has occurred */
-  XBT_DEBUG("wait for reception of the final ACK (i.e. migration has been correctly performed");
-  msg_task_t task = nullptr;
-  msg_error_t ret = MSG_task_receive(&task, ms.mbox_ctl.c_str());
-
-  vm->pimpl_vm_->isMigrating = false;
-
-  if (ret == MSG_HOST_FAILURE) {
-    // Note that since the communication failed, the owner did not change and the task should be destroyed on the
-    // other side. Hence, just throw the execption
-    XBT_ERROR("SRC crashes, throw an exception (m-control)");
-    // MSG_process_kill(tx_process); // Adrien, I made a merge on Nov 28th 2014, I'm not sure whether this line is
-    // required or not
-    THROWF(host_error, 0, "Source host '%s' failed during the migration of VM '%s'.", src_pm->getCname(),
-           vm->getCname());
-  } else if ((ret == MSG_TRANSFER_FAILURE) || (ret == MSG_TIMEOUT)) {
-    // MSG_TIMEOUT here means that MSG_host_is_avail() returned false.
-    XBT_ERROR("DST crashes, throw an exception (m-control)");
-    THROWF(host_error, 0, "Destination host '%s' failed during the migration of VM '%s'.", dst_pm->getCname(),
-           vm->getCname());
-  }
-
-  xbt_assert(get_mig_task_name(vm, src_pm, dst_pm, 4) == task->name);
-  MSG_task_destroy(task);
-}
 }
diff --git a/src/plugins/vm/VmLiveMigration.cpp b/src/plugins/vm/VmLiveMigration.cpp
new file mode 100644 (file)
index 0000000..46286f9
--- /dev/null
@@ -0,0 +1,327 @@
+/* Copyright (c) 2013-2017. 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/plugins/live_migration.h>
+#include <simgrid/s4u.hpp>
+#include <simgrid/s4u/VirtualMachine.hpp>
+#include <src/instr/instr_private.hpp>
+#include <src/plugins/vm/VirtualMachineImpl.hpp>
+#include <src/plugins/vm/VmLiveMigration.hpp>
+#include <xbt/ex.hpp>
+
+XBT_LOG_NEW_DEFAULT_CATEGORY(vm_live_migration, "S4U virtual machines live migration");
+
+namespace simgrid {
+namespace vm {
+
+void MigrationRx::operator()()
+{
+  XBT_DEBUG("mig: rx_start");
+  bool received_finalize = false;
+
+  std::string finalize_task_name =
+      std::string("__mig_stage3:") + vm_->getCname() + "(" + src_pm_->getCname() + "-" + dst_pm_->getCname() + ")";
+
+  while (not received_finalize) {
+    std::string* payload = static_cast<std::string*>(mbox->get());
+
+    if (finalize_task_name == *payload)
+      received_finalize = true;
+
+    delete payload;
+  }
+
+  // Here Stage 1, 2  and 3 have been performed.
+  // Hence complete the migration
+
+  // Copy the reference to the vm (if SRC crashes now, do_migration will free ms)
+  // This is clearly ugly but I (Adrien) need more time to do something cleaner (actually we should copy the whole ms
+  // structure at the beginning and free it at the end of each function)
+  simgrid::s4u::VirtualMachine* vm = vm_;
+  simgrid::s4u::Host* dst_pm       = dst_pm_;
+
+  // Make sure that we cannot get interrupted between the migrate and the resume to not end in an inconsistent state
+  simgrid::simix::kernelImmediate([vm, dst_pm]() {
+    /* Update the vm location */
+    /* precopy migration makes the VM temporally paused */
+    xbt_assert(vm->getState() == SURF_VM_STATE_SUSPENDED);
+
+    /* Update the vm location and resume it */
+    vm->pimpl_vm_->setPm(dst_pm);
+    vm->resume();
+  });
+
+  // Now the VM is running on the new host (the migration is completed) (even if the SRC crash)
+  vm->pimpl_vm_->isMigrating = false;
+  XBT_DEBUG("VM(%s) moved from PM(%s) to PM(%s)", vm_->getCname(), src_pm_->getCname(), dst_pm_->getCname());
+
+  if (TRACE_msg_vm_is_enabled()) {
+    static long long int counter = 0;
+    std::string key              = std::to_string(counter);
+    counter++;
+
+    // start link
+    container_t msg = simgrid::instr::Container::byName(vm->getName());
+    simgrid::instr::Container::getRoot()->getLink("MSG_VM_LINK")->startEvent(msg, "M", key);
+
+    // destroy existing container of this vm
+    container_t existing_container = simgrid::instr::Container::byName(vm->getName());
+    existing_container->removeFromParent();
+    delete existing_container;
+
+    // create new container on the new_host location
+    new simgrid::instr::Container(vm->getCname(), "MSG_VM", simgrid::instr::Container::byName(dst_pm_->getName()));
+
+    // end link
+    msg = simgrid::instr::Container::byName(vm->getName());
+    simgrid::instr::Container::getRoot()->getLink("MSG_VM_LINK")->endEvent(msg, "M", key);
+  }
+  // Inform the SRC that the migration has been correctly performed
+  std::string* payload = new std::string("__mig_stage4:");
+  *payload             = *payload + vm_->getCname() + "(" + src_pm_->getCname() + "-" + dst_pm_->getCname() + ")";
+
+  mbox_ctl->put(payload, 0);
+
+  XBT_DEBUG("mig: rx_done");
+}
+
+static sg_size_t get_updated_size(double computed, double dp_rate, double dp_cap)
+{
+  double updated_size = computed * dp_rate;
+  XBT_DEBUG("updated_size %f dp_rate %f", updated_size, dp_rate);
+  if (updated_size > dp_cap) {
+    updated_size = dp_cap;
+  }
+
+  return static_cast<sg_size_t>(updated_size);
+}
+
+sg_size_t MigrationTx::sendMigrationData(sg_size_t size, int stage, int stage2_round, double mig_speed, double timeout)
+{
+  sg_size_t sent   = size;
+  std::string* msg = new std::string("__mig_stage");
+  *msg = *msg + std::to_string(stage) + ":" + vm_->getCname() + "(" + src_pm_->getCname() + "-" + dst_pm_->getCname() +
+         ")";
+
+  double clock_sta = s4u::Engine::getClock();
+
+  s4u::Activity* comm = nullptr;
+  try {
+    if (mig_speed > 0)
+      comm = mbox->put_init(msg, size)->setRate(mig_speed)->wait(timeout);
+    else
+      comm = mbox->put_async(msg, size)->wait();
+  } catch (xbt_ex& e) {
+    if (comm) {
+      sg_size_t remaining = static_cast<sg_size_t>(comm->getRemains());
+      XBT_VERB("timeout (%lf s) in sending_migration_data, remaining %llu bytes of %llu", timeout, remaining, size);
+      sent -= remaining;
+    }
+  }
+
+  double clock_end    = s4u::Engine::getClock();
+  double duration     = clock_end - clock_sta;
+  double actual_speed = size / duration;
+
+  if (stage == 2)
+    XBT_DEBUG("mig-stage%d.%d: sent %llu duration %f actual_speed %f (target %f)", stage, stage2_round, size, duration,
+              actual_speed, mig_speed);
+  else
+    XBT_DEBUG("mig-stage%d: sent %llu duration %f actual_speed %f (target %f)", stage, size, duration, actual_speed,
+              mig_speed);
+
+  return sent;
+}
+
+void MigrationTx::operator()()
+{
+  XBT_DEBUG("mig: tx_start");
+
+  double host_speed = vm_->getPm()->getSpeed();
+  s_vm_params_t params;
+  vm_->getParameters(&params);
+  const sg_size_t ramsize = vm_->getRamsize();
+  const double dp_rate    = host_speed ? (params.mig_speed * params.dp_intensity) / host_speed : 1;
+  const double dp_cap     = params.dp_cap;
+  const double mig_speed  = params.mig_speed;
+  double max_downtime     = params.max_downtime;
+
+  double mig_timeout = 10000000.0;
+  bool skip_stage2   = false;
+
+  size_t remaining_size = ramsize;
+  size_t threshold      = 0.0;
+
+  /* check parameters */
+  if (ramsize == 0)
+    XBT_WARN("migrate a VM, but ramsize is zero");
+
+  if (max_downtime <= 0) {
+    XBT_WARN("use the default max_downtime value 30ms");
+    max_downtime = 0.03;
+  }
+
+  /* Stage1: send all memory pages to the destination. */
+  XBT_DEBUG("mig-stage1: remaining_size %zu", remaining_size);
+  sg_vm_start_dirty_page_tracking(vm_);
+
+  double computed_during_stage1 = 0;
+  double clock_prev_send        = s4u::Engine::getClock();
+
+  try {
+    /* At stage 1, we do not need timeout. We have to send all the memory pages even though the duration of this
+     * transfer exceeds the timeout value. */
+    XBT_VERB("Stage 1: Gonna send %llu bytes", ramsize);
+    sg_size_t sent = sendMigrationData(ramsize, 1, 0, mig_speed, -1);
+    remaining_size -= sent;
+    computed_during_stage1 = sg_vm_lookup_computed_flops(vm_);
+
+    if (sent < ramsize) {
+      XBT_VERB("mig-stage1: timeout, force moving to stage 3");
+      skip_stage2 = true;
+    } else if (sent > ramsize)
+      XBT_CRITICAL("bug");
+
+  } catch (xbt_ex& e) {
+    // hostfailure (if you want to know whether this is the SRC or the DST check directly in send_migration_data code)
+    // Stop the dirty page tracking an return (there is no memory space to release)
+    sg_vm_stop_dirty_page_tracking(vm_);
+    return;
+  }
+
+  double clock_post_send = s4u::Engine::getClock();
+  mig_timeout -= (clock_post_send - clock_prev_send);
+  if (mig_timeout < 0) {
+    XBT_VERB("The duration of stage 1 exceeds the timeout value, skip stage 2");
+    skip_stage2 = true;
+  }
+
+  /* estimate bandwidth */
+  double bandwidth = ramsize / (clock_post_send - clock_prev_send);
+  threshold        = bandwidth * max_downtime;
+  XBT_DEBUG("actual bandwidth %f (MB/s), threshold %zu", bandwidth / 1024 / 1024, threshold);
+
+  /* Stage2: send update pages iteratively until the size of remaining states becomes smaller than threshold value. */
+  if (not skip_stage2) {
+
+    int stage2_round = 0;
+    for (;;) {
+      sg_size_t updated_size = 0;
+      if (stage2_round == 0) {
+        /* just after stage1, nothing has been updated. But, we have to send the data updated during stage1 */
+        updated_size = get_updated_size(computed_during_stage1, dp_rate, dp_cap);
+      } else {
+        double computed = sg_vm_lookup_computed_flops(vm_);
+        updated_size    = get_updated_size(computed, dp_rate, dp_cap);
+      }
+
+      XBT_DEBUG("mig-stage 2:%d updated_size %llu computed_during_stage1 %f dp_rate %f dp_cap %f", stage2_round,
+                updated_size, computed_during_stage1, dp_rate, dp_cap);
+
+      /* Check whether the remaining size is below the threshold value. If so, move to stage 3. */
+      remaining_size += updated_size;
+      XBT_DEBUG("mig-stage2.%d: remaining_size %zu (%s threshold %zu)", stage2_round, remaining_size,
+                (remaining_size < threshold) ? "<" : ">", threshold);
+      if (remaining_size < threshold)
+        break;
+
+      sg_size_t sent         = 0;
+      double clock_prev_send = s4u::Engine::getClock();
+      try {
+        XBT_DEBUG("Stage 2, gonna send %llu", updated_size);
+        sent = sendMigrationData(updated_size, 2, stage2_round, mig_speed, mig_timeout);
+      } catch (xbt_ex& e) {
+        // hostfailure (if you want to know whether this is the SRC or the DST check directly in send_migration_data
+        // code)
+        // Stop the dirty page tracking an return (there is no memory space to release)
+        sg_vm_stop_dirty_page_tracking(vm_);
+        return;
+      }
+      double clock_post_send = s4u::Engine::getClock();
+
+      if (sent == updated_size) {
+        /* timeout did not happen */
+        double bandwidth = updated_size / (clock_post_send - clock_prev_send);
+        threshold        = bandwidth * max_downtime;
+        XBT_DEBUG("actual bandwidth %f, threshold %zu", bandwidth / 1024 / 1024, threshold);
+        remaining_size -= sent;
+        stage2_round += 1;
+        mig_timeout -= (clock_post_send - clock_prev_send);
+        xbt_assert(mig_timeout > 0);
+
+      } else if (sent < updated_size) {
+        /* When timeout happens, we move to stage 3. The size of memory pages
+         * updated before timeout must be added to the remaining size. */
+        XBT_VERB("mig-stage2.%d: timeout, force moving to stage 3. sent %llu / %llu, eta %lf", stage2_round, sent,
+                 updated_size, (clock_post_send - clock_prev_send));
+        remaining_size -= sent;
+
+        double computed = sg_vm_lookup_computed_flops(vm_);
+        updated_size    = get_updated_size(computed, dp_rate, dp_cap);
+        remaining_size += updated_size;
+        break;
+      } else
+        XBT_CRITICAL("bug");
+    }
+  }
+
+  /* Stage3: stop the VM and copy the rest of states. */
+  XBT_DEBUG("mig-stage3: remaining_size %zu", remaining_size);
+  vm_->suspend();
+  sg_vm_stop_dirty_page_tracking(vm_);
+
+  try {
+    XBT_DEBUG("Stage 3: Gonna send %zu bytes", remaining_size);
+    sendMigrationData(remaining_size, 3, 0, mig_speed, -1);
+  } catch (xbt_ex& e) {
+    // hostfailure (if you want to know whether this is the SRC or the DST check directly in send_migration_data code)
+    // Stop the dirty page tracking an return (there is no memory space to release)
+    vm_->resume();
+    return;
+  }
+
+  // At that point the Migration is considered valid for the SRC node but remind that the DST side should relocate
+  // effectively the VM on the DST node.
+  XBT_DEBUG("mig: tx_done");
+}
+}
+}
+
+SG_BEGIN_DECL()
+void sg_vm_migrate(simgrid::s4u::VirtualMachine* vm, simgrid::s4u::Host* dst_pm)
+{
+  simgrid::s4u::Host* src_pm = vm->getPm();
+
+  if (src_pm->isOff())
+    THROWF(vm_error, 0, "Cannot migrate VM '%s' from host '%s', which is offline.", vm->getCname(), src_pm->getCname());
+  if (dst_pm->isOff())
+    THROWF(vm_error, 0, "Cannot migrate VM '%s' to host '%s', which is offline.", vm->getCname(), dst_pm->getCname());
+  if (vm->getState() != SURF_VM_STATE_RUNNING)
+    THROWF(vm_error, 0, "Cannot migrate VM '%s' that is not running yet.", vm->getCname());
+  if (vm->isMigrating())
+    THROWF(vm_error, 0, "Cannot migrate VM '%s' that is already migrating.", vm->getCname());
+
+  std::string rx_name =
+      std::string("__pr_mig_rx:") + vm->getCname() + "(" + src_pm->getCname() + "-" + dst_pm->getCname() + ")";
+  std::string tx_name =
+      std::string("__pr_mig_tx:") + vm->getCname() + "(" + src_pm->getCname() + "-" + dst_pm->getCname() + ")";
+
+  simgrid::s4u::ActorPtr rx =
+      simgrid::s4u::Actor::createActor(rx_name.c_str(), dst_pm, simgrid::vm::MigrationRx(vm, dst_pm));
+  simgrid::s4u::ActorPtr tx =
+      simgrid::s4u::Actor::createActor(tx_name.c_str(), src_pm, simgrid::vm::MigrationTx(vm, dst_pm));
+
+  /* wait until the migration have finished or on error has occurred */
+  XBT_DEBUG("wait for reception of the final ACK (i.e. migration has been correctly performed");
+  simgrid::s4u::MailboxPtr mbox_ctl = simgrid::s4u::Mailbox::byName(
+      std::string("__mbox_mig_ctl:") + vm->getCname() + "(" + src_pm->getCname() + "-" + dst_pm->getCname() + ")");
+  delete static_cast<std::string*>(mbox_ctl->get());
+
+  tx->join();
+  rx->join();
+
+  vm->pimpl_vm_->isMigrating = false;
+}
+}
diff --git a/src/plugins/vm/VmLiveMigration.hpp b/src/plugins/vm/VmLiveMigration.hpp
new file mode 100644 (file)
index 0000000..7df29b4
--- /dev/null
@@ -0,0 +1,55 @@
+/* Copyright (c) 2004-2016. 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/s4u.hpp"
+
+#ifndef VM_LIVE_MIGRATION_HPP_
+#define VM_LIVE_MIGRATION_HPP_
+
+namespace simgrid {
+namespace vm {
+
+class MigrationRx {
+  /* The miration_rx process uses mbox_ctl to let the caller of do_migration()  know the completion of the migration. */
+  s4u::MailboxPtr mbox_ctl;
+  /* The migration_rx and migration_tx processes use mbox to transfer migration data. */
+  s4u::MailboxPtr mbox;
+  s4u::VirtualMachine* vm_;
+  s4u::Host* src_pm_ = nullptr;
+  s4u::Host* dst_pm_ = nullptr;
+
+public:
+  explicit MigrationRx(s4u::VirtualMachine* vm, s4u::Host* dst_pm) : vm_(vm), dst_pm_(dst_pm)
+  {
+    src_pm_ = vm_->getPm();
+
+    mbox_ctl = s4u::Mailbox::byName(std::string("__mbox_mig_ctl:") + vm_->getCname() + "(" + src_pm_->getCname() + "-" +
+                                    dst_pm_->getCname() + ")");
+    mbox = s4u::Mailbox::byName(std::string("__mbox_mig_src_dst:") + vm_->getCname() + "(" + src_pm_->getCname() + "-" +
+                                dst_pm_->getCname() + ")");
+  }
+  void operator()();
+};
+
+class MigrationTx {
+  /* The migration_rx and migration_tx processes use mbox to transfer migration data. */
+  s4u::MailboxPtr mbox;
+  s4u::VirtualMachine* vm_;
+  s4u::Host* src_pm_ = nullptr;
+  s4u::Host* dst_pm_ = nullptr;
+
+public:
+  explicit MigrationTx(s4u::VirtualMachine* vm, s4u::Host* dst_pm) : vm_(vm), dst_pm_(dst_pm)
+  {
+    src_pm_ = vm_->getPm();
+    mbox = s4u::Mailbox::byName(std::string("__mbox_mig_src_dst:") + vm_->getCname() + "(" + src_pm_->getCname() + "-" +
+                                dst_pm_->getCname() + ")");
+  }
+  void operator()();
+  sg_size_t sendMigrationData(sg_size_t size, int stage, int stage2_round, double mig_speed, double timeout);
+};
+}
+}
+#endif
index 3ee05b2..153625c 100644 (file)
@@ -3,11 +3,13 @@
 /* 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/s4u/Actor.hpp"
 #include "src/instr/instr_private.hpp"
 #include "src/plugins/vm/VirtualMachineImpl.hpp"
 #include "src/plugins/vm/VmHostExt.hpp"
 #include "src/simix/smx_host_private.hpp"
 #include "src/surf/cpu_cas01.hpp"
+#include <src/plugins/vm/VmLiveMigration.hpp>
 
 XBT_LOG_NEW_DEFAULT_CATEGORY(s4u_vm, "S4U virtual machines");
 
index 8ee67e0..f4f501d 100644 (file)
@@ -51,8 +51,8 @@ $ $SG_TEST_EXENV ${bindir:=.}/cloud-simple$EXEEXT --log=no_loc ${platfdir}/small
 > [Fafard:master_:(1) 49.000000] [msg_test/INFO] ## Test 5 (ended)
 > [Fafard:master_:(1) 49.000000] [msg_test/INFO] ## Test 6 (started): Check migration impact (not yet implemented neither on the CPU resource nor on the network one
 > [Fafard:master_:(1) 49.000000] [msg_test/INFO] ### Relocate VM0 between PM0 and PM1
-> [Fafard:__pr_mig_tx:VM0(Fafard-Tremblay):(38) 49.010000] [msg_vm/WARNING] use the default max_downtime value 30ms
+> [Fafard:__pr_mig_tx:VM0(Fafard-Tremblay):(38) 49.010000] [vm_live_migration/WARNING] use the default max_downtime value 30ms
 > [Bourassa:comm_rx:(36) 49.204993] [msg_test/INFO] VM0:comm_tx to Bourassa:comm_rx => 0.204993 sec
-> [Tremblay:__pr_mig_tx:VM0(Tremblay-Fafard):(40) 191.674258] [msg_vm/WARNING] use the default max_downtime value 30ms
+> [Tremblay:__pr_mig_tx:VM0(Tremblay-Fafard):(40) 191.674258] [vm_live_migration/WARNING] use the default max_downtime value 30ms
 > [Fafard:master_:(1) 339.199251] [msg_test/INFO] ## Test 6 (ended)
 > [339.199251] [msg_test/INFO] Bye (simulation time 339.199)
index 92cf23e..0759c48 100644 (file)
@@ -370,6 +370,8 @@ set(PLUGINS_SRC
   src/plugins/vm/VirtualMachineImpl.cpp
   src/plugins/vm/VmHostExt.hpp
   src/plugins/vm/VmHostExt.cpp
+  src/plugins/vm/VmLiveMigration.cpp
+  src/plugins/vm/VmLiveMigration.hpp
   )
   
 set(SIMIX_GENERATED_SRC   src/simix/popping_generated.cpp  )