Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Merge branch 'master' into hypervisor
authorPaul Bédaride <paul.bedaride@gmail.com>
Wed, 19 Jun 2013 11:42:14 +0000 (13:42 +0200)
committerPaul Bédaride <paul.bedaride@gmail.com>
Wed, 19 Jun 2013 11:42:14 +0000 (13:42 +0200)
Conflicts:
src/bindings/java/jmsg_synchro.c
src/bindings/java/org/simgrid/msg/Host.java
src/include/surf/surf.h
src/smpi/colls/allgather-RDB.c
src/smpi/colls/allgather-SMP-simple.c
src/surf/cpu_cas01.c
src/surf/surf.c
src/surf/surf_routing.c
src/surf/workstation.c

64 files changed:
buildtools/Cmake/DefinePackages.cmake
examples/java/cloud/Cloud.java
examples/java/cloud/Master.java
examples/java/cloud/Slave.java
examples/msg/cloud/CMakeLists.txt
examples/msg/cloud/bound.c [new file with mode: 0644]
examples/msg/cloud/masterslave_virtual_machines.c
examples/msg/cloud/migrate_vm.c [new file with mode: 0644]
examples/msg/cloud/simple_plat.xml [new file with mode: 0644]
examples/msg/cloud/simple_vm.c [new file with mode: 0644]
include/msg/datatypes.h
include/msg/msg.h
include/simgrid/platf.h
include/simgrid/simix.h
include/xbt/ex.h
include/xbt/lib.h
src/bindings/java/jmsg_vm.c
src/bindings/java/jmsg_vm.h
src/bindings/java/org/simgrid/msg/Host.java
src/bindings/java/org/simgrid/msg/VM.java
src/bindings/java/smx_context_java.c
src/bindings/lua/lua_host.c
src/include/surf/surf.h
src/msg/instr_msg_vm.c
src/msg/msg_global.c
src/msg/msg_gos.c
src/msg/msg_host.c
src/msg/msg_private.h
src/msg/msg_process.c
src/msg/msg_task.c
src/msg/msg_vm.c
src/simdag/sd_global.c
src/simgrid/sg_config.c
src/simix/smx_global.c
src/simix/smx_host.c
src/simix/smx_host_private.h
src/simix/smx_io.c
src/simix/smx_network.c
src/simix/smx_new_api.c
src/simix/smx_process.c
src/simix/smx_smurf_private.h
src/simix/smx_synchro.c
src/simix/smx_user.c
src/simix/smx_vm.c [new file with mode: 0644]
src/surf/cpu_cas01.c
src/surf/cpu_cas01_private.h [new file with mode: 0644]
src/surf/cpu_ti.c
src/surf/network.c
src/surf/network_constant.c
src/surf/network_gtnets.c
src/surf/network_ns3.c
src/surf/new_model.c
src/surf/storage.c
src/surf/surf.c
src/surf/surf_action.c
src/surf/surf_private.h
src/surf/vm_workstation.c [new file with mode: 0644]
src/surf/vm_workstation_private.h [new file with mode: 0644]
src/surf/workstation.c
src/surf/workstation_private.h [new file with mode: 0644]
src/surf/workstation_ptask_L07.c
src/xbt/ex.c
src/xbt/lib.c
testsuite/surf/surf_usage.c

index f8436b7..8803ef8 100644 (file)
@@ -311,6 +311,7 @@ set(SURF_SRC
   src/surf/trace_mgr.c
   src/surf/workstation.c
   src/surf/workstation_ptask_L07.c
+  src/surf/vm_workstation.c
   src/xbt/xbt_sg_stubs.c
   )
 
@@ -328,6 +329,7 @@ set(SIMIX_SRC
   src/simix/smx_smurf.c
   src/simix/smx_synchro.c
   src/simix/smx_user.c
+  src/simix/smx_vm.c
   )
 
 set(SIMGRID_SRC
index 1edb24b..eba9d07 100644 (file)
@@ -16,7 +16,7 @@ import org.simgrid.msg.MsgException;
 public class Cloud {
        public static final double task_comp_size = 10;
        public static final double task_comm_size = 10;
-
+       public static final int hostNB = 3 ; 
        public static void main(String[] args) throws MsgException {       
            Msg.init(args); 
            
@@ -27,12 +27,12 @@ public class Cloud {
            }
            /* Construct the platform */
                Msg.createEnvironment(args[0]);
-                 /* Retrieve the 10 first hosts of the platform file */
                Host[] hosts = Host.all();
-               if (hosts.length < 10) {
-                       Msg.info("I need at least 10 hosts in the platform file, but " + args[0] + " contains only " + hosts.length + " hosts");
+               if (hosts.length < hostNB+1) {
+                       Msg.info("I need at least "+ (hostNB+1) +"  hosts in the platform file, but " + args[0] + " contains only " + hosts.length + " hosts");
                        System.exit(42);
                }
+               Msg.info("Start"+ hostNB +"  hosts");
                new Master(hosts[0],"Master",hosts).start();
                /* Execute the simulation */
                Msg.run();
index 1551521..a832cac 100644 (file)
@@ -23,31 +23,36 @@ public class Master extends Process {
                this.hosts = hosts;
        }
        public void main(String[] args) throws MsgException {
-               int slavesCount = 10;
+               int slavesCount = Cloud.hostNB;
                
                ArrayList<VM> vms = new ArrayList<VM>();
                
+               // Create one VM per host and bind a process inside each one. 
                for (int i = 0; i < slavesCount; i++) {
-                       Slave slave = new Slave(hosts[i],i);
-                       slave.start();
-                       VM vm = new VM(hosts[i],hosts[i]+"_"+i,1);
-                       vm.bind(slave);
+                       Msg.info("create VM0"+i);       
+                       VM vm = new VM(hosts[i+1],"VM0"+i);
+                       vm.start();
                        vms.add(vm);
+                       Slave slave = new Slave(vm,i);
+                       Msg.info("Put Worker "+slave.msgName()+ " on "+vm.getName());
+                       slave.start();
+       
                }
                Msg.info("Launched " + vms.size() + " VMs");
                
                Msg.info("Send a first batch of work to everyone");
                workBatch(slavesCount);
                
-               Msg.info("Now suspend all VMs, just for fun");
+               Msg.info("Suspend all VMs");
                for (int i = 0; i < vms.size(); i++) {
+                       Msg.info("Suspend "+vms.get(i).getName());
                        vms.get(i).suspend();
                }
                
                Msg.info("Wait a while");
                waitFor(2);
                
-               Msg.info("Enough. Let's resume everybody.");
+               Msg.info("Resume all VMs.");
                for (int i = 0; i < vms.size(); i++) {
                        vms.get(i).resume();
                }
@@ -58,39 +63,44 @@ public class Master extends Process {
                Msg.info("Add one more process per VM.");
                for (int i = 0; i < vms.size(); i++) {
                        VM vm = vms.get(i);
-                       Slave slave = new Slave(hosts[i],i + vms.size());
+                       Slave slave = new Slave(vm,i + vms.size());
                        slave.start();
-                       vm.bind(slave);
                }
+       
+               workBatch(slavesCount * 2);
                
-               Msg.info("Migrate everyone to the second host.");
+               Msg.info("Migrate everyone to "+hosts[2].getName());
                for (int i = 0; i < vms.size(); i++) {
-                       vms.get(i).migrate(hosts[1]);
+                       vms.get(i).migrate(hosts[2]);
                }
                
-               Msg.info("Suspend everyone, move them to the third host, and resume them.");
+//             Msg.info("Suspend everyone, move them to the third host, and resume them.");
+               Msg.info("Migrate everyone to the third host (please note that cold migration is not yet available");
+               
+
                for (int i = 0; i < vms.size(); i++) {
                        VM vm = vms.get(i);
-                       vm.suspend();
-                       vm.migrate(hosts[2]);
-                       vm.resume();
+       //              vm.suspend();
+                       vm.migrate(hosts[3]);
+               //      vm.resume();
                }
                
-               workBatch(slavesCount * 2);
+       
                
                Msg.info("Let's shut down the simulation and kill everyone.");
                
                for (int i = 0; i < vms.size(); i++) {
                        vms.get(i).shutdown();
+                       vms.get(i).destroy();
                }                               
                Msg.info("Master done.");
        }
        
        public void workBatch(int slavesCount) throws MsgException {
                for (int i = 0; i < slavesCount; i++) {
-                       Task task = new Task("Task_" + i, Cloud.task_comp_size, Cloud.task_comm_size);
-                       Msg.info("Sending to " + i);
-                       task.send("slave_" + i);
+                       Task task = new Task("Task0" + i, Cloud.task_comp_size, Cloud.task_comm_size);
+                       Msg.info("Sending to WRK0" + i);
+                       task.send("MBOX:WRK0" + i);
                }
        }
 }
index 01e646f..527f989 100644 (file)
@@ -15,15 +15,15 @@ import org.simgrid.msg.Task;
 public class Slave extends Process {
        private int number;
        public Slave(Host host, int number) {
-               super(host,"Slave " + number,null);
+               super(host,"WRK0" + number,null);
                this.number = number;
        }
        public void main(String[] args) throws MsgException {
+               Msg.info(this.msgName() +" is listenning on MBOX:WRK0"+ number);
                while(true) {                   
-                       Msg.info("Receiving on " + "slave_" + number);
                        Task task;
                         try {
-                                task = Task.receive("slave_"+number);
+                                task = Task.receive("MBOX:WRK0"+number);
                         } catch (MsgException e) {
                                 Msg.debug("Received failed. I'm done. See you!");
                                 break;
@@ -38,7 +38,7 @@ public class Slave extends Process {
                        } catch (MsgException e) {
 
                        }
-                       Msg.info("\"" + task.getName() + "\" done ");
+                       Msg.info(this.msgName() +" executed task (" + task.getName()+")");
                }
 
                
index 534992d..29c9f3c 100644 (file)
@@ -3,13 +3,15 @@ cmake_minimum_required(VERSION 2.6)
 set(EXECUTABLE_OUTPUT_PATH "${CMAKE_CURRENT_BINARY_DIR}")
 
 add_executable(masterslave_virtual_machines "masterslave_virtual_machines.c")
+add_executable(simple_vm "simple_vm.c")
+add_executable(migrate_vm "migrate_vm.c")
+add_executable(bound "bound.c")
 
 ### Add definitions for compile
-if(WIN32)
-  target_link_libraries(masterslave_virtual_machines simgrid )
-else()
-  target_link_libraries(masterslave_virtual_machines simgrid)
-endif()
+target_link_libraries(masterslave_virtual_machines simgrid)
+target_link_libraries(simple_vm simgrid)
+target_link_libraries(migrate_vm simgrid)
+target_link_libraries(bound simgrid)
 
 set(tesh_files
   ${tesh_files}
@@ -19,11 +21,15 @@ set(tesh_files
 set(xml_files
   ${xml_files}
   ${CMAKE_CURRENT_SOURCE_DIR}/masterslave_virtual_machines.xml
+  ${CMAKE_CURRENT_SOURCE_DIR}/simple_plat.xml
   PARENT_SCOPE
   )
 set(examples_src
   ${examples_src}
   ${CMAKE_CURRENT_SOURCE_DIR}/masterslave_virtual_machines.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/simple_vm.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/migrate_vm.c
+  ${CMAKE_CURRENT_SOURCE_DIR}/bound.c
   PARENT_SCOPE
   )
 set(bin_files
diff --git a/examples/msg/cloud/bound.c b/examples/msg/cloud/bound.c
new file mode 100644 (file)
index 0000000..ec22eef
--- /dev/null
@@ -0,0 +1,380 @@
+/* Copyright (c) 2007-2013. 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 <stdio.h>
+#include "msg/msg.h"            /* Yeah! If you want to use msg, you need to include msg/msg.h */
+#include "xbt/sysdep.h"         /* calloc, printf */
+
+/* Create a log channel to have nice outputs. */
+#include "xbt/log.h"
+#include "xbt/asserts.h"
+XBT_LOG_NEW_DEFAULT_CATEGORY(msg_test,
+                             "Messages specific for this msg example");
+
+/** @addtogroup MSG_examples
+ *
+ * - <b>priority/priority.c</b>: Demonstrates the use of @ref
+ *   MSG_task_set_bound to change the computation priority of a
+ *   given task.
+ *
+ */
+
+static int worker_main(int argc, char *argv[])
+{
+  double computation_amount = atof(argv[1]);
+  int use_bound = atoi(argv[2]);
+  double bound = atof(argv[3]);
+
+  {
+    double clock_sta = MSG_get_clock();
+
+    msg_task_t task = MSG_task_create("Task", computation_amount, 0, NULL);
+    if (use_bound)
+      MSG_task_set_bound(task, bound);
+    MSG_task_execute(task);
+    MSG_task_destroy(task);
+
+    double clock_end = MSG_get_clock();
+    double duration = clock_end - clock_sta;
+    double flops_per_sec = computation_amount / duration;
+
+    if (use_bound)
+      XBT_INFO("bound to %f => duration %f (%f flops/s)", bound, duration, flops_per_sec);
+    else
+      XBT_INFO("not bound => duration %f (%f flops/s)", duration, flops_per_sec);
+  }
+
+  return 0;
+}
+
+static void launch_worker(msg_host_t host, const char *pr_name, double computation_amount, int use_bound, double bound)
+{
+  char **argv = xbt_new(char *, 5);
+  argv[0] = xbt_strdup(pr_name);
+  argv[1] = bprintf("%lf", computation_amount);
+  argv[2] = bprintf("%d", use_bound);
+  argv[3] = bprintf("%lf", bound);
+  argv[4] = NULL;
+
+  MSG_process_create_with_arguments(pr_name, worker_main, NULL, host, 4, argv);
+}
+
+
+
+static int worker_busy_loop_main(int argc, char *argv[])
+{
+  msg_task_t *task = MSG_process_get_data(MSG_process_self());
+  for (;;)
+    MSG_task_execute(*task);
+
+  return 0;
+}
+
+/* FIXME: */
+#define DOUBLE_MAX 100000000000L
+
+static void test_dynamic_change(void)
+{
+  xbt_dynar_t hosts_dynar = MSG_hosts_as_dynar();
+  msg_host_t pm0 = xbt_dynar_get_as(hosts_dynar, 0, msg_host_t);
+
+  msg_host_t vm0 = MSG_vm_create_core(pm0, "VM0");
+  msg_host_t vm1 = MSG_vm_create_core(pm0, "VM1");
+  MSG_vm_start(vm0);
+  MSG_vm_start(vm1);
+
+  msg_task_t task0 = MSG_task_create("Task0", DOUBLE_MAX, 0, NULL);
+  msg_task_t task1 = MSG_task_create("Task1", DOUBLE_MAX, 0, NULL);
+  msg_process_t pr0 = MSG_process_create("worker0", worker_busy_loop_main, &task0, vm0);
+  msg_process_t pr1 = MSG_process_create("worker1", worker_busy_loop_main, &task1, vm1);
+
+
+  double task0_remain_prev = MSG_task_get_remaining_computation(task0);
+  double task1_remain_prev = MSG_task_get_remaining_computation(task1);
+
+  {
+    const double cpu_speed = MSG_get_host_speed(pm0);
+    int i = 0;
+    for (i = 0; i < 10; i++) {
+      double new_bound = (cpu_speed / 10) * i;
+      XBT_INFO("set bound of VM1 to %f", new_bound);
+      MSG_vm_set_bound(vm1, new_bound);
+      MSG_process_sleep(100);
+
+      double task0_remain_now = MSG_task_get_remaining_computation(task0);
+      double task1_remain_now = MSG_task_get_remaining_computation(task1);
+
+      double task0_flops_per_sec = task0_remain_prev - task0_remain_now;
+      double task1_flops_per_sec = task1_remain_prev - task1_remain_now;
+
+      XBT_INFO("Task0@VM0: %f flops/s", task0_flops_per_sec / 100);
+      XBT_INFO("Task1@VM1: %f flops/s", task1_flops_per_sec / 100);
+
+      task0_remain_prev = task0_remain_now;
+      task1_remain_prev = task1_remain_now;
+    }
+  }
+
+  MSG_process_kill(pr0);
+  MSG_process_kill(pr1);
+  
+  MSG_vm_destroy(vm0);
+  MSG_vm_destroy(vm1);
+}
+
+
+
+static void test_one_task(msg_host_t hostA)
+{
+  const double cpu_speed = MSG_get_host_speed(hostA);
+  const double computation_amount = cpu_speed * 10;
+  const char *hostA_name = MSG_host_get_name(hostA);
+
+  XBT_INFO("### Test: with/without MSG_task_set_bound");
+
+#if 0
+  /* Easy-to-understand code (without calling MSG_task_set_bound) */
+  {
+    double clock_sta = MSG_get_clock();
+
+    msg_task_t task = MSG_task_create("Task", computation_amount, 0, NULL);
+    MSG_task_execute(task);
+    MSG_task_destroy(task);
+
+    double clock_end = MSG_get_clock();
+    double duration = clock_end - clock_sta;
+    double flops_per_sec = computation_amount / duration;
+
+    XBT_INFO("not bound => duration %f (%f flops/s)", duration, flops_per_sec);
+  }
+
+  /* Easy-to-understand code (with calling MSG_task_set_bound) */
+  {
+    double clock_sta = MSG_get_clock();
+
+    msg_task_t task = MSG_task_create("Task", computation_amount, 0, NULL);
+    MSG_task_set_bound(task, cpu_speed / 2);
+    MSG_task_execute(task);
+    MSG_task_destroy(task);
+
+    double clock_end = MSG_get_clock();
+    double duration = clock_end - clock_sta;
+    double flops_per_sec = computation_amount / duration;
+
+    XBT_INFO("bound to 0.5 => duration %f (%f flops/s)", duration, flops_per_sec);
+  }
+#endif
+
+  {
+    XBT_INFO("### Test: no bound for Task1@%s", hostA_name);
+    launch_worker(hostA, "worker0", computation_amount, 0, 0);
+  }
+
+  MSG_process_sleep(1000);
+
+  {
+    XBT_INFO("### Test: 50%% for Task1@%s", hostA_name);
+    launch_worker(hostA, "worker0", computation_amount, 1, cpu_speed / 2);
+  }
+
+  MSG_process_sleep(1000);
+
+  {
+    XBT_INFO("### Test: 33%% for Task1@%s", hostA_name);
+    launch_worker(hostA, "worker0", computation_amount, 1, cpu_speed / 3);
+  }
+
+  MSG_process_sleep(1000);
+
+  {
+    XBT_INFO("### Test: zero for Task1@%s (i.e., unlimited)", hostA_name);
+    launch_worker(hostA, "worker0", computation_amount, 1, 0);
+  }
+
+  MSG_process_sleep(1000);
+
+  {
+    XBT_INFO("### Test: 200%% for Task1@%s (i.e., meaningless)", hostA_name);
+    launch_worker(hostA, "worker0", computation_amount, 1, cpu_speed * 2);
+  }
+
+  MSG_process_sleep(1000);
+}
+
+
+static void test_two_tasks(msg_host_t hostA, msg_host_t hostB)
+{
+  const double cpu_speed = MSG_get_host_speed(hostA);
+  xbt_assert(cpu_speed == MSG_get_host_speed(hostB));
+  const double computation_amount = cpu_speed * 10;
+  const char *hostA_name = MSG_host_get_name(hostA);
+  const char *hostB_name = MSG_host_get_name(hostB);
+
+  {
+    XBT_INFO("### Test: no bound for Task1@%s, no bound for Task2@%s", hostA_name, hostB_name);
+    launch_worker(hostA, "worker0", computation_amount, 0, 0);
+    launch_worker(hostB, "worker1", computation_amount, 0, 0);
+  }
+
+  MSG_process_sleep(1000);
+
+  {
+    XBT_INFO("### Test: 0 for Task1@%s, 0 for Task2@%s (i.e., unlimited)", hostA_name, hostB_name);
+    launch_worker(hostA, "worker0", computation_amount, 1, 0);
+    launch_worker(hostB, "worker1", computation_amount, 1, 0);
+  }
+
+  MSG_process_sleep(1000);
+
+  {
+    XBT_INFO("### Test: 50%% for Task1@%s, 50%% for Task2@%s", hostA_name, hostB_name);
+    launch_worker(hostA, "worker0", computation_amount, 1, cpu_speed / 2);
+    launch_worker(hostB, "worker1", computation_amount, 1, cpu_speed / 2);
+  }
+
+  MSG_process_sleep(1000);
+
+  {
+    XBT_INFO("### Test: 25%% for Task1@%s, 25%% for Task2@%s", hostA_name, hostB_name);
+    launch_worker(hostA, "worker0", computation_amount, 1, cpu_speed / 4);
+    launch_worker(hostB, "worker1", computation_amount, 1, cpu_speed / 4);
+  }
+
+  MSG_process_sleep(1000);
+
+  {
+    XBT_INFO("### Test: 75%% for Task1@%s, 100%% for Task2@%s", hostA_name, hostB_name);
+    launch_worker(hostA, "worker0", computation_amount, 1, cpu_speed * 0.75);
+    launch_worker(hostB, "worker1", computation_amount, 1, cpu_speed);
+  }
+
+  MSG_process_sleep(1000);
+
+  {
+    XBT_INFO("### Test: no bound for Task1@%s, 25%% for Task2@%s", hostA_name, hostB_name);
+    launch_worker(hostA, "worker0", computation_amount, 0, 0);
+    launch_worker(hostB, "worker1", computation_amount, 1, cpu_speed / 4);
+  }
+
+  MSG_process_sleep(1000);
+
+  {
+    XBT_INFO("### Test: 75%% for Task1@%s, 25%% for Task2@%s", hostA_name, hostB_name);
+    launch_worker(hostA, "worker0", computation_amount, 1, cpu_speed * 0.75);
+    launch_worker(hostB, "worker1", computation_amount, 1, cpu_speed / 4);
+  }
+
+  MSG_process_sleep(1000);
+}
+
+static int master_main(int argc, char *argv[])
+{
+  xbt_dynar_t hosts_dynar = MSG_hosts_as_dynar();
+  msg_host_t pm0 = xbt_dynar_get_as(hosts_dynar, 0, msg_host_t);
+
+
+  {
+    XBT_INFO("# 1. Put a single task on a PM. ");
+    test_one_task(pm0);
+    XBT_INFO(" ");
+
+
+    XBT_INFO("# 2. Put two tasks on a PM.");
+    test_two_tasks(pm0, pm0);
+    XBT_INFO(" ");
+  }
+
+
+  {
+    msg_host_t vm0 = MSG_vm_create_core(pm0, "VM0");
+    MSG_vm_start(vm0);
+
+    XBT_INFO("# 3. Put a single task on a VM. ");
+    test_one_task(vm0);
+    XBT_INFO(" ");
+
+    XBT_INFO("# 4. Put two tasks on a VM.");
+    test_two_tasks(vm0, vm0);
+    XBT_INFO(" ");
+
+
+    MSG_vm_destroy(vm0);
+  }
+
+
+  {
+    msg_host_t vm0 = MSG_vm_create_core(pm0, "VM0");
+    MSG_vm_start(vm0);
+
+    XBT_INFO("# 6. Put a task on a PM and a task on a VM.");
+    test_two_tasks(pm0, vm0);
+    XBT_INFO(" ");
+
+
+    MSG_vm_destroy(vm0);
+  }
+
+
+  {
+    msg_host_t vm0 = MSG_vm_create_core(pm0, "VM0");
+    const double cpu_speed = MSG_get_host_speed(pm0);
+    MSG_vm_set_bound(vm0, cpu_speed / 10);
+    MSG_vm_start(vm0);
+
+    XBT_INFO("# 7. Put a single task on the VM capped by 10%%.");
+    test_one_task(vm0);
+    XBT_INFO(" ");
+
+    XBT_INFO("# 8. Put two tasks on the VM capped by 10%%.");
+    test_two_tasks(vm0, vm0);
+    XBT_INFO(" ");
+
+    XBT_INFO("# 9. Put a task on a PM and a task on the VM capped by 10%%.");
+    test_two_tasks(pm0, vm0);
+    XBT_INFO(" ");
+
+    MSG_vm_destroy(vm0);
+  }
+
+
+  XBT_INFO("# 10. Change a bound dynamically.");
+  test_dynamic_change();
+
+  return 0;
+}
+
+static void launch_master(msg_host_t host)
+{
+  const char *pr_name = "master_";
+  char **argv = xbt_new(char *, 2);
+  argv[0] = xbt_strdup(pr_name);
+  argv[1] = NULL;
+
+  MSG_process_create_with_arguments(pr_name, master_main, NULL, host, 1, argv);
+}
+
+int main(int argc, char *argv[])
+{
+  /* Get the arguments */
+  MSG_init(&argc, argv);
+
+  /* load the platform file */
+  if (argc != 2) {
+    printf("Usage: %s example/msg/cloud/simple_plat.xml\n", argv[0]);
+    return 1;
+  }
+
+  MSG_create_environment(argv[1]);
+
+  xbt_dynar_t hosts_dynar = MSG_hosts_as_dynar();
+  msg_host_t pm0 = xbt_dynar_get_as(hosts_dynar, 0, msg_host_t);
+  launch_master(pm0);
+
+  int res = MSG_main();
+  XBT_INFO("Bye (simulation time %g)", MSG_get_clock());
+
+
+  return !(res == MSG_OK);
+}
index e1527eb..830739a 100644 (file)
@@ -4,7 +4,7 @@
  * under the terms of the license (GNU LGPL) which comes with this package. */
 
 #include <stdio.h>
-#include "msg/msg.h"            /* Yeah! If you want to use msg, you need to include msg/msg.h */
+#include "msg/msg.h"
 #include "xbt/sysdep.h"         /* calloc, printf */
 
 /* Create a log channel to have nice outputs. */
@@ -15,217 +15,246 @@ XBT_LOG_NEW_DEFAULT_CATEGORY(msg_test,
 
 /** @addtogroup MSG_examples
  * 
- *  - <b>cloud/masterslave_virtual_machines.c: Master/slaves
- *    example, à la cloud</b>. The classical example revisited to demonstrate the use of virtual machines.
+ *  - <b>cloud/masterslave_virtual_machines.c: Master/workers
+ *    example on a cloud</b>. The classical example revisited to demonstrate the use of virtual machines.
  */
 
-double task_comp_size = 10000000;
-double task_comm_size = 10000000;
+const double task_comp_size = 10000000;
+const double task_comm_size = 10000000;
 
 
-int master(int argc, char *argv[]);
-int slave_fun(int argc, char *argv[]);
+int master_fun(int argc, char *argv[]);
+int worker_fun(int argc, char *argv[]);
 
-static void work_batch(int slaves_count) {
+
+static void work_batch(int workers_count)
+{
   int i;
-  for (i = 0; i < slaves_count; i++) {
-    char taskname_buffer[64];
-    char mailbox_buffer[64];
+  for (i = 0; i < workers_count; i++) {
+    char *tname = bprintf("Task%02d", i);
+    char *mbox =  bprintf("MBOX:WRK%02d", i);
+
+    msg_task_t task = MSG_task_create(tname, task_comp_size, task_comm_size, NULL);
 
-    sprintf(taskname_buffer, "Task_%d", i);
-    sprintf(mailbox_buffer,"Slave_%d",i);
+    XBT_INFO("send task(%s) to mailbox(%s)", tname, mbox);
+    MSG_task_send(task, mbox);
 
-    XBT_INFO("Sending \"%s\" to \"%s\"",taskname_buffer,mailbox_buffer);
-    MSG_task_send(MSG_task_create(taskname_buffer, task_comp_size, task_comm_size,NULL),
-        mailbox_buffer);
+    free(tname);
+    free(mbox);
   }
 }
 
-int master(int argc, char *argv[]) {
-  int slaves_count = 10;
-  msg_host_t *slaves = xbt_new(msg_host_t,10);
-
+int master_fun(int argc, char *argv[])
+{
   msg_vm_t vm;
   unsigned int i;
+  int workers_count = argc - 1;
 
-  /* Retrive the hostnames constituting our playground today */
-  for (i = 1; i < argc; i++) {
-    slaves[i - 1] = MSG_get_host_by_name(argv[i]);
-    xbt_assert(slaves[i - 1] != NULL, "Cannot use inexistent host %s", argv[i]);
-  }
+  msg_host_t *pms = xbt_new(msg_host_t, workers_count);
+  xbt_dynar_t vms = xbt_dynar_new(sizeof(msg_vm_t), NULL);
 
-  /* Launch the sub processes: one VM per host, with one process inside each */
+  /* Retrieve the PMs that will launch worker processes. */
+  for (i = 1; i < argc; i++)
+    pms[i - 1] = MSG_get_host_by_name(argv[i]);
 
-  for (i=0;i<slaves_count;i++) {
-    char slavename[64];
-    sprintf(slavename,"Slave %d",i);
-    char**argv=xbt_new(char*,3);
-    argv[0] = xbt_strdup(slavename);
-    argv[1] = bprintf("%d",i);
-    argv[2] = NULL;
 
-    char vmName[64];
-    snprintf(vmName, 64, "vm_%d", i);
+  /* Launch VMs and worker processes. One VM per PM, and one worker process per VM. */
 
-    msg_vm_t vm = MSG_vm_start(slaves[i],vmName,2);
-    MSG_vm_bind(vm, MSG_process_create_with_arguments(slavename,slave_fun,NULL,slaves[i],2,argv));
-  }
+  XBT_INFO("Launch %d VMs", workers_count);
+  for (i=0; i< workers_count; i++) {
+    char *vm_name = bprintf("VM%02d", i);
+    char *pr_name = bprintf("WRK%02d", i);
+    char *mbox = bprintf("MBOX:WRK%02d", i);
 
+    char **wrk_argv = xbt_new(char*, 3);
+    wrk_argv[0] = pr_name;
+    wrk_argv[1] = mbox;
+    wrk_argv[2] = NULL;
 
-  xbt_dynar_t vms = MSG_vms_as_dynar();
-  XBT_INFO("Launched %ld VMs", xbt_dynar_length(vms));
+    XBT_INFO("create %s", vm_name);
+    msg_vm_t vm = MSG_vm_create_core(pms[i], vm_name);
+
+    s_ws_params_t params;
+    memset(&params, 0, sizeof(params));
+    params.ramsize = 1L * 1024 * 1024 * 1024; // 1Gbytes
+    MSG_host_set_params(vm, &params);
+
+    MSG_vm_start(vm);
+    xbt_dynar_push(vms, &vm);
+
+    XBT_INFO("put %s on %s", pr_name, vm_name);
+    MSG_process_create_with_arguments(pr_name, worker_fun, NULL, vm, 2, wrk_argv);
+  }
 
-  /* Send a bunch of work to every one */
-  XBT_INFO("Send a first batch of work to every one");
-  work_batch(slaves_count);
 
-  XBT_INFO("Now suspend all VMs, just for fun");
+  /* Send a bunch of work to every one */
+  XBT_INFO("Send a task to %d worker process", workers_count);
+  work_batch(workers_count);
 
-  xbt_dynar_foreach(vms,i,vm) {
+  XBT_INFO("Suspend all VMs");
+  xbt_dynar_foreach(vms, i, vm) {
+    const char *vm_name = MSG_host_get_name(vm);
+    XBT_INFO("suspend %s", vm_name);
     MSG_vm_suspend(vm);
   }
 
   XBT_INFO("Wait a while");
   MSG_process_sleep(2);
 
-  XBT_INFO("Enough. Let's resume everybody.");
-  xbt_dynar_foreach(vms,i,vm) {
+  XBT_INFO("Resume all VMs");
+  xbt_dynar_foreach(vms, i, vm) {
     MSG_vm_resume(vm);
   }
+
+
   XBT_INFO("Sleep long enough for everyone to be done with previous batch of work");
-  MSG_process_sleep(1000-MSG_get_clock());
+  MSG_process_sleep(1000 - MSG_get_clock());
 
   XBT_INFO("Add one more process per VM");
-  xbt_dynar_foreach(vms,i,vm) {
-    msg_vm_t vm = xbt_dynar_get_as(vms,i,msg_vm_t);
-    char slavename[64];
-    sprintf(slavename,"Slave %ld",i+xbt_dynar_length(vms));
-    char**argv=xbt_new(char*,3);
-    argv[0] = xbt_strdup(slavename);
-    argv[1] = bprintf("%ld",i+xbt_dynar_length(vms));
-    argv[2] = NULL;
-    MSG_vm_bind(vm, MSG_process_create_with_arguments(slavename,slave_fun,NULL,slaves[i],2,argv));
+  xbt_dynar_foreach(vms, i, vm) {
+    unsigned int index = i + xbt_dynar_length(vms);
+    char *vm_name = bprintf("VM%02d", i);
+    char *pr_name = bprintf("WRK%02d", index);
+    char *mbox = bprintf("MBOX:WRK%02d", index);
+
+    char **wrk_argv = xbt_new(char*, 3);
+    wrk_argv[0] = pr_name;
+    wrk_argv[1] = mbox;
+    wrk_argv[2] = NULL;
+
+    XBT_INFO("put %s on %s", pr_name, vm_name);
+    MSG_process_create_with_arguments(pr_name, worker_fun, NULL, vm, 2, wrk_argv);
   }
 
-  XBT_INFO("Reboot all the VMs");
-  xbt_dynar_foreach(vms,i,vm) {
-    MSG_vm_reboot(vm);
-  }
-
-  work_batch(slaves_count*2);
+  XBT_INFO("Send a task to %d worker process", workers_count * 2);
+  work_batch(workers_count * 2);
 
-  XBT_INFO("Migrate everyone to the second host.");
-  xbt_dynar_foreach(vms,i,vm) {
-    MSG_vm_migrate(vm,slaves[1]);
+  XBT_INFO("Migrate all VMs to PM(%s)", MSG_host_get_name(pms[1]));
+  xbt_dynar_foreach(vms, i, vm) {
+    MSG_vm_migrate(vm, pms[1]);
   }
-  XBT_INFO("Suspend everyone, move them to the third host, and resume them.");
-  xbt_dynar_foreach(vms,i,vm) {
-    MSG_vm_suspend(vm);
-    MSG_vm_migrate(vm,slaves[2]);
-    MSG_vm_resume(vm);
+
+  /* Migration with default policy is called (i.e. live migration with pre-copy strategy) */
+  /* If you want to use other policy such as post-copy or cold migration, you should add a third parameter that defines the policy */
+  XBT_INFO("Migrate all VMs to PM(%s)", MSG_host_get_name(pms[2]));
+  xbt_dynar_foreach(vms, i, vm) {
+    // MSG_vm_suspend(vm);
+    MSG_vm_migrate(vm, pms[2]);
+    // MSG_vm_resume(vm);
   }
 
 
-  XBT_INFO("Let's shut down the simulation. 10 first processes will be shut down cleanly while the second half will forcefully get killed");
-  for (i = 0; i < slaves_count; i++) {
-    char mailbox_buffer[64];
-    sprintf(mailbox_buffer,"Slave_%d",i);
+  XBT_INFO("Shutdown the half of worker processes gracefuly. The remaining half will be forcibly killed");
+  for (i = 0; i < workers_count; i++) {
+    char mbox[64];
+    sprintf(mbox, "MBOX:WRK%02d", i);
     msg_task_t finalize = MSG_task_create("finalize", 0, 0, 0);
-    MSG_task_send(finalize, mailbox_buffer);
+    MSG_task_send(finalize, mbox);
   }
 
   XBT_INFO("Wait a while before effective shutdown.");
   MSG_process_sleep(2);
 
-  xbt_dynar_foreach(vms,i,vm) {
+
+  XBT_INFO("Shutdown and destroy all the VMs. The remaining worker processes will be forcibly killed.");
+  xbt_dynar_foreach(vms, i, vm) {
+    XBT_INFO("shutdown %s", MSG_host_get_name(vm));
     MSG_vm_shutdown(vm);
+    XBT_INFO("destroy %s", MSG_host_get_name(vm));
     MSG_vm_destroy(vm);
   }
 
   XBT_INFO("Goodbye now!");
-  free(slaves);
+  free(pms);
   xbt_dynar_free(&vms);
+
   return 0;
-}                               /* end_of_master */
+}
 
 /** Receiver function  */
-int slave_fun(int argc, char *argv[])
+int worker_fun(int argc, char *argv[])
 {
-  char mailbox_name[128];
-  msg_task_t task = NULL;
-  _XBT_GNUC_UNUSED int res;
-  /* since the slaves will move around, use slave_%d as mailbox names instead of hostnames */
-  xbt_assert(argc>=2, "slave processes need to be given their rank as parameter");
-  sprintf(mailbox_name,"Slave_%s",argv[1]);
-  XBT_INFO("Slave listenning on %s",argv[1]);
-  while (1) {
-    res = MSG_task_receive(&(task),mailbox_name);
-    xbt_assert(res == MSG_OK, "MSG_task_get failed");
-
-    XBT_INFO("Received \"%s\" from mailbox %s", MSG_task_get_name(task),mailbox_name);
+  xbt_assert(argc == 2, "need mbox in arguments");
+
+  char *mbox = argv[1];
+  const char *pr_name = MSG_process_get_name(MSG_process_self());
+  XBT_INFO("%s is listenning on mailbox(%s)", pr_name, mbox);
+
+  for (;;) {
+    msg_task_t task = NULL;
+
+    msg_error_t res = MSG_task_receive(&task, mbox);
+    if (res != MSG_OK) {
+      XBT_CRITICAL("MSG_task_get failed");
+      DIE_IMPOSSIBLE;
+    }
+
+    XBT_INFO("%s received task(%s) from mailbox(%s)",
+        pr_name, MSG_task_get_name(task), mbox);
+
     if (!strcmp(MSG_task_get_name(task), "finalize")) {
       MSG_task_destroy(task);
       break;
     }
 
     MSG_task_execute(task);
-    XBT_INFO("\"%s\" done", MSG_task_get_name(task));
+    XBT_INFO("%s executed task(%s)", pr_name, MSG_task_get_name(task));
     MSG_task_destroy(task);
-    task = NULL;
   }
 
   return 0;
-}                               /* end_of_slave */
+}
+
 
 /** Main function */
 int main(int argc, char *argv[])
 {
-  msg_error_t res = MSG_OK;
-  xbt_dynar_t hosts_dynar;
-  msg_host_t*hosts= xbt_new(msg_host_t,10);
-  char**hostnames= xbt_new(char*,10);
-  char**masterargv=xbt_new(char*,12);
-  int i;
+  const int nb_hosts = 3;
 
-  /* Get the arguments */
   MSG_init(&argc, argv);
-  if (argc < 2) {
-    printf("Usage: %s platform_file\n", argv[0]);
-    printf("example: %s msg_platform.xml\n", argv[0]);
-    exit(1);
-  } if (argc>2) {
-    printf("Usage: %s platform_file\n", argv[0]);
-    printf("Other parameters (such as the deployment file) are ignored.");
+  if (argc != 2) {
+    printf("Usage: %s example/msg/msg_platform.xml\n", argv[0]);
+    return 1;
   }
 
-  /* load the platform file */
+  /* Load the platform file */
   MSG_create_environment(argv[1]);
-  /* Retrieve the 10 first hosts of the platform file */
-  hosts_dynar = MSG_hosts_as_dynar();
-  xbt_assert(xbt_dynar_length(hosts_dynar)>10,
-      "I need at least 10 hosts in the platform file, but %s contains only %ld hosts_dynar.",
-      argv[1],xbt_dynar_length(hosts_dynar));
-  for (i=0;i<10;i++) {
-    hosts[i] = xbt_dynar_get_as(hosts_dynar,i,msg_host_t);
-    hostnames[i] = xbt_strdup(MSG_host_get_name(hosts[i]));
+
+  /* Retrieve hosts from the platform file */
+  xbt_dynar_t hosts_dynar = MSG_hosts_as_dynar();
+
+  if (xbt_dynar_length(hosts_dynar) <= nb_hosts) {
+    XBT_CRITICAL("need %d hosts", nb_hosts);
+    return 1;
   }
-  masterargv[0]=xbt_strdup("master");
-  for (i=1;i<11;i++) {
-    masterargv[i] = xbt_strdup(MSG_host_get_name(hosts[i-1]));
+
+  msg_host_t master_pm = NULL;
+  char **master_argv = xbt_new(char *, 12);
+  master_argv[0] = xbt_strdup("master");
+  master_argv[11] = NULL;
+
+  unsigned int i;
+  msg_host_t host;
+  xbt_dynar_foreach(hosts_dynar, i, host) {
+    if (i == 0) {
+      master_pm = host;
+      continue;
+    }
+
+    master_argv[i] = xbt_strdup(MSG_host_get_name(host));
+
+    if (i == nb_hosts)
+      break;
+  }
+
+  msg_error_t res = 1;
+  if (master_pm!=NULL){
+    MSG_process_create_with_arguments("master", master_fun, NULL, master_pm, nb_hosts + 1, master_argv);
+
+    res = MSG_main();
+    XBT_INFO("Bye (simulation time %g)", MSG_get_clock());
   }
-  masterargv[11]=NULL;
-  MSG_process_create_with_arguments("master",master,NULL,hosts[0],11,masterargv);
-  res = MSG_main();
-  XBT_INFO("Simulation time %g", MSG_get_clock());
-
-  free(hosts);
-  for (i=0;i<10;i++) 
-     free(hostnames[i]);
-  free(hostnames);
   xbt_dynar_free(&hosts_dynar);
 
-  if (res == MSG_OK)
-    return 0;
-  else
-    return 1;
-}                               /* end_of_main */
+  return !(res == MSG_OK);
+}
diff --git a/examples/msg/cloud/migrate_vm.c b/examples/msg/cloud/migrate_vm.c
new file mode 100644 (file)
index 0000000..46a8725
--- /dev/null
@@ -0,0 +1,163 @@
+/* Copyright (c) 2007-2012. 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 <stdio.h>
+#include "msg/msg.h"
+#include "xbt/sysdep.h"         /* calloc, printf */
+
+/* Create a log channel to have nice outputs. */
+#include "xbt/log.h"
+#include "xbt/asserts.h"
+XBT_LOG_NEW_DEFAULT_CATEGORY(msg_test,
+                             "Messages specific for this msg example");
+
+
+static void vm_migrate(msg_vm_t vm, msg_host_t dst_pm)
+{
+  msg_host_t src_pm = MSG_vm_get_pm(vm);
+  double mig_sta = MSG_get_clock();
+  MSG_vm_migrate(vm, dst_pm);
+  double mig_end = MSG_get_clock();
+
+  XBT_INFO("%s migrated: %s->%s in %g s", MSG_vm_get_name(vm),
+                 MSG_host_get_name(src_pm), MSG_host_get_name(dst_pm),
+                 mig_end - mig_sta);
+}
+
+static int migration_worker_main(int argc, char *argv[])
+{
+  xbt_assert(argc == 3);
+  char *vm_name = argv[1];
+  char *dst_pm_name = argv[2];
+
+  msg_vm_t vm = MSG_get_host_by_name(vm_name);
+  msg_host_t dst_pm = MSG_get_host_by_name(dst_pm_name);
+
+  vm_migrate(vm, dst_pm);
+
+  return 0;
+}
+
+static void vm_migrate_async(msg_vm_t vm, msg_host_t dst_pm)
+{
+  const char *vm_name = MSG_vm_get_name(vm);
+  const char *dst_pm_name = MSG_host_get_name(dst_pm);
+  msg_host_t host = MSG_host_self();
+
+  const char *pr_name = "mig_wrk";
+  char **argv = xbt_new(char *, 4);
+  argv[0] = xbt_strdup(pr_name);
+  argv[1] = xbt_strdup(vm_name);
+  argv[2] = xbt_strdup(dst_pm_name);
+  argv[3] = NULL;
+
+  MSG_process_create_with_arguments(pr_name, migration_worker_main, NULL, host, 3, argv);
+}
+
+static int master_main(int argc, char *argv[])
+{
+  xbt_dynar_t hosts_dynar = MSG_hosts_as_dynar();
+  msg_host_t pm0 = xbt_dynar_get_as(hosts_dynar, 0, msg_host_t);
+  msg_host_t pm1 = xbt_dynar_get_as(hosts_dynar, 1, msg_host_t);
+  msg_host_t pm2 = xbt_dynar_get_as(hosts_dynar, 2, msg_host_t);
+  msg_vm_t vm0, vm1;
+  s_ws_params_t params;
+  memset(&params, 0, sizeof(params));
+
+
+
+  vm0 = MSG_vm_create_core(pm0, "VM0");
+  params.ramsize = 1L * 1000 * 1000 * 1000; // 1Gbytes
+  MSG_host_set_params(vm0, &params);
+  MSG_vm_start(vm0);
+
+  XBT_INFO("Test: Migrate a VM with %ld Mbytes RAM", params.ramsize / 1000 / 1000);
+  vm_migrate(vm0, pm1);
+
+  MSG_vm_destroy(vm0);
+
+
+
+  vm0 = MSG_vm_create_core(pm0, "VM0");
+  params.ramsize = 1L * 1000 * 1000 * 100; // 100Mbytes
+  MSG_host_set_params(vm0, &params);
+  MSG_vm_start(vm0);
+
+  XBT_INFO("Test: Migrate a VM with %ld Mbytes RAM", params.ramsize / 1000 / 1000);
+  vm_migrate(vm0, pm1);
+
+  MSG_vm_destroy(vm0);
+
+
+
+  vm0 = MSG_vm_create_core(pm0, "VM0");
+  vm1 = MSG_vm_create_core(pm0, "VM1");
+
+  params.ramsize = 1L * 1000 * 1000 * 1000; // 1Gbytes
+  MSG_host_set_params(vm0, &params);
+  MSG_host_set_params(vm1, &params);
+  MSG_vm_start(vm0);
+  MSG_vm_start(vm1);
+
+  XBT_INFO("Test: Migrate two VMs at once from PM0 to PM1");
+  vm_migrate_async(vm0, pm1);
+  vm_migrate_async(vm1, pm1);
+  MSG_process_sleep(10000);
+
+  MSG_vm_destroy(vm0);
+  MSG_vm_destroy(vm1);
+
+
+
+  vm0 = MSG_vm_create_core(pm0, "VM0");
+  vm1 = MSG_vm_create_core(pm0, "VM1");
+
+  params.ramsize = 1L * 1000 * 1000 * 1000; // 1Gbytes
+  MSG_host_set_params(vm0, &params);
+  MSG_host_set_params(vm1, &params);
+  MSG_vm_start(vm0);
+  MSG_vm_start(vm1);
+
+  XBT_INFO("Test: Migrate two VMs at once to different PMs");
+  vm_migrate_async(vm0, pm1);
+  vm_migrate_async(vm1, pm2);
+  MSG_process_sleep(10000);
+
+  MSG_vm_destroy(vm0);
+  MSG_vm_destroy(vm1);
+
+
+  return 0;
+}
+
+static void launch_master(msg_host_t host)
+{
+  const char *pr_name = "master_";
+  char **argv = xbt_new(char *, 2);
+  argv[0] = xbt_strdup(pr_name);
+  argv[1] = NULL;
+
+  MSG_process_create_with_arguments(pr_name, master_main, NULL, host, 1, argv);
+}
+
+
+int main(int argc, char *argv[])
+{
+  /* Get the arguments */
+  MSG_init(&argc, argv);
+
+  /* load the platform file */
+  MSG_create_environment(argv[1]);
+
+  xbt_dynar_t hosts_dynar = MSG_hosts_as_dynar();
+  msg_host_t pm0 = xbt_dynar_get_as(hosts_dynar, 0, msg_host_t);
+  launch_master(pm0);
+
+  int res = MSG_main();
+  XBT_INFO("Bye (simulation time %g)", MSG_get_clock());
+
+
+  return !(res == MSG_OK);
+}
diff --git a/examples/msg/cloud/simple_plat.xml b/examples/msg/cloud/simple_plat.xml
new file mode 100644 (file)
index 0000000..9bc4478
--- /dev/null
@@ -0,0 +1,24 @@
+<?xml version='1.0'?>
+<!DOCTYPE platform SYSTEM "http://simgrid.gforge.inria.fr/simgrid.dtd">
+<platform version="3">
+       <AS id="siteA" routing="Full">
+               <host id="PM0" power="1E8"/>
+               <host id="PM1" power="1E8"/>
+               <host id="PM2" power="1E8"/>
+
+               <!-- <link id="link1" bandwidth="1E6" latency="1E-2" /> -->
+               <link id="link1" bandwidth="12500000" latency="1E-2" />
+
+               <route src="PM0" dst="PM1">
+                       <link_ctn id="link1"/>
+               </route>
+
+               <route src="PM0" dst="PM2">
+                       <link_ctn id="link1"/>
+               </route>
+
+               <route src="PM1" dst="PM2">
+                       <link_ctn id="link1"/>
+               </route>
+       </AS>
+</platform>
diff --git a/examples/msg/cloud/simple_vm.c b/examples/msg/cloud/simple_vm.c
new file mode 100644 (file)
index 0000000..e61c01c
--- /dev/null
@@ -0,0 +1,297 @@
+/* Copyright (c) 2007-2012. 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 <stdio.h>
+#include "msg/msg.h"
+#include "xbt/sysdep.h"         /* calloc, printf */
+
+/* Create a log channel to have nice outputs. */
+#include "xbt/log.h"
+#include "xbt/asserts.h"
+XBT_LOG_NEW_DEFAULT_CATEGORY(msg_test,
+                             "Messages specific for this msg example");
+
+
+static int computation_fun(int argc, char *argv[])
+{
+  const char *pr_name = MSG_process_get_name(MSG_process_self());
+  const char *host_name = MSG_host_get_name(MSG_host_self());
+
+  msg_task_t task = MSG_task_create("Task", 1000000, 1000000, NULL);
+
+  double clock_sta = MSG_get_clock();
+  MSG_task_execute(task);
+  double clock_end = MSG_get_clock();
+
+  XBT_INFO("%s:%s task executed %g", host_name, pr_name, clock_end - clock_sta);
+
+  MSG_task_destroy(task);
+
+  return 0;
+}
+
+static void launch_computation_worker(msg_host_t host)
+{
+  const char *pr_name = "compute";
+  char **argv = xbt_new(char *, 2);
+  argv[0] = xbt_strdup(pr_name);
+  argv[1] = NULL;
+
+  MSG_process_create_with_arguments(pr_name, computation_fun, NULL, host, 1, argv);
+}
+
+struct task_priv {
+  msg_host_t tx_host;
+  msg_process_t tx_proc;
+  double clock_sta;
+};
+
+static int communication_tx_fun(int argc, char *argv[])
+{
+  xbt_assert(argc == 2);
+  const char *mbox = argv[1];
+
+  msg_task_t task = MSG_task_create("Task", 1000000, 1000000, NULL);
+
+  struct task_priv *priv = xbt_new(struct task_priv, 1);
+  priv->tx_proc = MSG_process_self();
+  priv->tx_host = MSG_host_self();
+  priv->clock_sta = MSG_get_clock();
+
+  MSG_task_set_data(task, priv);
+
+  MSG_task_send(task, mbox);
+
+  return 0;
+}
+
+static int communication_rx_fun(int argc, char *argv[])
+{
+  const char *pr_name = MSG_process_get_name(MSG_process_self());
+  const char *host_name = MSG_host_get_name(MSG_host_self());
+  xbt_assert(argc == 2);
+  const char *mbox = argv[1];
+
+  msg_task_t task = NULL;
+  MSG_task_recv(&task, mbox);
+
+  struct task_priv *priv = MSG_task_get_data(task);
+  double clock_end = MSG_get_clock();
+
+  XBT_INFO("%s:%s to %s:%s => %g sec",
+      MSG_host_get_name(priv->tx_host),
+      MSG_process_get_name(priv->tx_proc),
+      host_name, pr_name, clock_end - priv->clock_sta);
+
+  MSG_task_destroy(task);
+
+  return 0;
+}
+
+static void launch_communication_worker(msg_host_t tx_host, msg_host_t rx_host)
+{
+  char *mbox = bprintf("MBOX:%s-%s",
+      MSG_host_get_name(tx_host),
+      MSG_host_get_name(rx_host));
+  char **argv = NULL;
+  
+  const char *pr_name_tx =  "comm_tx";
+  argv = xbt_new(char *, 3);
+  argv[0] = xbt_strdup(pr_name_tx);
+  argv[1] = xbt_strdup(mbox);
+  argv[2] = NULL;
+
+  MSG_process_create_with_arguments(pr_name_tx, communication_tx_fun, NULL, tx_host, 2, argv);
+
+  const char *pr_name_rx =  "comm_rx";  
+  argv = xbt_new(char *, 3);
+  argv[0] = xbt_strdup(pr_name_rx);
+  argv[1] = xbt_strdup(mbox);
+  argv[2] = NULL;
+
+  MSG_process_create_with_arguments(pr_name_rx, communication_rx_fun, NULL, rx_host, 2, argv);
+
+  xbt_free(mbox);
+}
+
+
+static int master_main(int argc, char *argv[])
+{
+  xbt_dynar_t hosts_dynar = MSG_hosts_as_dynar();
+  msg_host_t pm0 = xbt_dynar_get_as(hosts_dynar, 0, msg_host_t);
+  msg_host_t pm1 = xbt_dynar_get_as(hosts_dynar, 1, msg_host_t);
+  msg_host_t pm2 = xbt_dynar_get_as(hosts_dynar, 2, msg_host_t);
+  msg_vm_t vm0, vm1;
+
+
+  XBT_INFO("## Test 1 (started): check computation on normal PMs");
+
+  XBT_INFO("### Put a task on a PM");
+  launch_computation_worker(pm0);
+  MSG_process_sleep(2);
+
+  XBT_INFO("### Put two tasks on a PM");
+  launch_computation_worker(pm0);
+  launch_computation_worker(pm0);
+  MSG_process_sleep(2);
+
+  XBT_INFO("### Put a task on each PM");
+  launch_computation_worker(pm0);
+  launch_computation_worker(pm1);
+  MSG_process_sleep(2);
+
+  XBT_INFO("## Test 1 (ended)");
+
+
+  XBT_INFO("## Test 2 (started): check impact of running a task inside a VM (there is no degradation for the moment)");
+
+  XBT_INFO("### Put a VM on a PM, and put a task to the VM");
+  vm0 = MSG_vm_create_core(pm0, "VM0");
+  MSG_vm_start(vm0);
+  launch_computation_worker(vm0);
+  MSG_process_sleep(2);
+  MSG_vm_destroy(vm0);
+
+  XBT_INFO("## Test 2 (ended)");
+
+  
+  XBT_INFO("## Test 3 (started): check impact of running a task collocated with a VM (there is no VM noise for the moment)");
+
+  XBT_INFO("### Put a VM on a PM, and put a task to the PM");
+  vm0 = MSG_vm_create_core(pm0, "VM0");
+  MSG_vm_start(vm0);
+  launch_computation_worker(pm0);
+  MSG_process_sleep(2);
+  MSG_vm_destroy(vm0);
+
+  XBT_INFO("## Test 3 (ended)");
+
+
+  XBT_INFO("## Test 4 (started): compare the cost of running two tasks inside two different VMs collocated or not (for the moment, there is no degradation for the VMs. Hence, the time should be equals to the time of test 1");
+
+  XBT_INFO("### Put two VMs on a PM, and put a task to each VM");
+  vm0 = MSG_vm_create_core(pm0, "VM0");
+  vm1 = MSG_vm_create_core(pm0, "VM1");
+  MSG_vm_start(vm0);
+  MSG_vm_start(vm1);
+  launch_computation_worker(vm0);
+  launch_computation_worker(vm1);
+  MSG_process_sleep(2);
+  MSG_vm_destroy(vm0);
+  MSG_vm_destroy(vm1);
+
+  XBT_INFO("### Put a VM on each PM, and put a task to each VM");
+  vm0 = MSG_vm_create_core(pm0, "VM0");
+  vm1 = MSG_vm_create_core(pm1, "VM1");
+  MSG_vm_start(vm0);
+  MSG_vm_start(vm1);
+  launch_computation_worker(vm0);
+  launch_computation_worker(vm1);
+  MSG_process_sleep(2);
+  MSG_vm_destroy(vm0);
+  MSG_vm_destroy(vm1);
+  XBT_INFO("## Test 4 (ended)");
+
+  
+  XBT_INFO("## Test 5  (started): Analyse network impact");
+  XBT_INFO("### Make a connection between PM0 and PM1");
+  launch_communication_worker(pm0, pm1);
+  MSG_process_sleep(5);
+
+  XBT_INFO("### Make two connection between PM0 and PM1");
+  launch_communication_worker(pm0, pm1);
+  launch_communication_worker(pm0, pm1);
+  MSG_process_sleep(5);
+
+  XBT_INFO("### Make a connection between PM0 and VM0@PM0");
+  vm0 = MSG_vm_create_core(pm0, "VM0");
+  MSG_vm_start(vm0);
+  launch_communication_worker(pm0, vm0);
+  MSG_process_sleep(5);
+  MSG_vm_destroy(vm0);
+
+  XBT_INFO("### Make a connection between PM0 and VM0@PM1");
+  vm0 = MSG_vm_create_core(pm1, "VM0");
+  MSG_vm_start(vm0);
+  launch_communication_worker(pm0, vm0);
+  MSG_process_sleep(5);
+  MSG_vm_destroy(vm0);
+
+  XBT_INFO("### Make two connections between PM0 and VM0@PM1");
+  vm0 = MSG_vm_create_core(pm1, "VM0");
+  MSG_vm_start(vm0);
+  launch_communication_worker(pm0, vm0);
+  launch_communication_worker(pm0, vm0);
+  MSG_process_sleep(5);
+  MSG_vm_destroy(vm0);
+
+  XBT_INFO("### Make a connection between PM0 and VM0@PM1, and also make a connection between PM0 and PM1");
+  vm0 = MSG_vm_create_core(pm1, "VM0");
+  MSG_vm_start(vm0);
+  launch_communication_worker(pm0, vm0);
+  launch_communication_worker(pm0, pm1);
+  MSG_process_sleep(5);
+  MSG_vm_destroy(vm0);
+
+  XBT_INFO("### Make a connection between VM0@PM0 and PM1@PM1, and also make a connection between VM0@PM0 and VM1@PM1");
+  vm0 = MSG_vm_create_core(pm0, "VM0");
+  vm1 = MSG_vm_create_core(pm1, "VM1");
+  MSG_vm_start(vm0);
+  MSG_vm_start(vm1);
+  launch_communication_worker(vm0, vm1);
+  launch_communication_worker(vm0, vm1);
+  MSG_process_sleep(5);
+  MSG_vm_destroy(vm0);
+  MSG_vm_destroy(vm1);
+
+  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 = MSG_vm_create_core(pm0, "VM0");
+  MSG_vm_start(vm0);
+  launch_communication_worker(vm0, pm2);
+  MSG_process_sleep(0.01);
+  MSG_vm_migrate(vm0, pm1);
+  MSG_process_sleep(0.01);
+  MSG_vm_migrate(vm0, pm0);
+  MSG_process_sleep(5);
+  MSG_vm_destroy(vm0);
+  XBT_INFO("## Test 6 (ended)");
+  
+  return 0;
+}
+
+static void launch_master(msg_host_t host)
+{
+  const char *pr_name = "master_";
+  char **argv = xbt_new(char *, 2);
+  argv[0] = xbt_strdup(pr_name);
+  argv[1] = NULL;
+
+  MSG_process_create_with_arguments(pr_name, master_main, NULL, host, 1, argv);
+}
+
+
+int main(int argc, char *argv[])
+{
+  /* Get the arguments */
+  MSG_init(&argc, argv);
+
+  /* load the platform file */
+  xbt_assert(argc == 2);
+  MSG_create_environment(argv[1]);
+
+  xbt_dynar_t hosts_dynar = MSG_hosts_as_dynar();
+  msg_host_t pm0 = xbt_dynar_get_as(hosts_dynar, 0, msg_host_t);
+  launch_master(pm0);
+
+  int res = MSG_main();
+  XBT_INFO("Bye (simulation time %g)", MSG_get_clock());
+
+
+  return !(res == MSG_OK);
+}
index 2661276..041005d 100644 (file)
@@ -47,7 +47,10 @@ typedef xbt_dictelm_t msg_host_t;
 typedef s_xbt_dictelm_t s_msg_host_t;
 
 typedef struct msg_host_priv {
-  xbt_swag_t vms;
+  int        dp_enabled;
+  xbt_dict_t dp_objs;
+  double     dp_updated_by_deleted_tasks;
+
 #ifdef MSG_USE_DEPRECATED
   msg_mailbox_t *mailboxes;     /**< the channels  */
 #endif
@@ -82,22 +85,13 @@ typedef struct msg_task {
  */
 typedef struct msg_task *msg_task_t;
 
-/* ********************************  VM ************************************* */
-typedef struct msg_vm *msg_vm_t;
-
-typedef enum {
-  msg_vm_state_suspended, msg_vm_state_running, msg_vm_state_migrating
-} e_msg_vm_state_t;
-
-typedef struct msg_vm {
-  char *name;
-  s_xbt_swag_hookup_t all_vms_hookup;
-  s_xbt_swag_hookup_t host_vms_hookup;
-  xbt_dynar_t processes;
-  e_msg_vm_state_t state;
-  msg_host_t location;
-  int coreAmount;
-} s_msg_vm_t;
+/* ******************************** VM ************************************* */
+typedef msg_host_t msg_vm_t;
+typedef msg_host_priv_t msg_vm_priv_t;
+
+static inline msg_vm_priv_t MSG_vm_priv(msg_vm_t vm){
+  return xbt_lib_get_level(vm, MSG_HOST_LEVEL);
+}
 
 /* ******************************** File ************************************ */
 typedef struct simdata_file *simdata_file_t;
index 877d3e4..0dc3be4 100644 (file)
@@ -96,13 +96,16 @@ XBT_PUBLIC(void) MSG_as_router_set_property_value(const char* asr, const char *n
 XBT_PUBLIC(msg_error_t) MSG_host_set_data(msg_host_t host, void *data);
 XBT_PUBLIC(void *) MSG_host_get_data(msg_host_t host);
 XBT_PUBLIC(const char *) MSG_host_get_name(msg_host_t host);
+XBT_PUBLIC(void) MSG_host_on(msg_host_t host);
+XBT_PUBLIC(void) MSG_host_off(msg_host_t host);
 XBT_PUBLIC(msg_host_t) MSG_host_self(void);
 XBT_PUBLIC(int) MSG_get_host_msgload(msg_host_t host);
 /* int MSG_get_msgload(void); This function lacks specification; discard it */
 XBT_PUBLIC(double) MSG_get_host_speed(msg_host_t h);
 XBT_PUBLIC(int) MSG_get_host_core(msg_host_t h);
 XBT_PUBLIC(int) MSG_host_is_avail(msg_host_t h);
-XBT_PUBLIC(void) __MSG_host_destroy(msg_host_priv_t host);
+XBT_PUBLIC(void) __MSG_host_priv_free(msg_host_priv_t priv);
+XBT_PUBLIC(void) __MSG_host_destroy(msg_host_t host);
 
 /*property handlers*/
 XBT_PUBLIC(xbt_dict_t) MSG_host_get_properties(msg_host_t host);
@@ -119,6 +122,9 @@ XBT_PUBLIC(msg_host_t) MSG_get_host_by_name(const char *name);
 XBT_PUBLIC(xbt_dynar_t) MSG_hosts_as_dynar(void);
 XBT_PUBLIC(int) MSG_get_host_number(void);
 
+XBT_PUBLIC(void) MSG_host_get_params(msg_host_t ind_pm, ws_params_t params);
+XBT_PUBLIC(void) MSG_host_set_params(msg_host_t ind_pm, ws_params_t params);
+
 /************************** Process handling *********************************/
 XBT_PUBLIC(msg_process_t) MSG_process_create(const char *name,
                                            xbt_main_func_t code,
@@ -208,6 +214,7 @@ XBT_PUBLIC(msg_error_t) MSG_task_receive_from_host_bounded(msg_task_t * task, co
 XBT_PUBLIC(msg_error_t) MSG_task_execute(msg_task_t task);
 XBT_PUBLIC(msg_error_t) MSG_parallel_task_execute(msg_task_t task);
 XBT_PUBLIC(void) MSG_task_set_priority(msg_task_t task, double priority);
+XBT_PUBLIC(void) MSG_task_set_bound(msg_task_t task, double bound);
 
 XBT_PUBLIC(msg_error_t) MSG_process_sleep(double nb_sec);
 
@@ -381,30 +388,46 @@ XBT_PUBLIC(int) MSG_sem_would_block(msg_sem_t sem);
  * Usual lack of guaranty of any kind applies here, and is even increased.
  *
  */
-/* This function should not be called directly, but rather from MSG_vm_start_from_template that does not exist yet*/
-XBT_PUBLIC(msg_vm_t) MSG_vm_start(msg_host_t location, const char *name, int coreAmount);
 
-XBT_PUBLIC(int) MSG_vm_is_suspended(msg_vm_t);
+XBT_PUBLIC(int) MSG_vm_is_created(msg_vm_t);
 XBT_PUBLIC(int) MSG_vm_is_running(msg_vm_t);
+XBT_PUBLIC(int) MSG_vm_is_migrating(msg_vm_t);
 
-XBT_PUBLIC(void) MSG_vm_bind(msg_vm_t vm, msg_process_t process);
-XBT_PUBLIC(void) MSG_vm_unbind(msg_vm_t vm, msg_process_t process); // simple wrapper over process_kill
+XBT_PUBLIC(int) MSG_vm_is_suspended(msg_vm_t);
+XBT_PUBLIC(int) MSG_vm_is_saving(msg_vm_t);
+XBT_PUBLIC(int) MSG_vm_is_saved(msg_vm_t);
+XBT_PUBLIC(int) MSG_vm_is_restoring(msg_vm_t);
 
-XBT_PUBLIC(void) MSG_vm_migrate(msg_vm_t vm, msg_host_t destination);
 
-XBT_PUBLIC(void) MSG_vm_suspend(msg_vm_t vm);
-  // \forall p in VM, MSG_process_suspend(p) // Freeze the processes
+XBT_PUBLIC(const char*) MSG_vm_get_name(msg_vm_t);
 
-XBT_PUBLIC(void) MSG_vm_resume(msg_vm_t vm);  // Simulate the fact of reading the processes from disk and resuming them
-  // \forall p in VM, MSG_process_resume(p) // unfreeze them
+// TODO add VDI later
+XBT_PUBLIC(msg_vm_t) MSG_vm_create_core(msg_host_t location, const char *name);
+XBT_PUBLIC(msg_vm_t) MSG_vm_create(msg_host_t ind_pm, const char *name,
+    int core_nb, long mem_cap, long net_cap, char *disk_path, long disk_size);
 
-XBT_PUBLIC(void) MSG_vm_shutdown(msg_vm_t vm); // killall
+XBT_PUBLIC(void) MSG_vm_destroy(msg_vm_t vm);
 
-XBT_PUBLIC(void) MSG_vm_reboot(msg_vm_t vm);
+XBT_PUBLIC(void) MSG_vm_start(msg_vm_t);
 
-XBT_PUBLIC(void) MSG_vm_destroy(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);
+
+/* Save the VM state to a disk. */
+XBT_PUBLIC(void) MSG_vm_save(msg_vm_t vm);
+XBT_PUBLIC(void) MSG_vm_restore(msg_vm_t vm);
+
+XBT_PUBLIC(msg_host_t) MSG_vm_get_pm(msg_vm_t vm);
+XBT_PUBLIC(void) MSG_vm_set_bound(msg_vm_t vm, double bound);
 
-XBT_PUBLIC(xbt_dynar_t) MSG_vms_as_dynar(void);
+/* TODO: do we need this? */
+// XBT_PUBLIC(xbt_dynar_t) MSG_vms_as_dynar(void);
 
 /*
 void* MSG_process_get_property(msg_process_t, char* key)
index 6528b4f..c0cffed 100644 (file)
@@ -41,6 +41,46 @@ typedef enum {
 } e_surf_process_on_failure_t;
 
 
+/* FIXME: Where should the VM state be defined? */
+typedef enum {
+  /* created, but not yet started */
+  SURF_VM_STATE_CREATED,
+
+  SURF_VM_STATE_RUNNING,
+  SURF_VM_STATE_MIGRATING,
+
+  /* Suspend/resume does not involve disk I/O, so we assume there is no transition states. */
+  SURF_VM_STATE_SUSPENDED,
+
+  /* Save/restore involves disk I/O, so there should be transition states. */
+  SURF_VM_STATE_SAVING,
+  SURF_VM_STATE_SAVED,
+  SURF_VM_STATE_RESTORING,
+
+} e_surf_vm_state_t;
+
+typedef struct ws_params {
+  int ncpus;
+  long ramsize;
+  int overcommit;
+
+  /* The size of other states than memory pages, which is out-of-scope of dirty
+   * page tracking. */
+  long devsize;
+  int skip_stage1;
+  int skip_stage2;
+  double max_downtime;
+
+  double dp_rate;
+  double dp_cap; /* bytes per 1 flop execution */
+
+  double xfer_cpu_overhead;
+  double dpt_cpu_overhead;
+
+  /* set migration speed */
+  double mig_speed;
+} s_ws_params_t, *ws_params_t;
+
 typedef struct tmgr_trace *tmgr_trace_t; /**< Opaque structure defining an availability trace */
 
 /** opaque structure defining a event generator for availability based on a probability distribution */
index 510bade..8254d46 100644 (file)
@@ -14,6 +14,8 @@
 #include "xbt/parmap.h"
 #include "xbt/swag.h"
 
+#include "simgrid/platf.h" // ws_params_t
+
 SG_BEGIN_DECL()
 
 /**************************** Scalar Values **********************************/
@@ -254,6 +256,8 @@ XBT_PUBLIC(smx_host_t) SIMIX_host_get_by_name(const char *name);
 XBT_PUBLIC(smx_host_t) SIMIX_host_self(void);
 XBT_PUBLIC(const char*) SIMIX_host_self_get_name(void);
 XBT_PUBLIC(const char*) SIMIX_host_get_name(smx_host_t host); /* FIXME: make private: only the name of SIMIX_host_self() should be public without request */
+XBT_PUBLIC(void) SIMIX_host_on(smx_host_t host);
+XBT_PUBLIC(void) SIMIX_host_off(smx_host_t host);
 XBT_PUBLIC(void) SIMIX_host_self_set_data(void *data);
 XBT_PUBLIC(void*) SIMIX_host_self_get_data(void);
 XBT_PUBLIC(void*) SIMIX_host_get_data(smx_host_t host);
@@ -293,6 +297,8 @@ XBT_PUBLIC(void) SIMIX_comm_finish(smx_action_t action);
 XBT_PUBLIC(smx_host_t) simcall_host_get_by_name(const char *name);
 XBT_PUBLIC(const char *) simcall_host_get_name(smx_host_t host);
 XBT_PUBLIC(xbt_dict_t) simcall_host_get_properties(smx_host_t host);
+XBT_PUBLIC(void) simcall_host_on(smx_host_t host);
+XBT_PUBLIC(void) simcall_host_off(smx_host_t host);
 XBT_PUBLIC(int) simcall_host_get_core(smx_host_t host);
 XBT_PUBLIC(double) simcall_host_get_speed(smx_host_t host);
 XBT_PUBLIC(double) simcall_host_get_available_speed(smx_host_t host);
@@ -304,7 +310,7 @@ XBT_PUBLIC(void) simcall_host_set_data(smx_host_t host, void *data);
 
 XBT_PUBLIC(smx_action_t) simcall_host_execute(const char *name, smx_host_t host,
                                                 double computation_amount,
-                                                double priority);
+                                                double priority, double bound);
 XBT_PUBLIC(smx_action_t) simcall_host_parallel_execute(const char *name,
                                                      int host_nb,
                                                      smx_host_t *host_list,
@@ -317,8 +323,25 @@ XBT_PUBLIC(void) simcall_host_execution_cancel(smx_action_t execution);
 XBT_PUBLIC(double) simcall_host_execution_get_remains(smx_action_t execution);
 XBT_PUBLIC(e_smx_state_t) simcall_host_execution_get_state(smx_action_t execution);
 XBT_PUBLIC(void) simcall_host_execution_set_priority(smx_action_t execution, double priority);
+XBT_PUBLIC(void) simcall_host_execution_set_bound(smx_action_t execution, double bound);
 XBT_PUBLIC(e_smx_state_t) simcall_host_execution_wait(smx_action_t execution);
-
+XBT_PUBLIC(void) simcall_host_get_params(smx_host_t vm, ws_params_t param);
+XBT_PUBLIC(void) simcall_host_set_params(smx_host_t vm, ws_params_t param);
+
+/******************************* VM simcalls ********************************/
+// Create the vm_workstation at the SURF level
+XBT_PUBLIC(void*) simcall_vm_create(const char *name, smx_host_t host);
+XBT_PUBLIC(int) simcall_vm_get_state(smx_host_t vm);
+XBT_PUBLIC(void) simcall_vm_start(smx_host_t vm);
+XBT_PUBLIC(void) simcall_vm_migrate(smx_host_t vm, smx_host_t dst_pm);
+XBT_PUBLIC(void *) simcall_vm_get_pm(smx_host_t vm);
+XBT_PUBLIC(void) simcall_vm_set_bound(smx_host_t vm, double bound);
+XBT_PUBLIC(void) simcall_vm_resume(smx_host_t vm);
+XBT_PUBLIC(void) simcall_vm_save(smx_host_t vm);
+XBT_PUBLIC(void) simcall_vm_restore(smx_host_t vm);
+XBT_PUBLIC(void) simcall_vm_suspend(smx_host_t vm);
+XBT_PUBLIC(void) simcall_vm_destroy(smx_host_t vm);
+XBT_PUBLIC(void) simcall_vm_shutdown(smx_host_t vm);
 
 /**************************** Process simcalls ********************************/
 /* Constructor and Destructor */
index b64b4d0..d1e6f5c 100644 (file)
@@ -262,7 +262,8 @@ typedef enum {
   thread_error,                 /**< error while [un]locking */
   host_error,                   /**< host failed */
   tracing_error,                /**< error during the simulation tracing */
-  io_error                      /**< disk or file error */
+  io_error,                      /**< disk or file error */
+  vm_error                      /**< vm  error */
 } xbt_errcat_t;
 
 XBT_PUBLIC(const char *) xbt_ex_catname(xbt_errcat_t cat);
index cdc9fc7..36232d9 100644 (file)
@@ -26,10 +26,12 @@ XBT_PUBLIC(void) xbt_lib_free(xbt_lib_t * lib);
 XBT_PUBLIC(int) xbt_lib_add_level(xbt_lib_t lib, void_f_pvoid_t free_f);
 XBT_PUBLIC(void) xbt_lib_set(xbt_lib_t lib, const char *name, int level,
                              void *obj);
+XBT_PUBLIC(void) xbt_lib_unset(xbt_lib_t lib, const char *key, int level, int invoke_callback);
 XBT_PUBLIC(void *) xbt_lib_get_or_null(xbt_lib_t lib, const char *name,
                                        int level);
 XBT_PUBLIC(xbt_dictelm_t) xbt_lib_get_elm_or_null(xbt_lib_t lib, const char *key);
 XBT_PUBLIC(void *) xbt_lib_get_level(xbt_dictelm_t elm, int level);
+XBT_PUBLIC(void) xbt_lib_remove(xbt_lib_t lib, const char *key);
 
 #define xbt_lib_length(lib) xbt_dict_length((lib)->dict)
 
index 0980d90..395b8d2 100644 (file)
@@ -28,100 +28,154 @@ Java_org_simgrid_msg_VM_nativeInit(JNIEnv *env, jclass cls) {
     jxbt_throw_native(env,bprintf("Can't find some fields in Java class. You should report this bug."));
   }
 }
+
+JNIEXPORT jint JNICALL
+Java_org_simgrid_msg_VM_isCreated(JNIEnv * env, jobject jvm) {
+  msg_vm_t vm = jvm_get_native(env,jvm);
+  return (jint) MSG_vm_is_created(vm);
+}
+
+JNIEXPORT jint JNICALL
+Java_org_simgrid_msg_VM_isRunning(JNIEnv * env, jobject jvm) {
+  msg_vm_t vm = jvm_get_native(env,jvm);
+  return (jint) MSG_vm_is_running(vm);
+}
+
+JNIEXPORT jint JNICALL
+Java_org_simgrid_msg_VM_isMigrating(JNIEnv * env, jobject jvm) {
+  msg_vm_t vm = jvm_get_native(env,jvm);
+  return (jint) MSG_vm_is_migrating(vm);
+}
+
+JNIEXPORT jint JNICALL
+Java_org_simgrid_msg_VM_isSuspended(JNIEnv * env, jobject jvm) {
+  msg_vm_t vm = jvm_get_native(env,jvm);
+  return (jint) MSG_vm_is_suspended(vm);
+}
+
+JNIEXPORT jint JNICALL
+Java_org_simgrid_msg_VM_isSaving(JNIEnv * env, jobject jvm) {
+  msg_vm_t vm = jvm_get_native(env,jvm);
+  return (jint) MSG_vm_is_saving(vm);
+}
+
+JNIEXPORT jint JNICALL
+Java_org_simgrid_msg_VM_isSaved(JNIEnv * env, jobject jvm) {
+  msg_vm_t vm = jvm_get_native(env,jvm);
+  return (jint) MSG_vm_is_saved(vm);
+}
+
+JNIEXPORT jint JNICALL
+Java_org_simgrid_msg_VM_isRestoring(JNIEnv * env, jobject jvm) {
+  msg_vm_t vm = jvm_get_native(env,jvm);
+  return (jint) MSG_vm_is_restoring(vm);
+}
 JNIEXPORT void JNICALL
-Java_org_simgrid_msg_VM_start(JNIEnv *env, jobject jvm, jobject jhost, jstring jname, jint jcoreamount) {
+Java_org_simgrid_msg_VM_create(JNIEnv *env, jobject jvm, jobject jhost, jstring jname,
+                              jint jncore, jint jramsize, jint jnetcap, jstring jdiskpath, jint jdisksize) {
   msg_host_t host = jhost_get_native(env, jhost);
 
   const char *name;
   name = (*env)->GetStringUTFChars(env, jname, 0);
   name = xbt_strdup(name);
-  
-  msg_vm_t vm = MSG_vm_start(host, name, (int)jcoreamount);
+
+  // TODO disk concerns are not taken into account yet
+  // const char *diskpath;
+  // disk_path = (*env)->GetStringUTFChars(env, jdiskpath, 0);
+  // disk_path = xbt_strdup(disk_path);
+
+  msg_vm_t vm = MSG_vm_create(host, name, (int) jncore, (int) jramsize,
+                 (int) jnetcap, NULL, (int) jdisksize);
 
   jvm_bind(env,jvm,vm);
 }
+
 JNIEXPORT void JNICALL
 Java_org_simgrid_msg_VM_destroy(JNIEnv *env, jobject jvm) {
   msg_vm_t vm = jvm_get_native(env,jvm);
   MSG_vm_destroy(vm);
 }
-JNIEXPORT jboolean JNICALL
-Java_org_simgrid_msg_VM_isSuspended(JNIEnv *env, jobject jvm) {
-  msg_vm_t vm = jvm_get_native(env,jvm);
-
-  return MSG_vm_is_suspended(vm) ? JNI_TRUE : JNI_FALSE;
-}
-JNIEXPORT jboolean JNICALL
-Java_org_simgrid_msg_VM_isRunning(JNIEnv *env, jobject jvm) {
-  msg_vm_t vm = jvm_get_native(env,jvm);
 
-  return MSG_vm_is_running(vm) ? JNI_TRUE : JNI_FALSE;
-}
 JNIEXPORT void JNICALL
-Java_org_simgrid_msg_VM_bind(JNIEnv *env, jobject jvm, jobject jprocess) {
+Java_org_simgrid_msg_VM_start(JNIEnv *env, jobject jvm) {
   msg_vm_t vm = jvm_get_native(env,jvm);
-  msg_process_t process = jprocess_to_native_process(jprocess,env);
-
-  xbt_assert((vm != NULL), "VM object is not bound");
-  xbt_assert((process != NULL), "Process object is not bound.");
-
-  MSG_vm_bind(vm,process);
+  MSG_vm_start(vm);
 }
+
 JNIEXPORT void JNICALL
-Java_org_simgrid_msg_VM_unbind(JNIEnv *env, jobject jvm, jobject jprocess) {
+Java_org_simgrid_msg_VM_shutdown(JNIEnv *env, jobject jvm) {
   msg_vm_t vm = jvm_get_native(env,jvm);
-  msg_process_t process = jprocess_to_native_process(jprocess,env);
-
-  MSG_vm_unbind(vm,process);
+  MSG_vm_shutdown(vm);
 }
+
 JNIEXPORT void JNICALL
-Java_org_simgrid_msg_VM_migrate(JNIEnv *env, jobject jvm, jobject jhost) {
+Java_org_simgrid_msg_VM_internalmig(JNIEnv *env, jobject jvm, jobject jhost) {
   msg_vm_t vm = jvm_get_native(env,jvm);
   msg_host_t host = jhost_get_native(env, jhost);
 
+  XBT_INFO("Start migration of %s to %s", MSG_host_get_name(vm), MSG_host_get_name(host));
   MSG_vm_migrate(vm,host);
+  XBT_INFO("Migration done");
 }
+
 JNIEXPORT void JNICALL
 Java_org_simgrid_msg_VM_suspend(JNIEnv *env, jobject jvm) {
   msg_vm_t vm = jvm_get_native(env,jvm);
-  xbt_ex_t e;
-  TRY {
-    MSG_vm_suspend(vm);
-  }
-  CATCH(e) {
-    xbt_ex_free(e);
-  }
+  MSG_vm_suspend(vm);
 }
 JNIEXPORT void JNICALL
 Java_org_simgrid_msg_VM_resume(JNIEnv *env, jobject jvm) {
   msg_vm_t vm = jvm_get_native(env,jvm);
-  xbt_ex_t e;
-  TRY {
-    MSG_vm_resume(vm);
-  }
-  CATCH(e) {
-    xbt_ex_free(e);
-  }
+  MSG_vm_resume(vm);
 }
+
 JNIEXPORT void JNICALL
-Java_org_simgrid_msg_VM_shutdown(JNIEnv *env, jobject jvm) {
+Java_org_simgrid_msg_VM_save(JNIEnv *env, jobject jvm) {
   msg_vm_t vm = jvm_get_native(env,jvm);
-  xbt_ex_t e;
-  TRY {
-    MSG_vm_shutdown(vm);
-  }
-  CATCH(e) {
-    xbt_ex_free(e);
-  }
+  MSG_vm_save(vm);
 }
 JNIEXPORT void JNICALL
-Java_org_simgrid_msg_VM_reboot(JNIEnv *env, jobject jvm) {
+Java_org_simgrid_msg_VM_restore(JNIEnv *env, jobject jvm) {
   msg_vm_t vm = jvm_get_native(env,jvm);
-  xbt_ex_t e;
-  TRY {
-    MSG_vm_reboot(vm);
-  }
-  CATCH(e) {
-    xbt_ex_free(e);
+  MSG_vm_restore(vm);
+}
+
+
+
+JNIEXPORT jobject JNICALL
+Java_org_simgrid_msg_VM_get_pm(JNIEnv *env, jobject jvm) {
+  jobject jhost;
+  msg_vm_t vm = jvm_get_native(env,jvm);
+  msg_host_t host = MSG_vm_get_pm(vm);
+
+  if (!MSG_host_get_data(host)) {
+    /* the native host not yet associated with the java host instance */
+
+    /* instanciate a new java host instance */
+    jhost = jhost_new_instance(env);
+
+    if (!jhost) {
+      jxbt_throw_jni(env, "java host instantiation failed");
+      return NULL;
+    }
+
+    /* get a global reference to the newly created host */
+    jhost = jhost_ref(env, jhost);
+
+    if (!jhost) {
+      jxbt_throw_jni(env, "global ref allocation failed");
+      return NULL;
+    }
+    /* Sets the host name */
+    const char *name = MSG_host_get_name(host);
+    jobject jname = (*env)->NewStringUTF(env,name);
+    (*env)->SetObjectField(env, jhost, jxbt_get_jfield(env, (*env)->FindClass(env, "org/simgrid/msg/Host"), "name", "Ljava/lang/String;"), jname);
+    /* Bind & store it */
+    jhost_bind(jhost, host, env);
+    MSG_host_set_data(host, (void *) jhost);
+  } else {
+    jhost = (jobject) MSG_host_get_data(host);
   }
+
+  return jhost;
 }
index 49d54b2..7bfe807 100644 (file)
@@ -22,55 +22,94 @@ msg_vm_t jvm_get_native(JNIEnv *env, jobject jvm);
  */
 JNIEXPORT void JNICALL
 Java_org_simgrid_msg_VM_nativeInit(JNIEnv *env, jclass);
+
 /**
  * Class                       org_simgrid_msg_VM
- * Method                      start
- * Signature   (I)V
+ * Method                      isCreated
+ * Signature   ()B
  */
-JNIEXPORT void JNICALL
-Java_org_simgrid_msg_VM_start(JNIEnv *env, jobject jvm, jobject jhost, jstring jname, jint jcoreamount);
+JNIEXPORT jint JNICALL
+Java_org_simgrid_msg_VM_isCreated(JNIEnv *env, jobject jvm);
 /**
- * Class            org_simgrid_msg_VM
- * Method           destroy
- * Signature    ()V
+ * Class                       org_simgrid_msg_VM
+ * Method                      isRunning
+ * Signature   ()B
  */
-JNIEXPORT void JNICALL
-Java_org_simgrid_msg_VM_destroy(JNIEnv *env, jobject jvm);
+JNIEXPORT jint JNICALL
+Java_org_simgrid_msg_VM_isRunning(JNIEnv *env, jobject jvm);
+/**
+ * Class                       org_simgrid_msg_VM
+ * Method                      isMigrating
+ * Signature   ()B
+ */
+JNIEXPORT jint JNICALL
+Java_org_simgrid_msg_VM_isMigrating(JNIEnv *env, jobject jvm);
 /**
  * Class                       org_simgrid_msg_VM
  * Method                      isSuspended
  * Signature   ()B
  */
-JNIEXPORT jboolean JNICALL
+JNIEXPORT jint JNICALL
 Java_org_simgrid_msg_VM_isSuspended(JNIEnv *env, jobject jvm);
 /**
  * Class                       org_simgrid_msg_VM
- * Method                      isRunning
+ * Method                      isResuming
  * Signature   ()B
  */
-JNIEXPORT jboolean JNICALL
-Java_org_simgrid_msg_VM_isRunning(JNIEnv *env, jobject jvm);
+JNIEXPORT jint JNICALL
+Java_org_simgrid_msg_VM_isResuming(JNIEnv *env, jobject jvm);
+/**
+ * Class                       org_simgrid_msg_VM
+ * Method                      isSuspended
+ * Signature   ()B
+ */
+JNIEXPORT jint JNICALL
+Java_org_simgrid_msg_VM_isSaving(JNIEnv *env, jobject jvm);
 /**
  * Class                       org_simgrid_msg_VM
- * Method                      bind
- * Signature   (Lorg/simgrid/msg/Process;)V
+ * Method                      isSave
+ * Signature   ()B
+ */
+JNIEXPORT jint JNICALL
+Java_org_simgrid_msg_VM_isSaved(JNIEnv *env, jobject jvm);
+/**
+ * Class                       org_simgrid_msg_VM
+ * Method                      isResuming
+ * Signature   ()B
+ */
+JNIEXPORT jint JNICALL
+Java_org_simgrid_msg_VM_isRestoring(JNIEnv *env, jobject jvm);
+
+/**
+ * Class            org_simgrid_msg_VM
+ * Method           create
+ * Signature    ()V
  */
 JNIEXPORT void JNICALL
-Java_org_simgrid_msg_VM_bind(JNIEnv *env, jobject jvm, jobject jprocess);
+Java_org_simgrid_msg_VM_create(JNIEnv *env, jobject jvm, jobject jhost, jstring jname,
+                              jint jncore, jint jramsize, jint jnetcap, jstring jdiskpath, jint jdisksize);
+
+/**
+ * Class            org_simgrid_msg_VM
+ * Method           destroy
+ * Signature    ()V
+ */
+JNIEXPORT void JNICALL
+Java_org_simgrid_msg_VM_destroy(JNIEnv *env, jobject jvm);
 /**
  * Class                       org_simgrid_msg_VM
- * Method                      unbind
- * Signature   (Lorg/simgrid/msg/Process;)V
+ * Method                      start
+ * Signature   (I)V
  */
 JNIEXPORT void JNICALL
-Java_org_simgrid_msg_VM_unbind(JNIEnv *env, jobject jvm, jobject jprocess);
+Java_org_simgrid_msg_VM_start(JNIEnv *env, jobject jvm);
 /**
  * Class                       org_simgrid_msg_VM
- * Method                      migrate
+ * Method                      nativeMigrate
  * Signature   (Lorg/simgrid/msg/Host;)V
  */
 JNIEXPORT void JNICALL
-Java_org_simgrid_msg_VM_migrate(JNIEnv *env, jobject jvm, jobject jhost);
+Java_org_simgrid_msg_VM_internalmig(JNIEnv *env, jobject jvm, jobject jhost);
 /**
  * Class                       org_simgrid_msg_VM
  * Method                      suspend
@@ -94,11 +133,18 @@ JNIEXPORT void JNICALL
 Java_org_simgrid_msg_VM_shutdown(JNIEnv *env, jobject jvm);
 /**
  * Class            org_simgrid_msg_VM
- * Method           reboot
+ * Method           save
+ * Signature    ()V
+ */
+JNIEXPORT void JNICALL
+Java_org_simgrid_msg_VM_save(JNIEnv *env, jobject jvm);
+/**
+ * Class            org_simgrid_msg_VM
+ * Method           save
  * Signature    ()V
  */
 JNIEXPORT void JNICALL
-Java_org_simgrid_msg_VM_reboot(JNIEnv *env, jobject jvm);
+Java_org_simgrid_msg_VM_restore(JNIEnv *env, jobject jvm);
 
 JNIEXPORT jobject JNICALL
 Java_org_simgrid_msg_VM_get_pm(JNIEnv *env, jobject jvm);
index 3b7f41f..3a4c666 100644 (file)
@@ -53,7 +53,7 @@ public class Host {
        /**
         * Host name
         */
-       private String name;
+       protected String name;
 
        /**
         * User data.
@@ -66,6 +66,11 @@ public class Host {
                this.bind = 0;
                this.data = null;
        };
+       
+       public String toString (){
+               return this.name; 
+               
+       }
 
        /**
         * This static method gets an host instance associated with a native
@@ -177,11 +182,13 @@ public class Host {
         * Returns the value of a given host property. 
         */
        public native String getProperty(String name);
+       
        /**
         * Change the value of a given host property. 
         */
        public native void setProperty(String name, String value);
-    /** This method tests if a host is available.
+    
+       /** This method tests if a host is available.
      * @return True if the host is available.
      */
        public native boolean isAvail();
index 13fa595..675da0b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * JNI interface to Cloud interface in Simgrid
+ * JNI interface to virtual machine in Simgrid
  * 
  * Copyright 2006-2012 The SimGrid Team.           
  * All right reserved. 
@@ -13,61 +13,151 @@ package org.simgrid.msg;
 import org.simgrid.msg.Host;
 import org.simgrid.msg.Process;
 
-public class VM {
-       /**
-        * This attribute represents a bind between a java task object and
-        * a native task. Even if this attribute is public you must never
-        * access to it. It is set automatically during the build of the object.
-        */
-       private long bind = 0;
+public class VM extends Host{
+       // Please note that we are not declaring a new bind variable 
+       //(the bind variable has been inherited from the super class Host)
+       
+       /* Static functions */ 
+       // GetByName is inherited from the super class Host
        
-       private int coreAmount;
 
-        private String name;
+        private static VM[] vms=null;    
+    private Host currentHost; 
+    
+       /* Constructors / destructors */
+    /**
+        * Create a `basic' VM (i.e. 1 core, 1GB of RAM, other values are not taken into account).
+        */
+       public VM(Host host, String name) {
+               this(host,name,1,1024*1024*1024, -1, null, -1);
+       }
+
        /**
-        * Create a new empty VM.
-        * NOTE: it is expected that in the future, the coreAmount parameter will be used
-        * to add extra constraints on the execution, but the argument is ignored for now.
+        * Create a `basic' VM (i.e. 1 core, 1GB of RAM, other values are not taken into account).
         */
-       public VM(Host host, String name, int coreAmount) {
-               this.coreAmount = coreAmount;
-               this.name = name;
-               start(host,name,coreAmount);
+       public VM(Host host, String name, int nCore,  long ramSize, 
+                        long netCap, String diskPath, long diskSize){
+               super();
+               super.name = name; 
+               this.currentHost = host; 
+               create(host, name, nCore, ramSize, netCap, diskPath, diskSize);
+               VM.addVM(this);
+       }
+
+       private static void addVM(VM vm){
+               VM[] vmsN=null; 
+               int i=0;
+               if(VM.vms == null)
+                       vmsN = new VM[1]; 
+               else
+                       vmsN = new VM[vms.length+1]; 
+               
+               for (i=0; i<vmsN.length-1 ; i ++){
+                       vmsN[i]=vms[i]; 
+               } 
+               vmsN[i]=vm;
+               vms=vmsN;
+       }
+   public static VM[] all(){
+               return vms;
+       }
+       public static VM getVMByName(String name){
+               for (int i=0 ; i < vms.length ; i++){
+                         if (vms[i].getName().equals(name))
+                                       return vms[i];          
+               }
+               return null; 
        }
        protected void finalize() {
                destroy();
        }
-       /**
-        * Destroy the VM
-        */
-       protected native void destroy();
-       /**
-        * Natively implemented method starting the VM.
-        * @param coreAmount
-        */
-       private native void start(Host host, String name, int coreAmount);
-               
+       
+
+       /* JNI / Native code */
+       /* get/set property methods are inherited from the Host class. */
+       
        /** Returns whether the given VM is currently suspended
         */     
-       public native boolean isSuspended();
+       public native int isCreated();
+       
        /** Returns whether the given VM is currently running
         */
-       public native boolean isRunning();
-       /** Add the given process into the VM.
-        * Afterward, when the VM is migrated or suspended or whatever, the process will have the corresponding handling, too.
-        */     
-       public native void bind(Process process);
-       /** Removes the given process from the given VM, and kill it
-        *  Will raise a ProcessNotFound exception if the process were not bound to that VM
+       public native int isRunning();
+
+       /** Returns whether the given VM is currently running
+        */
+       public native int isMigrating();
+       
+       /** Returns whether the given VM is currently suspended
         */     
-       public native void unbind(Process process);
-       /** Immediately change the host on which all processes are running
-        *
-        * No migration cost occurs. If you want to simulate this too, you want to use a
-        * Task.send() before or after, depending on whether you want to do cold or hot
-        * migration.
+       public native int isSuspended();
+               
+       /** Returns whether the given VM is currently saving
+        */
+       public native int isSaving();
+       
+       /** Returns whether the given VM is currently saved
+        */
+       public native int isSaved();
+
+       /** Returns whether the given VM is currently restoring its state
+        */
+       public native boolean isRestoring();
+       
+       /**
+        * Natively implemented method create the VM.
+        * @param nCore, number of core
+        * @param ramSize, size of the RAM that should be allocated 
+        * @param netCap (not used for the moment)
+        * @param diskPath (not used for the moment)
+        * @param diskSize (not used for the moment)
+        */
+       private native void create(Host host, String name, int nCore, long ramSize, 
+                        long netCap, String diskPath, long diskSize);
+       
+       /**
+        * start the VM
+        */
+       public native void start();
+
+       
+       /**
+        * Immediately kills all processes within the given VM. Any memory that they allocated will be leaked.
+        * No extra delay occurs. If you want to simulate this too, you want to use a MSG_process_sleep() or something
+        */
+       public native void shutdown();
+       
+       /**  
+        * Invoke native migration routine
+       */
+       public native void internalmig(Host destination);
+
+       
+       /** Change the host on which all processes are running
+        * (pre-copy is implemented)
         */     
-       public native void migrate(Host destination);
+       public void migrate(Host destination){
+//             String[] argsRx = new String[5];
+//             argsRx[1] = this.getName();
+//             argsRx[2] = this.currentHost.getName();
+//             argsRx[3] = destination.getName();
+//             argsRx[0] =  "__pr_mig_rx:"+argsRx[1]+"("+argsRx[2]+"-"+argsRx[3]+")";
+//             argsRx[4] = null; // TODO: Why ? 
+//             
+//             //Process rx = new Process(destination, argsRx[0], argsRx );
+//             
+//             String[] argsTx = new String[5];
+//             argsTx[1] = this.getName();
+//             argsTx[2] = this.currentHost.getName();
+//             argsTx[3] = destination.getName();
+//             argsTx[0] =  "__pr_mig_tx:"+argsTx[1]+"("+argsTx[2]+"-"+argsTx[3]+")";
+//             argsTx[4] = null; // TODO: Why ? 
+//             
+//             //Process tx = new Process(this.currentHost, argsTx[0], argsRx ); 
+//             
+               this.internalmig(destination);
+       }
+       
        /** Immediately suspend the execution of all processes within the given VM
         *
         * No suspension cost occurs. If you want to simulate this too, you want to
@@ -75,6 +165,7 @@ public class VM {
         * of VM suspend to you.
         */     
        public native void suspend();
+       
        /** Immediately resumes the execution of all processes within the given VM
         *
         * No resume cost occurs. If you want to simulate this too, you want to
@@ -82,19 +173,33 @@ public class VM {
         * of VM resume to you.
         */
        public native void resume();
-       /**
-        * Immediately kills all processes within the given VM. Any memory that they allocated will be leaked.
-        * No extra delay occurs. If you want to simulate this too, you want to use a MSG_process_sleep() or something
+       
+       /** Immediately suspend the execution of all processes within the given VM 
+        *  and save its state on the persistent HDD
+        *  Not yet implemented (for the moment it behaves like suspend)
+        *  No suspension cost occurs. If you want to simulate this too, you want to
+        *  use a \ref File.write() before or after, depending on the exact semantic
+        *  of VM suspend to you.
+        */     
+       public native void save();
+       
+       /** Immediately resumes the execution of all processes previously saved 
+        * within the given VM
+        *  Not yet implemented (for the moment it behaves like resume)
+        *
+        * No resume cost occurs. If you want to simulate this too, you want to
+        * use a \ref File.read() before or after, depending on the exact semantic
+        * of VM resume to you.
         */
-       public native void shutdown();
+       public native void restore();
+       
+
        /**
-        * Reboot the VM, restarting all the processes in it.
+        * Destroy the VM
         */
-       public native void reboot();
+       public native void destroy();
 
-       public String getName() {
-               return name;
-       }               
+       
 
        /**
         * Class initializer, to initialize various JNI stuff
index 92005a4..8b13218 100644 (file)
@@ -111,18 +111,23 @@ static void* smx_ctx_java_thread_run(void *data) {
     (*env)->SetLongField(env, context->jprocess, jprocess_field_Process_bind,
                          (intptr_t)process);
   }
-  xbt_assert((context->jprocess != NULL), "Process not created...");
-  //wait for the process to be able to begin
-  //TODO: Cache it
+
+  // Adrien, ugly path, just to bypass creation of context at low levels
+  // (i.e such as for the VM migration for instance)
+  if(context->jprocess != NULL){
+       xbt_assert((context->jprocess != NULL), "Process not created...");
+       //wait for the process to be able to begin
+       //TODO: Cache it
        jfieldID jprocess_field_Process_startTime = jxbt_get_sfield(env, "org/simgrid/msg/Process", "startTime", "D");
-  jdouble startTime =  (*env)->GetDoubleField(env, context->jprocess, jprocess_field_Process_startTime);
-  if (startTime > MSG_get_clock()) {
-       MSG_process_sleep(startTime - MSG_get_clock());
+       jdouble startTime =  (*env)->GetDoubleField(env, context->jprocess, jprocess_field_Process_startTime);
+       if (startTime > MSG_get_clock()) {
+               MSG_process_sleep(startTime - MSG_get_clock());
+       }
+       //Execution of the "run" method.
+       jmethodID id = jxbt_get_smethod(env, "org/simgrid/msg/Process", "run", "()V");
+       xbt_assert( (id != NULL), "Method not found...");
+       (*env)->CallVoidMethod(env, context->jprocess, id);
   }
-  //Execution of the "run" method.
-  jmethodID id = jxbt_get_smethod(env, "org/simgrid/msg/Process", "run", "()V");
-  xbt_assert( (id != NULL), "Method not found...");
-  (*env)->CallVoidMethod(env, context->jprocess, id);
   smx_ctx_java_stop((smx_context_t)context);
 
   return NULL;
index a862a2a..46d9086 100644 (file)
@@ -184,7 +184,7 @@ static int l_host_sleep(lua_State *L)
 static int l_host_destroy(lua_State *L)
 {
   msg_host_t ht = sglua_check_host(L, 1);
-  __MSG_host_destroy(MSG_host_priv(ht));
+  __MSG_host_priv_free(MSG_host_priv(ht));
   return 0;
 }
 
index 3b684fe..cb867e3 100644 (file)
@@ -79,6 +79,13 @@ enum heap_action_type{
   NOTSET
 };
 
+
+typedef struct surf_resource {
+  surf_model_t model;
+  char *name;
+  xbt_dict_t properties;
+} s_surf_resource_t, *surf_resource_t;
+
 /** \ingroup SURF_actions
  *  \brief Action structure
  *
@@ -92,6 +99,7 @@ typedef struct surf_action {
   xbt_swag_t state_set;
   double cost;                  /**< cost        */
   double priority;              /**< priority (1.0 by default) */
+  double bound;              /**< the capping of the CPU use  */
   double max_duration;          /**< max_duration (may fluctuate until
            the task is completed) */
   double remains;               /**< How much of that cost remains to
@@ -105,7 +113,12 @@ typedef struct surf_action {
          * and fluctuates until the task is completed */
   void *data;                   /**< for your convenience */
   int refcount;
-  surf_model_t model_type;
+
+  /* The previous name was model_type. For VM support, we have to distinguish a
+   * model type and its model object. Thus, we use model_obj here. The type of
+   * a model object is available by looking at the inside of the model object. */
+  surf_model_t model_obj;       /**< the surf model object */
+
 #ifdef HAVE_TRACING
   char *category;               /**< tracing category for categorized resource utilization monitoring */
 #endif
@@ -193,6 +206,8 @@ typedef struct surf_cpu_model_extension_public {
   surf_action_t(*execute) (void *cpu, double size);
   surf_action_t(*sleep) (void *cpu, double duration);
   e_surf_resource_state_t(*get_state) (void *cpu);
+  void(*set_state) (void *cpu, e_surf_resource_state_t state);
+
   int (*get_core) (void *cpu);
   double (*get_speed) (void *cpu, double load);
   double (*get_available_speed) (void *cpu);
@@ -236,16 +251,20 @@ typedef struct surf_storage_model_extension_public {
   surf_action_t(*ls) (void *storage, const char *path);
 } s_surf_model_extension_storage_t;
 
-     /** \ingroup SURF_models
     *  \brief Workstation model extension public
     *
     *  Public functions specific to the workstation model.
     */
+/** \ingroup SURF_models
+ *  \brief Workstation model extension public
+ *
+ *  Public functions specific to the workstation model.
+ */
 typedef struct surf_workstation_model_extension_public {
+  /* This points to the surf cpu model object bound to the workstation model. */
+  surf_model_t cpu_model;
+
   surf_action_t(*execute) (void *workstation, double size);                                /**< Execute a computation amount on a workstation
                                       and create the corresponding action */
   surf_action_t(*sleep) (void *workstation, double duration);                              /**< Make a workstation sleep during a given duration */
   e_surf_resource_state_t(*get_state) (void *workstation);                                      /**< Return the CPU state of a workstation */
+  void(*set_state) (void *workstation, e_surf_resource_state_t state);
   int (*get_core) (void *workstation); 
   double (*get_speed) (void *workstation, double load);                                    /**< Return the speed of a workstation */
   double (*get_available_speed) (void *workstation);                                       /**< Return tha available speed of a workstation */
@@ -278,10 +297,60 @@ typedef struct surf_workstation_model_extension_public {
    xbt_dict_t(*get_properties) (const void *resource);
   void (*add_traces) (void);
 
+  void (*get_params) (void *ind_vm_ws, ws_params_t param);
+  void (*set_params) (void *ind_vm_ws, ws_params_t param);
+  xbt_dynar_t (*get_vms) (void *ind_vm_ws);
+
 } s_surf_model_extension_workstation_t;
 
+typedef struct surf_vm_workstation_model_extension_public {
+  /* The vm workstation model object has all members of the physical machine
+   * workstation model object. If these members are correctly initialized also
+   * in the vm workstation model object, we can access the vm workstation model
+   * object as if it is the pm workstatoin model object.
+   *
+   * But, it's not so clean. Think it again later.
+   * */
+  s_surf_model_extension_workstation_t basic;
+
+  // start does not appear here as it corresponds to turn the state from created to running (see smx_vm.c)
+
+  void   (*create)  (const char *name, void *ind_phys_workstation); // First operation of the VM model
+  void   (*destroy) (void *ind_vm_ws); // will be vm_ws_destroy(), which destroies the vm-workstation-specific data
+
+  void   (*suspend) (void *ind_vm_ws);
+  void   (*resume)  (void *ind_vm_ws);
+
+  void   (*save)    (void *ind_vm_ws);
+  void   (*restore) (void *ind_vm_ws);
+
+  void   (*migrate) (void *ind_vm_ws, void *ind_vm_ws_dest); // will be vm_ws_migrate()
+
+  int    (*get_state) (void *ind_vm_ws);
+  void   (*set_state) (void *ind_vm_ws, int state);
+
+  void * (*get_pm) (void *ind_vm_ws); // will be vm_ws_get_pm()
 
+  void   (*set_vm_bound) (void *ind_vm_ws, double bound); // will be vm_ws_set_vm_bound()
 
+} s_surf_model_extension_vm_workstation_t;
+
+/** \ingroup SURF_models
+ *  \brief Model types
+ *
+ *  The type of the model object. For example, we will have two model objects
+ *  of the surf cpu model. One is for physical machines, and the other is for
+ *  virtual machines.
+ *
+ */
+typedef enum {
+  SURF_MODEL_TYPE_CPU = 0,
+  SURF_MODEL_TYPE_NETWORK,
+  SURF_MODEL_TYPE_STORAGE,
+  SURF_MODEL_TYPE_WORKSTATION,
+  SURF_MODEL_TYPE_VM_WORKSTATION,
+  SURF_MODEL_TYPE_NEW_MODEL
+} e_surf_model_type_t;
 
 /** \ingroup SURF_models
  *  \brief Model datatype
@@ -293,7 +362,9 @@ typedef struct surf_model {
   const char *name;     /**< Name of this model */
   s_surf_action_state_t states;      /**< Any living action on this model */
 
-   e_surf_action_state_t(*action_state_get) (surf_action_t action);
+  e_surf_model_type_t type; /**< See e_surf_model_type_t */
+
+  e_surf_action_state_t(*action_state_get) (surf_action_t action);
                                                                        /**< Return the state of an action */
   void (*action_state_set) (surf_action_t action,
                             e_surf_action_state_t state);
@@ -310,6 +381,7 @@ typedef struct surf_model {
   int (*is_suspended) (surf_action_t action);     /**< Return whether an action is suspended */
   void (*set_max_duration) (surf_action_t action, double duration);     /**< Set the max duration of an action*/
   void (*set_priority) (surf_action_t action, double priority);     /**< Set the priority of an action */
+  void (*set_bound) (surf_action_t action, double bound);     /**< Set the bound (the maximum CPU utilization) of an action */
 #ifdef HAVE_TRACING
   void (*set_category) (surf_action_t action, const char *category); /**< Set the category of an action */
 #endif
@@ -327,6 +399,8 @@ typedef struct surf_model {
     s_surf_model_extension_network_t network;
     s_surf_model_extension_storage_t storage;
     s_surf_model_extension_workstation_t workstation;
+    // TODO Implement the corresponding model
+    s_surf_model_extension_vm_workstation_t vm_workstation;
     /*******************************************/
     /* TUTORIAL: New model                     */
     s_surf_model_extension_new_model_t new_model;
@@ -357,11 +431,14 @@ static inline void *surf_storage_resource_by_name(const char *name){
   return xbt_lib_get_elm_or_null(storage_lib, name);
 }
 
-typedef struct surf_resource {
-  surf_model_t model;
-  char *name;
-  xbt_dict_t properties;
-} s_surf_resource_t, *surf_resource_t;
+static inline surf_model_t surf_resource_model(const void *host, int level) {
+  /* If level is SURF_WKS_LEVEL, ws is a workstation_CLM03 object. It has
+   * surf_resource at the generic_resource field. */
+  surf_resource_t ws = xbt_lib_get_level((void *) host, level);
+  return ws->model;
+}
+
+
 
 /**
  * Resource which have a metric handled by a maxmin system
@@ -386,9 +463,14 @@ typedef struct surf_resource_lmm {
 
 
 /** \ingroup SURF_models
- *  \brief The CPU model
+ *  \brief The CPU model object for the physical machine layer
+ */
+XBT_PUBLIC_DATA(surf_model_t) surf_cpu_model_pm;
+
+/** \ingroup SURF_models
+ *  \brief The CPU model object for the virtual machine layer
  */
-XBT_PUBLIC_DATA(surf_model_t) surf_cpu_model;
+XBT_PUBLIC_DATA(surf_model_t) surf_cpu_model_vm;
 
 /** \ingroup SURF_models
  *  \brief Initializes the CPU model with the model Cas01
@@ -407,7 +489,7 @@ XBT_PUBLIC(void) surf_cpu_model_init_Cas01(void);
  *
  *  You shouldn't have to call it by yourself.
  */
-XBT_PUBLIC(void) surf_cpu_model_init_ti(void);
+XBT_PUBLIC(surf_model_t) surf_cpu_model_init_ti(void);
 
 /** \ingroup SURF_models
  *  \brief The list of all available optimization modes (both for cpu and networks).
@@ -579,6 +661,16 @@ XBT_PUBLIC_DATA(s_surf_model_description_t) surf_storage_model_description[];
  */
 XBT_PUBLIC_DATA(surf_model_t) surf_workstation_model;
 
+/** \ingroup SURF_models
+ *  \brief The vm_workstation model
+ *
+ *  Note that when you create an API on top of SURF,
+ *  the vm_workstation model should be the only one you use
+ *  because depending on the platform model, the network model and the CPU model
+ *  may not exist.
+ */
+XBT_PUBLIC_DATA(surf_model_t) surf_vm_workstation_model;
+
 /** \ingroup SURF_models
  *  \brief Initializes the platform with a compound workstation model
  *
@@ -627,6 +719,7 @@ XBT_PUBLIC_DATA(s_surf_model_description_t) surf_new_model_description[];
  *  \brief List of initialized models
  */
 XBT_PUBLIC_DATA(xbt_dynar_t) model_list;
+XBT_PUBLIC_DATA(xbt_dynar_t) model_list_invoke;
 
 /*******************************************/
 /*** SURF Platform *************************/
index 7b7e3e4..8876113 100644 (file)
@@ -13,7 +13,7 @@ XBT_LOG_NEW_DEFAULT_SUBCATEGORY (instr_msg_vm, instr, "MSG VM");
 
 char *instr_vm_id (msg_vm_t vm, char *str, int len)
 {
-  return instr_vm_id_2 (vm->name, str, len);
+       return instr_vm_id_2 (MSG_vm_get_name(vm), str, len);
 }
 
 char *instr_vm_id_2 (const char *vm_name, char *str, int len)
@@ -55,7 +55,7 @@ void TRACE_msg_vm_change_host(msg_vm_t vm, msg_host_t old_host, msg_host_t new_h
   }
 }
 
-void TRACE_msg_vm_create (const char *vm_name, msg_host_t host)
+void TRACE_msg_vm_create(const char *vm_name, msg_host_t host)
 {
   if (TRACE_msg_vm_is_enabled()){
     int len = INSTR_DEFAULT_STR_SIZE;
@@ -66,6 +66,20 @@ void TRACE_msg_vm_create (const char *vm_name, msg_host_t host)
   }
 }
 
+void TRACE_msg_vm_start(msg_vm_t vm)
+{
+  if (TRACE_msg_vm_is_enabled()){
+    int len = INSTR_DEFAULT_STR_SIZE;
+    char str[INSTR_DEFAULT_STR_SIZE];
+
+    container_t vm_container = PJ_container_get (instr_vm_id(vm, str, len));
+    type_t type = PJ_type_get ("MSG_VM_STATE", vm_container->type);
+    val_t value = PJ_value_get ("start", type);
+    new_pajePushState (MSG_get_clock(), vm_container, type, value);
+  }
+
+}
+
 void TRACE_msg_vm_kill(msg_vm_t vm) {
   if (TRACE_msg_vm_is_enabled()) {
     int len = INSTR_DEFAULT_STR_SIZE;
@@ -103,7 +117,7 @@ void TRACE_msg_vm_resume(msg_vm_t vm)
   }
 }
 
-void TRACE_msg_vm_sleep_in(msg_vm_t vm)
+void TRACE_msg_vm_save(msg_vm_t vm)
 {
   if (TRACE_msg_vm_is_enabled()){
     int len = INSTR_DEFAULT_STR_SIZE;
@@ -111,12 +125,12 @@ void TRACE_msg_vm_sleep_in(msg_vm_t vm)
 
     container_t vm_container = PJ_container_get (instr_vm_id(vm, str, len));
     type_t type = PJ_type_get ("MSG_VM_STATE", vm_container->type);
-    val_t value = PJ_value_get ("sleep", type);
+    val_t value = PJ_value_get ("save", type);
     new_pajePushState (MSG_get_clock(), vm_container, type, value);
   }
 }
 
-void TRACE_msg_vm_sleep_out(msg_vm_t vm)
+void TRACE_msg_vm_restore(msg_vm_t vm)
 {
   if (TRACE_msg_vm_is_enabled()){
     int len = INSTR_DEFAULT_STR_SIZE;
index 3a3ad8c..7290f94 100644 (file)
@@ -37,7 +37,6 @@ void MSG_init_nocheck(int *argc, char **argv) {
 
   xbt_getpid = MSG_process_self_PID;
   if (!msg_global) {
-    s_msg_vm_t vm; // to compute the offset
 
     SIMIX_global_init(argc, argv);
     
@@ -49,7 +48,6 @@ void MSG_init_nocheck(int *argc, char **argv) {
     msg_global->sent_msg = 0;
     msg_global->task_copy_callback = NULL;
     msg_global->process_data_cleanup = NULL;
-    msg_global->vms = xbt_swag_new(xbt_swag_offset(vm,all_vms_hookup));
 
     /* initialization of the action module */
     _MSG_action_init();
@@ -70,7 +68,7 @@ void MSG_init_nocheck(int *argc, char **argv) {
 #endif
 
   XBT_DEBUG("ADD MSG LEVELS");
-  MSG_HOST_LEVEL = xbt_lib_add_level(host_lib, (void_f_pvoid_t) __MSG_host_destroy);
+  MSG_HOST_LEVEL = xbt_lib_add_level(host_lib, (void_f_pvoid_t) __MSG_host_priv_free);
 
   atexit(MSG_exit);
 }
@@ -175,7 +173,6 @@ static void MSG_exit(void) {
   TRACE_end();
 #endif
 
-  xbt_swag_free(msg_global->vms);
   free(msg_global);
   msg_global = NULL;
 }
index 2b28c97..e8112ed 100644 (file)
@@ -23,7 +23,15 @@ XBT_LOG_NEW_DEFAULT_SUBCATEGORY(msg_gos, msg,
  */
 msg_error_t MSG_task_execute(msg_task_t task)
 {
-  return MSG_parallel_task_execute(task);
+  /* TODO: add this to other locations */
+  msg_host_t host = MSG_process_get_host(MSG_process_self());
+  MSG_host_add_task(host, task);
+
+  msg_error_t ret = MSG_parallel_task_execute(task);
+
+  MSG_host_del_task(host, task);
+
+  return ret;
 }
 
 /** \ingroup msg_task_usage
@@ -77,7 +85,8 @@ msg_error_t MSG_parallel_task_execute(msg_task_t task)
       simdata->compute = simcall_host_execute(task->name,
                                               p_simdata->m_host,
                                               simdata->computation_amount,
-                                              simdata->priority);
+                                              simdata->priority,
+                                              simdata->bound);
 
     }
 #ifdef HAVE_TRACING
index 6f01ec9..3a64215 100644 (file)
@@ -29,28 +29,30 @@ XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(msg);
 msg_host_t __MSG_host_create(smx_host_t workstation)
 {
   const char *name = SIMIX_host_get_name(workstation);
-  msg_host_priv_t host = xbt_new0(s_msg_host_priv_t, 1);
-  s_msg_vm_t vm; // simply to compute the offset
-
-  host->vms = xbt_swag_new(xbt_swag_offset(vm,host_vms_hookup));
+  msg_host_priv_t priv = xbt_new0(s_msg_host_priv_t, 1);
 
 #ifdef MSG_USE_DEPRECATED
   int i;
   char alias[MAX_ALIAS_NAME + 1] = { 0 };       /* buffer used to build the key of the mailbox */
 
   if (msg_global->max_channel > 0)
-    host->mailboxes = xbt_new0(msg_mailbox_t, msg_global->max_channel);
+    priv->mailboxes = xbt_new0(msg_mailbox_t, msg_global->max_channel);
 
   for (i = 0; i < msg_global->max_channel; i++) {
     sprintf(alias, "%s:%d", name, i);
 
     /* the key of the mailbox (in this case) is build from the name of the host and the channel number */
-    host->mailboxes[i] = MSG_mailbox_new(alias);
+    priv->mailboxes[i] = MSG_mailbox_new(alias);
     memset(alias, 0, MAX_ALIAS_NAME + 1);
   }
 #endif
 
-  xbt_lib_set(host_lib,name,MSG_HOST_LEVEL,host);
+
+  priv->dp_objs = xbt_dict_new();
+  priv->dp_enabled = 0;
+  priv->dp_updated_by_deleted_tasks = 0;
+
+  xbt_lib_set(host_lib, name, MSG_HOST_LEVEL, priv);
   
   return xbt_lib_get_elm_or_null(host_lib, name);
 }
@@ -114,20 +116,53 @@ msg_host_t MSG_host_self(void)
   return MSG_process_get_host(NULL);
 }
 
+
 /*
- * \brief Destroys a host (internal call only)
+ * \brief Start the host if it is off
  */
-void __MSG_host_destroy(msg_host_priv_t host) {
+void MSG_host_on(msg_host_t host)
+{
+  simcall_host_on(host);
+}
+
+/*
+ * \brief Stop the host if it is on
+ */
+void MSG_host_off(msg_host_t host)
+{ 
+  simcall_host_off(host);
+}
+
+/*
+ * \brief Frees private data of a host (internal call only)
+ */
+void __MSG_host_priv_free(msg_host_priv_t priv)
+{
+  unsigned int size = xbt_dict_size(priv->dp_objs);
+  if (size > 0)
+    XBT_WARN("dp_objs: %u pending task?", size);
+  xbt_dict_free(&priv->dp_objs);
 
 #ifdef MSG_USE_DEPRECATED
   if (msg_global->max_channel > 0)
-    free(host->mailboxes);
+    free(priv->mailboxes);
 #endif
-  if (xbt_swag_size(host->vms) > 0 ) {
-    XBT_VERB("Host shut down, but it still hosts %d VMs. They will be leaked.",xbt_swag_size(host->vms));
-  }
-  xbt_swag_free(host->vms);
-  free(host);
+
+  free(priv);
+}
+
+/*
+ * \brief Destroys a host (internal call only)
+ */
+void __MSG_host_destroy(msg_host_t host)
+{
+  const char *name = MSG_host_get_name(host);
+  /* TODO:
+   * What happens if VMs still remain on this host?
+   * Revisit here after the surf layer gets stable.
+   **/
+
+  xbt_lib_unset(host_lib, name, MSG_HOST_LEVEL, 1);
 }
 
 /** \ingroup m_host_management
@@ -263,3 +298,25 @@ int MSG_host_is_avail(msg_host_t host)
   xbt_assert((host != NULL), "Invalid parameters (host is NULL)");
   return (simcall_host_get_state(host));
 }
+
+/** \ingroup m_host_management
+ * \brief Set the parameters of a given host
+ *
+ * \param host a host
+ * \param params a prameter object
+ */
+void MSG_host_set_params(msg_host_t ind_pm, ws_params_t params)
+{
+  simcall_host_set_params(ind_pm, params);
+}
+
+/** \ingroup m_host_management
+ * \brief Get the parameters of a given host
+ *
+ * \param host a host
+ * \param params a prameter object
+ */
+void MSG_host_get_params(msg_host_t ind_pm, ws_params_t params)
+{
+  simcall_host_get_params(ind_pm, params);
+}
index 02af63d..109ebbc 100644 (file)
@@ -31,7 +31,8 @@ typedef struct simdata_task {
   msg_process_t receiver;
   msg_host_t source;
   double priority;
-  double rate;
+  double bound; /* Capping for CPU resource */
+  double rate;  /* Capping for network resource */
   int isused;  /* Indicates whether the task is used in SIMIX currently */
   int host_nb;                  /* ==0 if sequential task; parallel task if not */
   /*******  Parallel Tasks Only !!!! *******/
@@ -68,8 +69,6 @@ typedef struct simdata_process {
   int argc;                     /* arguments number if any */
   msg_error_t last_errno;       /* the last value returned by a MSG_function */
 
-  msg_vm_t vm;                 /* virtual machine the process is in */
-
   void* data;                   /* user data */
 } s_simdata_process_t, *simdata_process_t;
 
@@ -89,21 +88,21 @@ typedef struct msg_comm {
   msg_task_t *task_received;      /* where the task will be received (NULL for the sender) */
   msg_error_t status;           /* status of the communication once finished */
 } s_msg_comm_t;
-/*
-typedef enum {
-  msg_vm_state_suspended, msg_vm_state_running, msg_vm_state_migrating
-} e_msg_vm_state_t;
 
-typedef struct msg_vm {
-  const char *name;
-  s_xbt_swag_hookup_t all_vms_hookup;
-  s_xbt_swag_hookup_t host_vms_hookup;
-  xbt_dynar_t processes;
-  e_msg_vm_state_t state;
-  msg_host_t location;
-  int coreAmount;
-} s_msg_vm_t;
-*/
+
+/******************************* VM *************************************/
+typedef struct dirty_page {
+  double prev_clock;
+  double prev_remaining;
+  msg_task_t task;
+} s_dirty_page, *dirty_page_t;
+
+XBT_PUBLIC_DATA(const char*) MSG_vm_get_property_value(msg_vm_t vm, const char *name);
+XBT_PUBLIC_DATA(xbt_dict_t) MSG_vm_get_properties(msg_vm_t vm);
+XBT_PUBLIC_DATA(void) MSG_vm_set_property_value(msg_vm_t vm, const char *name, void *value, void_f_pvoid_t free_ctn);
+XBT_PUBLIC_DATA(msg_vm_t) MSG_vm_get_by_name(const char *name);
+XBT_PUBLIC_DATA(const char*) MSG_vm_get_name(msg_vm_t vm);
+
 /************************** Global variables ********************************/
 typedef struct MSG_Global {
   xbt_fifo_t host;
@@ -114,7 +113,6 @@ typedef struct MSG_Global {
   unsigned long int sent_msg;   /* Total amount of messages sent during the simulation */
   void (*task_copy_callback) (msg_task_t task, msg_process_t src, msg_process_t dst);
   void_f_pvoid_t process_data_cleanup;
-  xbt_swag_t vms;
 } s_MSG_Global_t, *MSG_Global_t;
 
 /*extern MSG_Global_t msg_global;*/
@@ -136,7 +134,7 @@ XBT_PUBLIC_DATA(MSG_Global_t) msg_global;
 #endif
 
 msg_host_t __MSG_host_create(smx_host_t workstation);
-void __MSG_host_destroy(msg_host_priv_t host);
+void __MSG_host_destroy(msg_host_t host);
 
 void MSG_process_cleanup_from_SIMIX(smx_process_t smx_proc);
 void MSG_process_create_from_SIMIX(smx_process_t *process, const char *name,
@@ -150,6 +148,13 @@ void _MSG_action_exit(void);
 
 void MSG_post_create_environment(void);
 
+static inline void *msg_host_resource_priv(const void *host) {
+  return xbt_lib_get_level((void *)host, MSG_HOST_LEVEL);
+}
+
+void MSG_host_add_task(msg_host_t host, msg_task_t task);
+void MSG_host_del_task(msg_host_t host, msg_task_t task);
+
 /********** Tracing **********/
 /* declaration of instrumentation functions from msg_task_instr.c */
 void TRACE_msg_set_task_category(msg_task_t task, const char *category);
@@ -177,16 +182,17 @@ void TRACE_msg_process_sleep_out(msg_process_t process);
 void TRACE_msg_process_end(msg_process_t process);
 
 /* declaration of instrumentation functions from instr_msg_vm.c */
-char *instr_vm_id (msg_vm_t vm, char *str, int len);
-char *instr_vm_id_2 (const char *vm_name, char *str, int len);
+char *instr_vm_id(msg_vm_t vm, char *str, int len);
+char *instr_vm_id_2(const char *vm_name, char *str, int len);
 void TRACE_msg_vm_change_host(msg_vm_t vm, msg_host_t old_host,
                                    msg_host_t new_host);
-void TRACE_msg_vm_create (const char *vm_name, msg_host_t host);
+void TRACE_msg_vm_start(msg_vm_t vm);
+void TRACE_msg_vm_create(const char *vm_name, msg_host_t host);
 void TRACE_msg_vm_kill(msg_vm_t process);
 void TRACE_msg_vm_suspend(msg_vm_t vm);
 void TRACE_msg_vm_resume(msg_vm_t vm);
-void TRACE_msg_vm_sleep_in(msg_vm_t vm);
-void TRACE_msg_vm_sleep_out(msg_vm_t vm);
+void TRACE_msg_vm_save(msg_vm_t vm);
+void TRACE_msg_vm_restore(msg_vm_t vm);
 void TRACE_msg_vm_end(msg_vm_t vm);
 
 SG_END_DECL()
index be51825..357d57c 100644 (file)
@@ -50,12 +50,6 @@ void MSG_process_cleanup_from_SIMIX(smx_process_t smx_proc)
     msg_global->process_data_cleanup(msg_proc->data);
   }
 
-  // remove the process from its virtual machine
-  if (msg_proc->vm) {
-    int pos = xbt_dynar_search(msg_proc->vm->processes,&smx_proc);
-    xbt_dynar_remove_at(msg_proc->vm->processes,pos, NULL);
-  }
-
   // free the MSG process
   xbt_free(msg_proc);
 }
index a32e0d8..d95b180 100644 (file)
@@ -62,6 +62,7 @@ msg_task_t MSG_task_create(const char *name, double compute_duration,
   simdata->receiver = NULL;
   simdata->source = NULL;
   simdata->priority = 1.0;
+  simdata->bound = 0;
   simdata->rate = -1.0;
   simdata->isused = 0;
 
@@ -438,3 +439,24 @@ void MSG_task_set_priority(msg_task_t task, double priority)
     simcall_host_execution_set_priority(task->simdata->compute,
                                       task->simdata->priority);
 }
+
+
+/** \ingroup m_task_management
+ * \brief Changes the maximum CPU utilization of a computation task.
+ *        Unit is flops/s.
+ *
+ * For VMs, there is a pitfall. Please see MSG_vm_set_bound().
+ */
+void MSG_task_set_bound(msg_task_t task, double bound)
+{
+  xbt_assert(task, "Invalid parameter");
+  xbt_assert(task->simdata, "Invalid parameter");
+
+  if (bound == 0)
+    XBT_INFO("bound == 0 means no capping (i.e., unlimited).");
+
+  task->simdata->bound = bound;
+  if (task->simdata->compute)
+    simcall_host_execution_set_bound(task->simdata->compute,
+                                      task->simdata->bound);
+}
index 1143525..8055867 100644 (file)
@@ -3,6 +3,20 @@
 /* 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. */
 
+// QUESTIONS:
+// 1./ check how and where a new VM is added to the list of the hosts
+// 2./ Diff between SIMIX_Actions and SURF_Actions
+// => SIMIX_actions : point synchro entre processus de niveau (theoretically speaking I do not have to create such SIMIX_ACTION
+// =>  Surf_Actions
+
+// TODO
+//     MSG_TRACE can be revisited in order to use  the host
+//     To implement a mixed model between workstation and vm_workstation,
+//     please give a look at surf_model_private_t model_private at SURF Level and to the share resource functions
+//     double (*share_resources) (double now);
+//     For the action into the vm workstation model, we should be able to leverage the usual one (and if needed, look at
+//             the workstation model.
+
 #include "msg_private.h"
 #include "xbt/sysdep.h"
 #include "xbt/log.h"
 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(msg_vm, msg,
                                 "Cloud-oriented parts of the MSG API");
 
-/** @brief Create a new (empty) VMs.
- *  @ingroup msg_VMs
+
+/* **** ******** GENERAL ********* **** */
+
+/** \ingroup m_vm_management
+ * \brief Returns the value of a given vm property
  *
- *  @bug it is expected that in the future, the coreAmount parameter will be used
- *  to add extra constraints on the execution, but the argument is ignored for now.
+ * \param vm a vm
+ * \param name a property name
+ * \return value of a property (or NULL if property not set)
  */
 
-msg_vm_t MSG_vm_start(msg_host_t location, const char *name, int coreAmount) {
-  msg_vm_t res = xbt_new0(s_msg_vm_t,1);
-  res->all_vms_hookup.prev = NULL;
-  res->host_vms_hookup.prev = NULL;
-  res->state = msg_vm_state_running;
-  res->location = location;
-  res->coreAmount = coreAmount;
-  res->name = xbt_strdup(name);
-  res->processes = xbt_dynar_new(sizeof(msg_process_t),NULL);
+const char *MSG_vm_get_property_value(msg_vm_t vm, const char *name)
+{
+  return MSG_host_get_property_value(vm, name);
+}
+
+/** \ingroup m_vm_management
+ * \brief Returns a xbt_dict_t consisting of the list of properties assigned to this host
+ *
+ * \param vm a vm
+ * \return a dict containing the properties
+ */
+xbt_dict_t MSG_vm_get_properties(msg_vm_t vm)
+{
+  xbt_assert((vm != NULL), "Invalid parameters (vm is NULL)");
 
-  xbt_swag_insert(res,msg_global->vms);
-  xbt_swag_insert(res, MSG_host_priv(location)->vms);
+  return (simcall_host_get_properties(vm));
+}
 
-  #ifdef HAVE_TRACING
-  TRACE_msg_vm_create(name, location);
-  #endif
+/** \ingroup m_host_management
+ * \brief Change the value of a given host property
+ *
+ * \param host a host
+ * \param name a property name
+ * \param value what to change the property to
+ * \param free_ctn the freeing function to use to kill the value on need
+ */
+void MSG_vm_set_property_value(msg_vm_t vm, const char *name, void *value, void_f_pvoid_t free_ctn)
+{
+  xbt_dict_set(MSG_host_get_properties(vm), name, value, free_ctn);
+}
 
+/** \ingroup msg_vm_management
+ * \brief Finds a msg_vm_t using its name.
+ *
+ * This is a name directory service
+ * \param name the name of a vm.
+ * \return the corresponding vm
+ *
+ * Please note that a VM is a specific host. Hence, you should give a different name
+ * for each VM/PM.
+ */
 
-  return res;
+msg_vm_t MSG_vm_get_by_name(const char *name)
+{
+       return MSG_get_host_by_name(name);
 }
-/** @brief Returns a newly constructed dynar containing all existing VMs in the system.
- *  @ingroup msg_VMs
+
+/** \ingroup m_vm_management
+ *
+ * \brief Return the name of the #msg_host_t.
  *
- * Don't forget to free the dynar after use.
+ * This functions checks whether \a host is a valid pointer or not and return
+   its name.
  */
-xbt_dynar_t MSG_vms_as_dynar(void) {
-  xbt_dynar_t res = xbt_dynar_new(sizeof(msg_vm_t),NULL);
-  msg_vm_t vm;
-  xbt_swag_foreach(vm,msg_global->vms) {
-    xbt_dynar_push(res,&vm);
-  }
-  return res;
+const char *MSG_vm_get_name(msg_vm_t vm)
+{
+  return MSG_host_get_name(vm);
+}
+
+
+/* **** Check state of a VM **** */
+static inline int __MSG_vm_is_state(msg_vm_t vm, e_surf_vm_state_t state)
+{
+  return simcall_vm_get_state(vm) == state;
 }
 
-/** @brief Returns whether the given VM is currently suspended
+/** @brief Returns whether the given VM has just reated, not running.
  *  @ingroup msg_VMs
  */
-int MSG_vm_is_suspended(msg_vm_t vm) {
-  return vm->state == msg_vm_state_suspended;
+int MSG_vm_is_created(msg_vm_t vm)
+{
+  return __MSG_vm_is_state(vm, SURF_VM_STATE_CREATED);
 }
+
 /** @brief Returns whether the given VM is currently running
  *  @ingroup msg_VMs
  */
-int MSG_vm_is_running(msg_vm_t vm) {
-  return vm->state == msg_vm_state_running;
+int MSG_vm_is_running(msg_vm_t vm)
+{
+  return __MSG_vm_is_state(vm, SURF_VM_STATE_RUNNING);
 }
-/** @brief Add the given process into the VM.
+
+/** @brief Returns whether the given VM is currently migrating
  *  @ingroup msg_VMs
- *
- * Afterward, when the VM is migrated or suspended or whatever, the process will have the corresponding handling, too.
- *
  */
-void MSG_vm_bind(msg_vm_t vm, msg_process_t process) {
-  /* check if the process is already in a VM */
-  simdata_process_t simdata = simcall_process_get_data(process);
-  if (simdata->vm) {
-    msg_vm_t old_vm = simdata->vm;
-    int pos = xbt_dynar_search(old_vm->processes,&process);
-    xbt_dynar_remove_at(old_vm->processes,pos, NULL);
-  }
-  /* check if the host is in the right host */
-  if (simdata->m_host != vm->location) {
-    MSG_process_migrate(process,vm->location);
-  }
-  simdata->vm = vm;
+int MSG_vm_is_migrating(msg_vm_t vm)
+{
+  return __MSG_vm_is_state(vm, SURF_VM_STATE_MIGRATING);
+}
 
-  XBT_DEBUG("binding Process %s to %p",MSG_process_get_name(process),vm);
+/** @brief Returns whether the given VM is currently suspended, not running.
+ *  @ingroup msg_VMs
+ */
+int MSG_vm_is_suspended(msg_vm_t vm)
+{
+  return __MSG_vm_is_state(vm, SURF_VM_STATE_SUSPENDED);
+}
 
-  xbt_dynar_push_as(vm->processes,msg_process_t,process);
+/** @brief Returns whether the given VM is being saved (FIXME: live saving or not?).
+ *  @ingroup msg_VMs
+ */
+int MSG_vm_is_saving(msg_vm_t vm)
+{
+  return __MSG_vm_is_state(vm, SURF_VM_STATE_SAVING);
 }
-/** @brief Removes the given process from the given VM, and kill it
+
+/** @brief Returns whether the given VM has been saved, not running.
  *  @ingroup msg_VMs
- *
- *  Will raise a not_found exception if the process were not bound to that VM
  */
-void MSG_vm_unbind(msg_vm_t vm, msg_process_t process) {
-  int pos = xbt_dynar_search(vm->processes,process);
-  xbt_dynar_remove_at(vm->processes,pos, NULL);
-  MSG_process_kill(process);
+int MSG_vm_is_saved(msg_vm_t vm)
+{
+  return __MSG_vm_is_state(vm, SURF_VM_STATE_SAVED);
 }
 
-/** @brief Immediately change the host on which all processes are running.
+/** @brief Returns whether the given VM is being restored, not running.
  *  @ingroup msg_VMs
+ */
+int MSG_vm_is_restoring(msg_vm_t vm)
+{
+  return __MSG_vm_is_state(vm, SURF_VM_STATE_RESTORING);
+}
+
+
+
+/* ------------------------------------------------------------------------- */
+/* ------------------------------------------------------------------------- */
+
+/* **** ******** MSG vm actions ********* **** */
+
+/** @brief Create a new VM with specified parameters.
+ *  @ingroup msg_VMs*
  *
- * No migration cost occurs. If you want to simulate this too, you want to use a
- * MSG_task_send() before or after, depending on whether you want to do cold or hot
- * migration.
  */
-void MSG_vm_migrate(msg_vm_t vm, msg_host_t destination) {
-  unsigned int cpt;
-  msg_process_t process;
-  xbt_dynar_foreach(vm->processes,cpt,process) {
-    MSG_process_migrate(process,destination);
+msg_vm_t MSG_vm_create(msg_host_t ind_pm, const char *name,
+                                            int ncpus, long ramsize, long net_cap, char *disk_path, long disksize)
+{
+  msg_vm_t vm = MSG_vm_create_core(ind_pm, name);
+
+  {
+    s_ws_params_t params;
+    memset(&params, 0, sizeof(params));
+    params.ramsize = ramsize;
+    //params.overcommit = 0;
+    simcall_host_set_params(vm, &params);
+  }
+
+  /* TODO: Limit net capability, take into account disk considerations. */
+
+  return vm;
+}
+
+
+/** @brief Create a new VM object. The VM is not yet started. The resource of the VM is allocated upon MSG_vm_start().
+ *  @ingroup msg_VMs*
+ *
+ * A VM is treated as a host. The name of the VM must be unique among all hosts.
+ */
+msg_vm_t MSG_vm_create_core(msg_host_t ind_pm, const char *name)
+{
+  /* make sure the VM of the same name does not exit */
+  {
+    void *ind_host_tmp = xbt_lib_get_elm_or_null(host_lib, name);
+    if (ind_host_tmp) {
+      XBT_ERROR("host %s already exits", name);
+      return NULL;
+    }
   }
-  xbt_swag_remove(vm, MSG_host_priv(vm->location)->vms);
-  xbt_swag_insert_at_tail(vm, MSG_host_priv(destination)->vms);
-  
+
+  /* Note: ind_vm and vm_workstation point to the same elm object. */
+  msg_vm_t ind_vm = NULL;
+  void *ind_vm_workstation =  NULL;
+
+  /* Ask the SIMIX layer to create the surf vm resource */
+  ind_vm_workstation = simcall_vm_create(name, ind_pm);
+  ind_vm = (msg_vm_t) __MSG_host_create(ind_vm_workstation);
+
+  XBT_DEBUG("A new VM (%s) has been created", name);
+
   #ifdef HAVE_TRACING
-  TRACE_msg_vm_change_host(vm,vm->location,destination);
+  TRACE_msg_vm_create(name, ind_pm);
   #endif
 
-  vm->location = destination;
+  return ind_vm;
 }
 
-/** @brief Immediately suspend the execution of all processes within the given VM.
+/** @brief Destroy a VM. Destroy the VM object from the simulation.
  *  @ingroup msg_VMs
- *
- * No suspension cost occurs. If you want to simulate this too, you want to
- * use a \ref MSG_file_write() before or after, depending on the exact semantic
- * of VM suspend to you.
  */
-void MSG_vm_suspend(msg_vm_t vm) {
-  unsigned int cpt;
-  msg_process_t process;
-  xbt_dynar_foreach(vm->processes,cpt,process) {
-    XBT_DEBUG("suspend process %s of host %s",MSG_process_get_name(process),MSG_host_get_name(MSG_process_get_host(process)));
-    MSG_process_suspend(process);
+void MSG_vm_destroy(msg_vm_t vm)
+{
+  /* First, terminate all processes on the VM if necessary */
+  if (MSG_vm_is_running(vm))
+      simcall_vm_shutdown(vm);
+
+  if (!MSG_vm_is_created(vm)) {
+    XBT_CRITICAL("shutdown the given VM before destroying it");
+    DIE_IMPOSSIBLE;
   }
 
+  /* Then, destroy the VM object */
+  simcall_vm_destroy(vm);
+
+  __MSG_host_destroy(vm);
+
   #ifdef HAVE_TRACING
-  TRACE_msg_vm_suspend(vm);
+  TRACE_msg_vm_end(vm);
   #endif
 }
 
-/** @brief Immediately resumes the execution of all processes within the given VM.
+
+/** @brief Start a vm (i.e., boot the guest operating system)
  *  @ingroup msg_VMs
  *
- * No resume cost occurs. If you want to simulate this too, you want to
- * use a \ref MSG_file_read() before or after, depending on the exact semantic
- * of VM resume to you.
+ *  If the VM cannot be started, an exception is generated.
+ *
  */
-void MSG_vm_resume(msg_vm_t vm) {
-  unsigned int cpt;
-  msg_process_t process;
-  xbt_dynar_foreach(vm->processes,cpt,process) {
-    XBT_DEBUG("resume process %s of host %s",MSG_process_get_name(process),MSG_host_get_name(MSG_process_get_host(process)));
-    MSG_process_resume(process);
-  }
+void MSG_vm_start(msg_vm_t vm)
+{
+  simcall_vm_start(vm);
 
   #ifdef HAVE_TRACING
-  TRACE_msg_vm_resume(vm);
+  TRACE_msg_vm_start(vm);
   #endif
 }
 
+
+
 /** @brief Immediately kills all processes within the given VM. Any memory that they allocated will be leaked.
  *  @ingroup msg_VMs
  *
- * No extra delay occurs. If you want to simulate this too, you want to
+ * FIXME: No extra delay occurs. If you want to simulate this too, you want to
  * use a #MSG_process_sleep() or something. I'm not quite sure.
  */
 void MSG_vm_shutdown(msg_vm_t vm)
 {
-  msg_process_t process;
-  XBT_DEBUG("%lu processes in the VM", xbt_dynar_length(vm->processes));
-  while (!xbt_dynar_is_empty(vm->processes)) {
-    process = xbt_dynar_get_as(vm->processes,0,msg_process_t);
-    MSG_process_kill(process);
+  /* msg_vm_t equals to msg_host_t */
+  simcall_vm_shutdown(vm);
+
+  // #ifdef HAVE_TRACING
+  // TRACE_msg_vm_(vm);
+  // #endif
+}
+
+
+
+/* We have two mailboxes. mbox is used to transfer migration data between
+ * source and destiantion PMs. mbox_ctl is used to detect the completion of a
+ * migration. The names of these mailboxes must not conflict with others. */
+static inline char *get_mig_mbox_src_dst(const char *vm_name, const char *src_pm_name, const char *dst_pm_name)
+{
+  return bprintf("__mbox_mig_src_dst:%s(%s-%s)", vm_name, src_pm_name, dst_pm_name);
+}
+
+static inline char *get_mig_mbox_ctl(const char *vm_name, const char *src_pm_name, const char *dst_pm_name)
+{
+  return bprintf("__mbox_mig_ctl:%s(%s-%s)", vm_name, src_pm_name, dst_pm_name);
+}
+
+static inline char *get_mig_process_tx_name(const char *vm_name, const char *src_pm_name, const char *dst_pm_name)
+{
+  return bprintf("__pr_mig_tx:%s(%s-%s)", vm_name, src_pm_name, dst_pm_name);
+}
+
+static inline char *get_mig_process_rx_name(const char *vm_name, const char *src_pm_name, const char *dst_pm_name)
+{
+  return bprintf("__pr_mig_rx:%s(%s-%s)", vm_name, src_pm_name, dst_pm_name);
+}
+
+static inline char *get_mig_task_name(const char *vm_name, const char *src_pm_name, const char *dst_pm_name, int stage)
+{
+  return bprintf("__task_mig_stage%d:%s(%s-%s)", stage, vm_name, src_pm_name, dst_pm_name);
+}
+
+static void launch_deferred_exec_process(msg_host_t host, double computation, double prio);
+
+static int migration_rx_fun(int argc, char *argv[])
+{
+  XBT_DEBUG("mig: rx_start");
+
+  xbt_assert(argc == 4);
+  const char *vm_name = argv[1];
+  const char *src_pm_name  = argv[2];
+  const char *dst_pm_name  = argv[3];
+  msg_vm_t vm = MSG_get_host_by_name(vm_name);
+  msg_vm_t dst_pm = MSG_get_host_by_name(dst_pm_name);
+
+
+  s_ws_params_t params;
+  simcall_host_get_params(vm, &params);
+  const double xfer_cpu_overhead = params.xfer_cpu_overhead;
+
+
+  int need_exit = 0;
+
+  char *mbox = get_mig_mbox_src_dst(vm_name, src_pm_name, dst_pm_name);
+  char *mbox_ctl = get_mig_mbox_ctl(vm_name, src_pm_name, dst_pm_name);
+  char *finalize_task_name = get_mig_task_name(vm_name, src_pm_name, dst_pm_name, 3);
+
+  for (;;) {
+    msg_task_t task = NULL;
+    MSG_task_recv(&task, mbox);
+    {
+      double received = MSG_task_get_data_size(task);
+      /* TODO: clean up */
+      // const double alpha = 0.22L * 1.0E8 / (80L * 1024 * 1024);
+      launch_deferred_exec_process(vm, received * xfer_cpu_overhead, 1);
+    }
+
+    if (strcmp(task->name, finalize_task_name) == 0)
+      need_exit = 1;
+
+    MSG_task_destroy(task);
+
+    if (need_exit)
+      break;
+  }
+
+
+  simcall_vm_migrate(vm, dst_pm);
+  simcall_vm_resume(vm);
+
+  {
+    char *task_name = get_mig_task_name(vm_name, src_pm_name, dst_pm_name, 4);
+
+    msg_task_t task = MSG_task_create(task_name, 0, 0, NULL);
+    msg_error_t ret = MSG_task_send(task, mbox_ctl);
+    xbt_assert(ret == MSG_OK);
+
+    xbt_free(task_name);
+  }
+
+
+  xbt_free(mbox);
+  xbt_free(mbox_ctl);
+  xbt_free(finalize_task_name);
+
+  XBT_DEBUG("mig: rx_done");
+
+  return 0;
+}
+
+static void reset_dirty_pages(msg_vm_t vm)
+{
+  msg_host_priv_t priv = msg_host_resource_priv(vm);
+
+  char *key = NULL;
+  xbt_dict_cursor_t cursor = NULL;
+  dirty_page_t dp = NULL;
+  xbt_dict_foreach(priv->dp_objs, cursor, key, dp) {
+    double remaining = MSG_task_get_remaining_computation(dp->task);
+    dp->prev_clock = MSG_get_clock();
+    dp->prev_remaining = remaining;
+
+    // XBT_INFO("%s@%s remaining %f", key, sg_host_name(vm), remaining);
+  }
+}
+
+static void start_dirty_page_tracking(msg_vm_t vm)
+{
+  msg_host_priv_t priv = msg_host_resource_priv(vm);
+  priv->dp_enabled = 1;
+
+  reset_dirty_pages(vm);
+}
+
+static void stop_dirty_page_tracking(msg_vm_t vm)
+{
+  msg_host_priv_t priv = msg_host_resource_priv(vm);
+  priv->dp_enabled = 0;
+}
+
+#if 0
+/* It might be natural that we define dp_rate for each task. But, we will also
+ * have to care about how each task behavior affects the memory update behavior
+ * at the operating system level. It may not be easy to model it with a simple algorithm. */
+double calc_updated_pages(char *key, msg_vm_t vm, dirty_page_t dp, double remaining, double clock)
+{
+    double computed = dp->prev_remaining - remaining;
+    double duration = clock - dp->prev_clock;
+    double updated = dp->task->dp_rate * computed;
+
+    XBT_INFO("%s@%s: computated %f ops (remaining %f -> %f) in %f secs (%f -> %f)",
+        key, sg_host_name(vm), computed, dp->prev_remaining, remaining, duration, dp->prev_clock, clock);
+    XBT_INFO("%s@%s: updated %f bytes, %f Mbytes/s",
+        key, sg_host_name(vm), updated, updated / duration / 1000 / 1000);
+
+    return updated;
+}
+#endif
+
+static double get_computed(char *key, msg_vm_t vm, dirty_page_t dp, double remaining, double clock)
+{
+  double computed = dp->prev_remaining - remaining;
+  double duration = clock - dp->prev_clock;
+
+  XBT_DEBUG("%s@%s: computated %f ops (remaining %f -> %f) in %f secs (%f -> %f)",
+      key, sg_host_name(vm), computed, dp->prev_remaining, remaining, duration, dp->prev_clock, clock);
+
+  return computed;
+}
+
+static double lookup_computed_flop_counts(msg_vm_t vm, int stage_for_fancy_debug, int stage2_round_for_fancy_debug)
+{
+  msg_host_priv_t priv = msg_host_resource_priv(vm);
+  double total = 0;
+
+  char *key = NULL;
+  xbt_dict_cursor_t cursor = NULL;
+  dirty_page_t dp = NULL;
+  xbt_dict_foreach(priv->dp_objs, cursor, key, dp) {
+    double remaining = MSG_task_get_remaining_computation(dp->task);
+    double clock = MSG_get_clock();
+
+    // total += calc_updated_pages(key, vm, dp, remaining, clock);
+    total += get_computed(key, vm, dp, remaining, clock);
+
+    dp->prev_remaining = remaining;
+    dp->prev_clock = clock;
   }
 
+  total += priv->dp_updated_by_deleted_tasks;
+
+  XBT_INFO("mig-stage%d.%d: computed %f flop_counts (including %f by deleted tasks)",
+      stage_for_fancy_debug,
+      stage2_round_for_fancy_debug,
+      total, priv->dp_updated_by_deleted_tasks);
+
+
+
+  priv->dp_updated_by_deleted_tasks = 0;
+
+
+  return total;
+}
+
+// TODO Is this code redundant with the information provided by
+// msg_process_t MSG_process_create(const char *name, xbt_main_func_t code, void *data, msg_host_t host)
+void MSG_host_add_task(msg_host_t host, msg_task_t task)
+{
+  msg_host_priv_t priv = msg_host_resource_priv(host);
+  double remaining = MSG_task_get_remaining_computation(task);
+  char *key = bprintf("%s-%lld", task->name, task->counter);
+
+  dirty_page_t dp = xbt_new0(s_dirty_page, 1);
+  dp->task = task;
+
+  /* It should be okay that we add a task onto a migrating VM. */
+  if (priv->dp_enabled) {
+    dp->prev_clock = MSG_get_clock();
+    dp->prev_remaining = remaining;
+  }
+
+  xbt_assert(xbt_dict_get_or_null(priv->dp_objs, key) == NULL);
+  xbt_dict_set(priv->dp_objs, key, dp, NULL);
+  XBT_DEBUG("add %s on %s (remaining %f, dp_enabled %d)", key, sg_host_name(host), remaining, priv->dp_enabled);
+
+  xbt_free(key);
+}
+
+void MSG_host_del_task(msg_host_t host, msg_task_t task)
+{
+  msg_host_priv_t priv = msg_host_resource_priv(host);
+
+  char *key = bprintf("%s-%lld", task->name, task->counter);
+
+  dirty_page_t dp = xbt_dict_get_or_null(priv->dp_objs, key);
+  xbt_assert(dp->task == task);
+
+  /* If we are in the middle of dirty page tracking, we record how much
+   * computaion has been done until now, and keep the information for the
+   * lookup_() function that will called soon. */
+  if (priv->dp_enabled) {
+    double remaining = MSG_task_get_remaining_computation(task);
+    double clock = MSG_get_clock();
+    // double updated = calc_updated_pages(key, host, dp, remaining, clock);
+    double updated = get_computed(key, host, dp, remaining, clock);
+
+    priv->dp_updated_by_deleted_tasks += updated;
+  }
+
+  xbt_dict_remove(priv->dp_objs, key);
+  xbt_free(dp);
+
+  XBT_DEBUG("del %s on %s", key, sg_host_name(host));
+
+  xbt_free(key);
+}
+
+
+static int deferred_exec_fun(int argc, char *argv[])
+{
+  xbt_assert(argc == 3);
+  const char *comp_str = argv[1];
+  double computaion = atof(comp_str);
+  const char *prio_str = argv[2];
+  double prio = atof(prio_str);
+
+  msg_task_t task = MSG_task_create("__task_deferred", computaion, 0, NULL);
+  // XBT_INFO("exec deferred %f", computaion);
+
+  /* dpt is the results of the VM activity */
+  MSG_task_set_priority(task, prio);
+  MSG_task_execute(task);
+
+
+
+  MSG_task_destroy(task);
+
+  return 0;
+}
+
+static void launch_deferred_exec_process(msg_host_t host, double computation, double prio)
+{
+  char *pr_name = bprintf("__pr_deferred_exec_%s", MSG_host_get_name(host));
+
+  int nargvs = 4;
+  char **argv = xbt_new(char *, nargvs);
+  argv[0] = xbt_strdup(pr_name);
+  argv[1] = bprintf("%lf", computation);
+  argv[2] = bprintf("%lf", prio);
+  argv[3] = NULL;
+
+  MSG_process_create_with_arguments(pr_name, deferred_exec_fun, NULL, host, nargvs - 1, argv);
+
+  xbt_free(pr_name);
+}
+
+
+static int task_tx_overhead_fun(int argc, char *argv[])
+{
+  xbt_assert(argc == 2);
+  const char *mbox = argv[1];
+
+  int need_exit = 0;
+
+  // XBT_INFO("start %s", mbox);
+
+  for (;;) {
+    msg_task_t task = NULL;
+    MSG_task_recv(&task, mbox);
+
+    // XBT_INFO("task->name %s", task->name);
+
+    if (strcmp(task->name, "finalize_making_overhead") == 0)
+      need_exit = 1;
+
+    // XBT_INFO("exec");
+    // MSG_task_set_priority(task, 1000000);
+    MSG_task_execute(task);
+    MSG_task_destroy(task);
+
+    if (need_exit)
+      break;
+  }
+
+  // XBT_INFO("bye");
+
+  return 0;
+}
+
+static void start_overhead_process(msg_task_t comm_task)
+{
+  char *pr_name = bprintf("__pr_task_tx_overhead_%s", MSG_task_get_name(comm_task));
+  char *mbox    = bprintf("__mb_task_tx_overhead_%s", MSG_task_get_name(comm_task));
+
+  int nargvs = 3;
+  char **argv = xbt_new(char *, nargvs);
+  argv[0] = xbt_strdup(pr_name);
+  argv[1] = xbt_strdup(mbox);
+  argv[2] = NULL;
+
+  // XBT_INFO("micro start: mbox %s", mbox);
+  MSG_process_create_with_arguments(pr_name, task_tx_overhead_fun, NULL, MSG_host_self(), nargvs - 1, argv);
+
+  xbt_free(pr_name);
+  xbt_free(mbox);
+}
+
+static void shutdown_overhead_process(msg_task_t comm_task)
+{
+  char *mbox = bprintf("__mb_task_tx_overhead_%s", MSG_task_get_name(comm_task));
+
+  msg_task_t task = MSG_task_create("finalize_making_overhead", 0, 0, NULL);
+
+  // XBT_INFO("micro shutdown: mbox %s", mbox);
+  msg_error_t ret = MSG_task_send(task, mbox);
+  xbt_assert(ret == MSG_OK);
+
+  xbt_free(mbox);
+  // XBT_INFO("shutdown done");
+}
+
+static void request_overhead(msg_task_t comm_task, double computation)
+{
+  char *mbox = bprintf("__mb_task_tx_overhead_%s", MSG_task_get_name(comm_task));
+
+  msg_task_t task = MSG_task_create("micro", computation, 0, NULL);
+
+  // XBT_INFO("req overhead");
+  msg_error_t ret = MSG_task_send(task, mbox);
+  xbt_assert(ret == MSG_OK);
+
+  xbt_free(mbox);
+}
+
+/* alpha is (floating_operations / bytes).
+ *
+ * When actual migration traffic was 32 mbytes/s, we observed the CPU
+ * utilization of the main thread of the Qemu process was 10 %. 
+ *   alpha = 0.1 * C / (32 * 1024 * 1024)
+ * where the CPU capacity of the PM is C flops/s.
+ *
+ * */
+static void task_send_bounded_with_cpu_overhead(msg_task_t comm_task, char *mbox, double mig_speed, double alpha)
+{
+  const double chunk_size = 1024 * 1024 * 10;
+  double remaining = MSG_task_get_data_size(comm_task);
+
+  start_overhead_process(comm_task);
+
+
+  while (remaining > 0) {
+    double data_size = chunk_size;
+    if (remaining < chunk_size)
+      data_size = remaining;
+
+    remaining -= data_size;
+
+    // XBT_INFO("remaining %f bytes", remaining);
+
+
+    double clock_sta = MSG_get_clock();
+
+    /* create a micro task */
+    {
+      char *mtask_name = bprintf("__micro_%s", MSG_task_get_name(comm_task));
+      msg_task_t mtask = MSG_task_create(mtask_name, 0, data_size, NULL);
+
+      request_overhead(comm_task, data_size * alpha);
+
+      msg_error_t ret = MSG_task_send(mtask, mbox);
+      xbt_assert(ret == MSG_OK);
+
+      xbt_free(mtask_name);
+    }
+
+#if 0
+    {
+      /* In the real world, sending data involves small CPU computation. */
+      char *mtask_name = bprintf("__micro_%s", MSG_task_get_name(comm_task));
+      msg_task_t mtask = MSG_task_create(mtask_name, data_size * alpha, data_size, NULL);
+      MSG_task_execute(mtask);
+      MSG_task_destroy(mtask);
+      xbt_free(mtask_name);
+    }
+#endif
+   
+    /* TODO */
+
+    double clock_end = MSG_get_clock();
+
+
+    if (mig_speed > 0) {
+      /*
+       * (max bandwidth) > data_size / ((elapsed time) + time_to_sleep)
+       *
+       * Thus, we get
+       *   time_to_sleep > data_size / (max bandwidth) - (elapsed time)
+       *
+       * If time_to_sleep is smaller than zero, the elapsed time was too big. We
+       * do not need a micro sleep.
+       **/
+      double time_to_sleep = data_size / mig_speed - (clock_end - clock_sta);
+      if (time_to_sleep > 0)
+        MSG_process_sleep(time_to_sleep);
+
+
+      //XBT_INFO("duration %f", clock_end - clock_sta);
+      //XBT_INFO("time_to_sleep %f", time_to_sleep);
+    }
+  }
+
+  // XBT_INFO("%s", MSG_task_get_name(comm_task));
+  shutdown_overhead_process(comm_task);
+
+}
+
+
+#if 0
+static void make_cpu_overhead_of_data_transfer(msg_task_t comm_task, double init_comm_size)
+{
+  double prev_remaining = init_comm_size;
+
+  for (;;) {
+    double remaining = MSG_task_get_remaining_communication(comm_task);
+    if (remaining == 0)
+      need_exit = 1;
+
+    double sent = prev_remaining - remaining;
+    double comp_size = sent * overhead;
+
+
+    char *comp_task_name = bprintf("__sender_overhead%s", MSG_task_get_name(comm_task));
+    msg_task_t comp_task = MSG_task_create(comp_task_name, comp_size, 0, NULL);
+    MSG_task_execute(comp_task);
+    MSG_task_destroy(comp_task);
+
+    if (need_exit)
+      break;
+
+    prev_remaining = remaining;
+
+  }
+
+  xbt_free(comp_task_name);
+}
+#endif
+
+#define USE_MICRO_TASK 1
+
+#if 0
+// const double alpha = 0.1L * 1.0E8 / (32L * 1024 * 1024);
+// const double alpha = 0.25L * 1.0E8 / (85L * 1024 * 1024);
+// const double alpha = 0.20L * 1.0E8 / (85L * 1024 * 1024);
+// const double alpha = 0.25L * 1.0E8 / (85L * 1024 * 1024);
+// const double alpha = 0.32L * 1.0E8 / (24L * 1024 * 1024);   // makes super good values for 32 mbytes/s
+//const double alpha = 0.32L * 1.0E8 / (32L * 1024 * 1024);
+// const double alpha = 0.56L * 1.0E8 / (80L * 1024 * 1024);
+////const double alpha = 0.20L * 1.0E8 / (80L * 1024 * 1024);
+// const double alpha = 0.56L * 1.0E8 / (90L * 1024 * 1024);
+// const double alpha = 0.66L * 1.0E8 / (90L * 1024 * 1024);
+// const double alpha = 0.20L * 1.0E8 / (80L * 1024 * 1024);
+
+/* CPU 22% when 80Mbyte/s */
+const double alpha = 0.22L * 1.0E8 / (80L * 1024 * 1024);
+#endif
+
+
+static void send_migration_data(const char *vm_name, const char *src_pm_name, const char *dst_pm_name,
+    double size, char *mbox, int stage, int stage2_round, double mig_speed, double xfer_cpu_overhead)
+{
+  char *task_name = get_mig_task_name(vm_name, src_pm_name, dst_pm_name, stage);
+  msg_task_t task = MSG_task_create(task_name, 0, size, NULL);
+
+  /* TODO: clean up */
+
+  double clock_sta = MSG_get_clock();
+
+#ifdef USE_MICRO_TASK
+
+  task_send_bounded_with_cpu_overhead(task, mbox, mig_speed, xfer_cpu_overhead);
+
+#else
+  msg_error_t ret;
+  if (mig_speed > 0)
+    ret = MSG_task_send_bounded(task, mbox, mig_speed);
+  else
+    ret = MSG_task_send(task, mbox);
+  xbt_assert(ret == MSG_OK);
+#endif
+
+  double clock_end = MSG_get_clock();
+  double duration = clock_end - clock_sta;
+  double actual_speed = size / duration;
+#ifdef USE_MICRO_TASK
+  double cpu_utilization = size * xfer_cpu_overhead / duration / 1.0E8;
+#else
+  double cpu_utilization = 0;
+#endif
+
+
+
+
+  if (stage == 2)
+    XBT_INFO("mig-stage%d.%d: sent %f duration %f actual_speed %f (target %f) cpu %f", stage, stage2_round, size, duration, actual_speed, mig_speed, cpu_utilization);
+  else
+    XBT_INFO("mig-stage%d: sent %f duration %f actual_speed %f (target %f) cpu %f", stage, size, duration, actual_speed, mig_speed, cpu_utilization);
+
+  xbt_free(task_name);
+
+
+
+#ifdef USE_MICRO_TASK
+  /* The name of a micro task starts with __micro, which does not match the
+   * special name that finalizes the receiver loop. Thus, we send the special task.
+   **/
+  {
+    if (stage == 3) {
+      char *task_name = get_mig_task_name(vm_name, src_pm_name, dst_pm_name, stage);
+      msg_task_t task = MSG_task_create(task_name, 0, 0, NULL);
+      msg_error_t ret = MSG_task_send(task, mbox);
+      xbt_assert(ret == MSG_OK);
+      xbt_free(task_name);
+    }
+  }
+#endif
+}
+
+static double get_updated_size(double computed, double dp_rate, double dp_cap)
+{
+  double updated_size = computed * dp_rate;
+  XBT_INFO("updated_size %f dp_rate %f", updated_size, dp_rate);
+  if (updated_size > dp_cap) {
+    // XBT_INFO("mig-stage2.%d: %f bytes updated, but cap it with the working set size %f", stage2_round, updated_size, dp_cap);
+    updated_size = dp_cap;
+  }
+
+  return updated_size;
+}
+
+static double send_stage1(msg_host_t vm, const char *src_pm_name, const char *dst_pm_name,
+    long ramsize, double mig_speed, double xfer_cpu_overhead, double dp_rate, double dp_cap, double dpt_cpu_overhead)
+{
+  const char *vm_name = MSG_host_get_name(vm);
+  char *mbox = get_mig_mbox_src_dst(vm_name, src_pm_name, dst_pm_name);
+
+  const long chunksize = 1024 * 1024 * 100;
+  long remaining = ramsize;
+  double computed_total = 0;
+
+  while (remaining > 0) {
+    long datasize = chunksize;
+    if (remaining < chunksize)
+      datasize = remaining;
+
+    remaining -= datasize;
+
+    send_migration_data(vm_name, src_pm_name, dst_pm_name, datasize, mbox, 1, 0, mig_speed, xfer_cpu_overhead);
+
+    double computed = lookup_computed_flop_counts(vm, 1, 0);
+    computed_total += computed;
+
+    {
+      double updated_size = get_updated_size(computed, dp_rate, dp_cap);
+
+      double overhead = dpt_cpu_overhead * updated_size;
+      launch_deferred_exec_process(vm, overhead, 10000);
+    }
+  }
+
+  return computed_total;
+}
+
+
+
+
+static int migration_tx_fun(int argc, char *argv[])
+{
+  XBT_DEBUG("mig: tx_start");
+
+  xbt_assert(argc == 4);
+  const char *vm_name = argv[1];
+  const char *src_pm_name  = argv[2];
+  const char *dst_pm_name  = argv[3];
+  msg_vm_t vm = MSG_get_host_by_name(vm_name);
+
+
+  s_ws_params_t params;
+  simcall_host_get_params(vm, &params);
+  const long ramsize        = params.ramsize;
+  const long devsize        = params.devsize;
+  const int skip_stage1     = params.skip_stage1;
+  const int skip_stage2     = params.skip_stage2;
+  const double dp_rate      = params.dp_rate;
+  const double dp_cap       = params.dp_cap;
+  const double mig_speed    = params.mig_speed;
+  const double xfer_cpu_overhead = params.xfer_cpu_overhead;
+  const double dpt_cpu_overhead = params.dpt_cpu_overhead;
+
+  double remaining_size = ramsize + devsize;
+
+  double max_downtime = params.max_downtime;
+  if (max_downtime == 0) {
+    XBT_WARN("use the default max_downtime value 30ms");
+    max_downtime = 0.03;
+  }
+
+  /* This value assumes the network link is 1Gbps. */
+  double threshold = max_downtime * 125 * 1024 * 1024;
+
+  /* setting up parameters has done */
+
+
+  if (ramsize == 0)
+    XBT_WARN("migrate a VM, but ramsize is zero");
+
+  char *mbox = get_mig_mbox_src_dst(vm_name, src_pm_name, dst_pm_name);
+
+  XBT_INFO("mig-stage1: remaining_size %f", remaining_size);
+
+  /* Stage1: send all memory pages to the destination. */
+  start_dirty_page_tracking(vm);
+
+  double computed_during_stage1 = 0;
+  if (!skip_stage1) {
+    // send_migration_data(vm_name, src_pm_name, dst_pm_name, ramsize, mbox, 1, 0, mig_speed, xfer_cpu_overhead);
+
+    /* send ramsize, but split it */
+    computed_during_stage1 = send_stage1(vm, src_pm_name, dst_pm_name, ramsize, mig_speed, xfer_cpu_overhead, dp_rate, dp_cap, dpt_cpu_overhead);
+    remaining_size -= ramsize;
+  }
+
+
+  /* Stage2: send update pages iteratively until the size of remaining states
+   * becomes smaller than the threshold value. */
+  if (skip_stage2)
+    goto stage3;
+  if (max_downtime == 0) {
+    XBT_WARN("no max_downtime parameter, skip stage2");
+    goto stage3;
+  }
+
+
+  int stage2_round = 0;
+  for (;;) {
+
+    double 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 = lookup_computed_flop_counts(vm, 2, stage2_round);
+      updated_size = get_updated_size(computed, dp_rate, dp_cap);
+    }
+
+    XBT_INFO("%d updated_size %f computed_during_stage1 %f dp_rate %f dp_cap %f",
+        stage2_round, updated_size, computed_during_stage1, dp_rate, dp_cap);
+
+
+    if (stage2_round != 0) {
+      /* during stage1, we have already created overhead tasks */
+      double overhead = dpt_cpu_overhead * updated_size;
+      XBT_INFO("updated %f overhead %f", updated_size, overhead);
+      launch_deferred_exec_process(vm, overhead, 10000);
+    }
+
+
+    {
+      remaining_size += updated_size;
+
+      XBT_INFO("mig-stage2.%d: remaining_size %f (%s threshold %f)", stage2_round,
+          remaining_size, (remaining_size < threshold) ? "<" : ">", threshold);
+
+      if (remaining_size < threshold)
+        break;
+    }
+
+
+    send_migration_data(vm_name, src_pm_name, dst_pm_name, updated_size, mbox, 2, stage2_round, mig_speed, xfer_cpu_overhead);
+
+    remaining_size -= updated_size;
+    stage2_round += 1;
+  }
+
+
+stage3:
+  /* Stage3: stop the VM and copy the rest of states. */
+  XBT_INFO("mig-stage3: remaining_size %f", remaining_size);
+  simcall_vm_suspend(vm);
+  stop_dirty_page_tracking(vm);
+
+  send_migration_data(vm_name, src_pm_name, dst_pm_name, remaining_size, mbox, 3, 0, mig_speed, xfer_cpu_overhead);
+
+  xbt_free(mbox);
+
+  XBT_DEBUG("mig: tx_done");
+
+  return 0;
+}
+
+
+
+static void do_migration(msg_vm_t vm, msg_host_t src_pm, msg_host_t dst_pm)
+{
+  char *mbox_ctl = get_mig_mbox_ctl(sg_host_name(vm), sg_host_name(src_pm), sg_host_name(dst_pm));
+
+  {
+    char *pr_name = get_mig_process_rx_name(sg_host_name(vm), sg_host_name(src_pm), sg_host_name(dst_pm));
+    int nargvs = 5;
+    char **argv = xbt_new(char *, nargvs);
+    argv[0] = xbt_strdup(pr_name);
+    argv[1] = xbt_strdup(sg_host_name(vm));
+    argv[2] = xbt_strdup(sg_host_name(src_pm));
+    argv[3] = xbt_strdup(sg_host_name(dst_pm));
+    argv[4] = NULL;
+
+    MSG_process_create_with_arguments(pr_name, migration_rx_fun, NULL, dst_pm, nargvs - 1, argv);
+
+    xbt_free(pr_name);
+  }
+
+  {
+    char *pr_name = get_mig_process_tx_name(sg_host_name(vm), sg_host_name(src_pm), sg_host_name(dst_pm));
+    int nargvs = 5;
+    char **argv = xbt_new(char *, nargvs);
+    argv[0] = xbt_strdup(pr_name);
+    argv[1] = xbt_strdup(sg_host_name(vm));
+    argv[2] = xbt_strdup(sg_host_name(src_pm));
+    argv[3] = xbt_strdup(sg_host_name(dst_pm));
+    argv[4] = NULL;
+    MSG_process_create_with_arguments(pr_name, migration_tx_fun, NULL, src_pm, nargvs - 1, argv);
+
+    xbt_free(pr_name);
+  }
+
+  /* wait until the migration have finished */
+  {
+    msg_task_t task = NULL;
+    msg_error_t ret = MSG_task_recv(&task, mbox_ctl);
+    xbt_assert(ret == MSG_OK);
+
+    char *expected_task_name = get_mig_task_name(sg_host_name(vm), sg_host_name(src_pm), sg_host_name(dst_pm), 4);
+    xbt_assert(strcmp(task->name, expected_task_name) == 0);
+    xbt_free(expected_task_name);
+  }
+
+  xbt_free(mbox_ctl);
+}
+
+
+/** @brief Migrate the VM to the given host.
+ *  @ingroup msg_VMs
+ *
+ * FIXME: No migration cost occurs. If you want to simulate this too, you want to use a
+ * MSG_task_send() before or after, depending on whether you want to do cold or hot
+ * migration.
+ */
+void MSG_vm_migrate(msg_vm_t vm, msg_host_t new_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 migraion 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 old_pm = simcall_vm_get_pm(vm);
+
+  if (simcall_vm_get_state(vm) != SURF_VM_STATE_RUNNING)
+    THROWF(vm_error, 0, "VM(%s) is not running", sg_host_name(vm));
+
+  do_migration(vm, old_pm, new_pm);
+
+
+
+  XBT_DEBUG("VM(%s) moved from PM(%s) to PM(%s)", vm->key, old_pm->key, new_pm->key);
+
   #ifdef HAVE_TRACING
-  TRACE_msg_vm_kill(vm);
+  TRACE_msg_vm_change_host(vm, old_pm, new_pm);
   #endif
+}
+
+
+/** @brief Immediately suspend the execution of all processes within the given VM.
+ *  @ingroup msg_VMs
+ *
+ * This function stops the exection of the VM. All the processes on this VM
+ * will pause. The state of the VM is perserved. We can later resume it again.
+ *
+ * No suspension cost occurs.
+ */
+void MSG_vm_suspend(msg_vm_t vm)
+{
+  simcall_vm_suspend(vm);
 
+  XBT_DEBUG("vm_suspend done");
+
+  #ifdef HAVE_TRACING
+  TRACE_msg_vm_suspend(vm);
+  #endif
 }
 
-/**
- * \ingroup msg_VMs
- * \brief Reboot the VM, restarting all the processes in it.
+
+/** @brief Resume the execution of the VM. All processes on the VM run again.
+ *  @ingroup msg_VMs
+ *
+ * No resume cost occurs.
  */
-void MSG_vm_reboot(msg_vm_t vm)
+void MSG_vm_resume(msg_vm_t vm)
 {
-  xbt_dynar_t process_list = xbt_dynar_new(sizeof(msg_process_t), NULL);
-  msg_process_t process;
-  unsigned int cpt;
+  simcall_vm_resume(vm);
 
-  xbt_dynar_foreach(vm->processes, cpt, process) {
-    xbt_dynar_push_as(process_list, msg_process_t, process);
-  }
+  #ifdef HAVE_TRACING
+  TRACE_msg_vm_resume(vm);
+  #endif
+}
 
-  xbt_dynar_foreach(process_list, cpt, process) {
-    msg_process_t new_process = MSG_process_restart(process);
-    MSG_vm_bind(vm, new_process);
-  }
 
-  xbt_dynar_free(&process_list);
+/** @brief Immediately save the execution of all processes within the given VM.
+ *  @ingroup msg_VMs
+ *
+ * This function stops the exection of the VM. All the processes on this VM
+ * will pause. The state of the VM is perserved. We can later resume it again.
+ *
+ * FIXME: No suspension cost occurs. If you want to simulate this too, you want to
+ * use a \ref MSG_file_write() before or after, depending on the exact semantic
+ * of VM save to you.
+ */
+void MSG_vm_save(msg_vm_t vm)
+{
+  simcall_vm_save(vm);
+  #ifdef HAVE_TRACING
+  TRACE_msg_vm_save(vm);
+  #endif
 }
 
-/** @brief Destroy a msg_vm_t.
+/** @brief Restore the execution of the VM. All processes on the VM run again.
  *  @ingroup msg_VMs
+ *
+ * FIXME: No restore cost occurs. If you want to simulate this too, you want to
+ * use a \ref MSG_file_read() before or after, depending on the exact semantic
+ * of VM restore to you.
  */
-void MSG_vm_destroy(msg_vm_t vm) {
-  unsigned int cpt;
-  msg_process_t process;
-  xbt_dynar_foreach(vm->processes,cpt,process) {
-    //FIXME: Slow ?
-    simdata_process_t simdata = simcall_process_get_data(process);
-    simdata->vm = NULL;
-  }
+void MSG_vm_restore(msg_vm_t vm)
+{
+  simcall_vm_restore(vm);
 
   #ifdef HAVE_TRACING
-  TRACE_msg_vm_end(vm);
+  TRACE_msg_vm_restore(vm);
   #endif
+}
+
 
-  xbt_free(vm->name);
-  xbt_dynar_free(&vm->processes);
-  xbt_free(vm);
+/** @brief Get the physical host of a given VM.
+ *  @ingroup msg_VMs
+ */
+msg_host_t MSG_vm_get_pm(msg_vm_t vm)
+{
+  return simcall_vm_get_pm(vm);
+}
+
+
+/** @brief Set a CPU bound for a given VM.
+ *  @ingroup msg_VMs
+ *
+ * 1.
+ * Note that in some cases MSG_task_set_bound() may not intuitively work for VMs.
+ *
+ * For example,
+ *  On PM0, there are Task1 and VM0.
+ *  On VM0, there is Task2.
+ * Now we bound 75% to Task1@PM0 and bound 25% to Task2@VM0.
+ * Then, 
+ *  Task1@PM0 gets 50%.
+ *  Task2@VM0 gets 25%.
+ * This is NOT 75% for Task1@PM0 and 25% for Task2@VM0, respectively.
+ *
+ * This is because a VM has the dummy CPU action in the PM layer. Putting a
+ * task on the VM does not affect the bound of the dummy CPU action. The bound
+ * of the dummy CPU action is unlimited.
+ *
+ * There are some solutions for this problem. One option is to update the bound
+ * of the dummy CPU action automatically. It should be the sum of all tasks on
+ * the VM. But, this solution might be costy, because we have to scan all tasks
+ * on the VM in share_resource() or we have to trap both the start and end of
+ * task execution.
+ *
+ * The current solution is to use MSG_vm_set_bound(), which allows us to
+ * directly set the bound of the dummy CPU action.
+ *
+ *
+ * 2.
+ * Note that bound == 0 means no bound (i.e., unlimited).
+ */
+void MSG_vm_set_bound(msg_vm_t vm, double bound)
+{
+  return simcall_vm_set_bound(vm, bound);
 }
index 896e758..f04fd06 100644 (file)
@@ -284,6 +284,7 @@ xbt_swag_t SD_simulate_swag(double how_long) {
     if (elapsed_time > 0.0)
       total_time += elapsed_time;
 
+    /* FIXME: shoud look at model_list or model_list_invoke? */
     /* let's see which tasks are done */
     xbt_dynar_foreach(model_list, iter, model) {
       while ((action = xbt_swag_extract(model->states.done_action_set))) {
index 3022b61..6abbd4d 100644 (file)
@@ -21,6 +21,7 @@
 #include "smpi/smpi_interface.h"
 #include "mc/mc.h"
 #include "instr/instr.h"
+#include "surf/vm_workstation_private.h"
 
 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(surf_config, surf,
                                 "About the configuration of simgrid");
@@ -916,6 +917,9 @@ void surf_config_models_setup()
   XBT_DEBUG("Call workstation_model_init");
   surf_workstation_model_description[workstation_id].model_init_preparse();
 
+  XBT_DEBUG("Call vm_workstation_model_init");
+  surf_vm_workstation_model_init();
+
   XBT_DEBUG("Call storage_model_init");
   storage_id = find_model_description(surf_storage_model_description, storage_model_name);
   surf_storage_model_description[storage_id].model_init_preparse();
index c578d51..e171cd7 100644 (file)
@@ -323,13 +323,23 @@ void SIMIX_run(void)
       while ((action = xbt_swag_extract(set)))
         SIMIX_simcall_post((smx_action_t) action->data);
       set = model->states.done_action_set;
-      while ((action = xbt_swag_extract(set)))
-        SIMIX_simcall_post((smx_action_t) action->data);
+
+      while ((action = xbt_swag_extract(set))) {
+        if (action->data == NULL)
+          XBT_DEBUG("probably vcpu's action %p, skip", action);
+        else
+          SIMIX_simcall_post((smx_action_t) action->data);
+      }
     }
 
     /* Clean processes to destroy */
     SIMIX_process_empty_trash();
 
+
+    XBT_DEBUG("### time %f, empty %d", time, xbt_dynar_is_empty(simix_global->process_to_run));
+    // !(time == -1.0 && xbt_dynar_is_empty()) 
+
+
   } while (time != -1.0 || !xbt_dynar_is_empty(simix_global->process_to_run));
 
   if (xbt_swag_size(simix_global->process_list) != 0) {
index 72da17a..08ecdf3 100644 (file)
@@ -38,6 +38,62 @@ smx_host_t SIMIX_host_create(const char *name,
   return xbt_lib_get_elm_or_null(host_lib, name);
 }
 
+void SIMIX_pre_host_on(smx_simcall_t simcall, smx_host_t h)
+{
+  SIMIX_host_on(h);
+}
+
+/**
+ * \brief Start the host if it is off
+ *
+ */
+void SIMIX_host_on(smx_host_t h)
+{
+  smx_host_priv_t host = (smx_host_priv_t) h;
+
+  xbt_assert((host != NULL), "Invalid parameters");
+  
+  surf_model_t ws_model = surf_resource_model(h, SURF_WKS_LEVEL);
+  ws_model->extension.workstation.set_state(host, SURF_RESOURCE_ON);
+
+  SIMIX_host_restart_processes(h);
+}
+
+void SIMIX_pre_host_off(smx_simcall_t simcall, smx_host_t h)
+{
+  SIMIX_host_off(h);
+}
+
+/**
+ * \brief Stop the host if it is on
+ *
+ */
+void SIMIX_host_off(smx_host_t h)
+{
+  smx_host_priv_t host = (smx_host_priv_t) h;
+
+  xbt_assert((host != NULL), "Invalid parameters");
+
+  /* Clean Simulator data */
+  if (xbt_swag_size(host->process_list) != 0) {
+    char *msg = xbt_strdup("Shutting down host, but it's not empty:");
+    char *tmp;
+    smx_process_t process = NULL;
+
+    xbt_swag_foreach(process, host->process_list) {
+      tmp = bprintf("%s\n\t%s", msg, process->name);
+      free(msg);
+      msg = tmp;
+    }
+    SIMIX_display_process_status();
+    THROWF(arg_error, 0, "%s", msg);
+  }
+  xbt_swag_free(host->process_list);
+
+  surf_model_t ws_model = surf_resource_model(h, SURF_WKS_LEVEL);
+  ws_model->extension.workstation.set_state(host, SURF_RESOURCE_OFF);
+}
+
 /**
  * \brief Internal function to destroy a SIMIX host.
  *
@@ -135,7 +191,8 @@ xbt_dict_t SIMIX_pre_host_get_properties(smx_simcall_t simcall, smx_host_t host)
 xbt_dict_t SIMIX_host_get_properties(smx_host_t host){
   xbt_assert((host != NULL), "Invalid parameters (simix host is NULL)");
 
-  return surf_workstation_model->extension.workstation.get_properties(host);
+  surf_model_t ws_model = surf_resource_model(host, SURF_WKS_LEVEL);
+  return ws_model->extension.workstation.get_properties(host);
 }
 
 double SIMIX_pre_host_get_speed(smx_simcall_t simcall, smx_host_t host){
@@ -144,8 +201,8 @@ double SIMIX_pre_host_get_speed(smx_simcall_t simcall, smx_host_t host){
 double SIMIX_host_get_speed(smx_host_t host){
   xbt_assert((host != NULL), "Invalid parameters (simix host is NULL)");
 
-  return surf_workstation_model->extension.workstation.
-      get_speed(host, 1.0);
+  surf_model_t ws_model = surf_resource_model(host, SURF_WKS_LEVEL);
+  return ws_model->extension.workstation.get_speed(host, 1.0);
 }
 
 int SIMIX_pre_host_get_core(smx_simcall_t simcall, smx_host_t host){
@@ -166,8 +223,8 @@ double SIMIX_pre_host_get_available_speed(smx_simcall_t simcall, smx_host_t host
 double SIMIX_host_get_available_speed(smx_host_t host){
   xbt_assert((host != NULL), "Invalid parameters (simix host is NULL)");
 
-  return surf_workstation_model->extension.workstation.
-      get_available_speed(host);
+  surf_model_t ws_model = surf_resource_model(host, SURF_WKS_LEVEL);
+  return ws_model->extension.workstation.get_available_speed(host);
 }
 
 int SIMIX_pre_host_get_state(smx_simcall_t simcall, smx_host_t host){
@@ -176,8 +233,8 @@ int SIMIX_pre_host_get_state(smx_simcall_t simcall, smx_host_t host){
 int SIMIX_host_get_state(smx_host_t host){
   xbt_assert((host != NULL), "Invalid parameters (simix host is NULL)");
 
-  return surf_workstation_model->extension.workstation.
-      get_state(host);
+  surf_model_t ws_model = surf_resource_model(host, SURF_WKS_LEVEL);
+  return ws_model->extension.workstation.get_state(host);
 }
 
 void* SIMIX_pre_host_self_get_data(smx_simcall_t simcall){
@@ -316,11 +373,11 @@ void SIMIX_host_set_data(smx_host_t host, void *data){
 }
 
 smx_action_t SIMIX_pre_host_execute(smx_simcall_t simcall,const char *name,
-    smx_host_t host, double computation_amount, double priority){
-  return SIMIX_host_execute(name, host, computation_amount, priority);
+    smx_host_t host, double computation_amount, double priority, double bound){
+  return SIMIX_host_execute(name, host, computation_amount, priority, bound);
 }
 smx_action_t SIMIX_host_execute(const char *name,
-    smx_host_t host, double computation_amount, double priority){
+    smx_host_t host, double computation_amount, double priority, double bound){
 
   /* alloc structures and initialize */
   smx_action_t action = xbt_mallocator_get(simix_global->action_mallocator);
@@ -333,13 +390,13 @@ smx_action_t SIMIX_host_execute(const char *name,
   action->category = NULL;
 #endif
 
+  surf_model_t ws_model = surf_resource_model(host, SURF_WKS_LEVEL);
   /* set surf's action */
   if (!MC_is_active()) {
-    action->execution.surf_exec =
-      surf_workstation_model->extension.workstation.execute(host,
-    computation_amount);
-    surf_workstation_model->action_data_set(action->execution.surf_exec, action);
-    surf_workstation_model->set_priority(action->execution.surf_exec, priority);
+    action->execution.surf_exec = ws_model->extension.workstation.execute(host, computation_amount);
+    ws_model->action_data_set(action->execution.surf_exec, action);
+    ws_model->set_priority(action->execution.surf_exec, priority);
+    ws_model->set_bound(action->execution.surf_exec, bound);
   }
 
   XBT_DEBUG("Create execute action %p", action);
@@ -378,28 +435,54 @@ smx_action_t SIMIX_host_parallel_execute(const char *name,
   for (i = 0; i < host_nb; i++)
     workstation_list[i] = host_list[i];
 
+
+  /* FIXME: what happens if host_list contains VMs and PMs. If
+   * execute_parallel_task() does not change the state of the model, we can mix
+   * them. */
+  surf_model_t ws_model = surf_resource_model(host_list[0], SURF_WKS_LEVEL);
+  for (i = 1; i < host_nb; i++) {
+    surf_model_t ws_model_tmp = surf_resource_model(host_list[i], SURF_WKS_LEVEL);
+    if (ws_model_tmp != ws_model) {
+      XBT_CRITICAL("mixing VMs and PMs is not supported");
+      DIE_IMPOSSIBLE;
+    }
+  }
+
   /* set surf's action */
   if (!MC_is_active()) {
     action->execution.surf_exec =
-      surf_workstation_model->extension.workstation.
+      ws_model->extension.workstation.
       execute_parallel_task(host_nb, workstation_list, computation_amount,
                       communication_amount, rate);
 
-    surf_workstation_model->action_data_set(action->execution.surf_exec, action);
+    ws_model->action_data_set(action->execution.surf_exec, action);
   }
   XBT_DEBUG("Create parallel execute action %p", action);
 
   return action;
 }
 
+static surf_model_t get_ws_model_from_action(smx_action_t action)
+{
+  xbt_assert(action->type == SIMIX_ACTION_EXECUTE);
+  smx_host_t host = action->execution.host;
+  surf_model_t model = surf_resource_model(host, SURF_WKS_LEVEL);
+
+  xbt_assert((model == surf_workstation_model) || (model == surf_vm_workstation_model));
+
+  return model;
+}
+
 void SIMIX_pre_host_execution_destroy(smx_simcall_t simcall, smx_action_t action){
   SIMIX_host_execution_destroy(action);
 }
 void SIMIX_host_execution_destroy(smx_action_t action){
   XBT_DEBUG("Destroy action %p", action);
 
+  surf_model_t ws_model = get_ws_model_from_action(action);
+
   if (action->execution.surf_exec) {
-    surf_workstation_model->action_unref(action->execution.surf_exec);
+    ws_model->action_unref(action->execution.surf_exec);
     action->execution.surf_exec = NULL;
   }
   xbt_free(action->name);
@@ -412,8 +495,10 @@ void SIMIX_pre_host_execution_cancel(smx_simcall_t simcall, smx_action_t action)
 void SIMIX_host_execution_cancel(smx_action_t action){
   XBT_DEBUG("Cancel action %p", action);
 
+  surf_model_t ws_model = get_ws_model_from_action(action);
+
   if (action->execution.surf_exec)
-    surf_workstation_model->action_cancel(action->execution.surf_exec);
+    ws_model->action_cancel(action->execution.surf_exec);
 }
 
 double SIMIX_pre_host_execution_get_remains(smx_simcall_t simcall, smx_action_t action){
@@ -421,9 +506,10 @@ double SIMIX_pre_host_execution_get_remains(smx_simcall_t simcall, smx_action_t
 }
 double SIMIX_host_execution_get_remains(smx_action_t action){
   double result = 0.0;
+  surf_model_t ws_model = get_ws_model_from_action(action);
 
   if (action->state == SIMIX_RUNNING)
-    result = surf_workstation_model->get_remains(action->execution.surf_exec);
+    result = ws_model->get_remains(action->execution.surf_exec);
 
   return result;
 }
@@ -437,11 +523,24 @@ e_smx_state_t SIMIX_host_execution_get_state(smx_action_t action){
 
 void SIMIX_pre_host_execution_set_priority(smx_simcall_t simcall, smx_action_t action,
                                        double priority){
-  return SIMIX_host_execution_set_priority(action, priority);
+  SIMIX_host_execution_set_priority(action, priority);
 }
 void SIMIX_host_execution_set_priority(smx_action_t action, double priority){
+  surf_model_t ws_model = get_ws_model_from_action(action);
+
+  if(action->execution.surf_exec)
+    ws_model->set_priority(action->execution.surf_exec, priority);
+}
+
+void SIMIX_pre_host_execution_set_bound(smx_simcall_t simcall, smx_action_t action,
+                                       double bound){
+  SIMIX_host_execution_set_bound(action, bound);
+}
+void SIMIX_host_execution_set_bound(smx_action_t action, double bound){
+  surf_model_t ws_model = get_ws_model_from_action(action);
+
   if(action->execution.surf_exec)
-    surf_workstation_model->set_priority(action->execution.surf_exec, priority);
+    ws_model->set_bound(action->execution.surf_exec, bound);
 }
 
 void SIMIX_pre_host_execution_wait(smx_simcall_t simcall, smx_action_t action){
@@ -466,20 +565,25 @@ void SIMIX_pre_host_execution_wait(smx_simcall_t simcall, smx_action_t action){
 
 void SIMIX_host_execution_suspend(smx_action_t action)
 {
+  surf_model_t ws_model = get_ws_model_from_action(action);
+
   if(action->execution.surf_exec)
-    surf_workstation_model->suspend(action->execution.surf_exec);
+    ws_model->suspend(action->execution.surf_exec);
 }
 
 void SIMIX_host_execution_resume(smx_action_t action)
 {
+  surf_model_t ws_model = get_ws_model_from_action(action);
+
   if(action->execution.surf_exec)
-    surf_workstation_model->resume(action->execution.surf_exec);
+    ws_model->resume(action->execution.surf_exec);
 }
 
 void SIMIX_execution_finish(smx_action_t action)
 {
   xbt_fifo_item_t item;
   smx_simcall_t simcall;
+  surf_model_t ws_model = get_ws_model_from_action(action);
 
   xbt_fifo_foreach(action->simcalls, item, simcall, smx_simcall_t) {
 
@@ -506,8 +610,7 @@ void SIMIX_execution_finish(smx_action_t action)
             (int)action->state);
     }
     /* check if the host is down */
-    if (surf_workstation_model->extension.
-        workstation.get_state(simcall->issuer->smx_host) != SURF_RESOURCE_ON) {
+    if (ws_model->extension.workstation.get_state(simcall->issuer->smx_host) != SURF_RESOURCE_ON) {
       simcall->issuer->context->iwannadie = 1;
     }
 
@@ -520,15 +623,18 @@ void SIMIX_execution_finish(smx_action_t action)
   SIMIX_host_execution_destroy(action);
 }
 
+
 void SIMIX_post_host_execute(smx_action_t action)
 {
+  surf_model_t ws_model = get_ws_model_from_action(action);
+
   if (action->type == SIMIX_ACTION_EXECUTE && /* FIMXE: handle resource failure
                                                * for parallel tasks too */
-      surf_workstation_model->extension.workstation.get_state(action->execution.host) == SURF_RESOURCE_OFF) {
+      ws_model->extension.workstation.get_state(action->execution.host) == SURF_RESOURCE_OFF) {
     /* If the host running the action failed, notice it so that the asking
      * process can be killed if it runs on that host itself */
     action->state = SIMIX_FAILED;
-  } else if (surf_workstation_model->action_state_get(action->execution.surf_exec) == SURF_ACTION_FAILED) {
+  } else if (ws_model->action_state_get(action->execution.surf_exec) == SURF_ACTION_FAILED) {
     /* If the host running the action didn't fail, then the action was
      * canceled */
     action->state = SIMIX_CANCELED;
@@ -537,7 +643,7 @@ void SIMIX_post_host_execute(smx_action_t action)
   }
 
   if (action->execution.surf_exec) {
-    surf_workstation_model->action_unref(action->execution.surf_exec);
+    ws_model->action_unref(action->execution.surf_exec);
     action->execution.surf_exec = NULL;
   }
 
@@ -555,12 +661,44 @@ void SIMIX_pre_set_category(smx_simcall_t simcall, smx_action_t action,
 }
 void SIMIX_set_category(smx_action_t action, const char *category)
 {
+  surf_model_t ws_model = get_ws_model_from_action(action);
+
   if (action->state != SIMIX_RUNNING) return;
   if (action->type == SIMIX_ACTION_EXECUTE){
-    surf_workstation_model->set_category(action->execution.surf_exec, category);
+    ws_model->set_category(action->execution.surf_exec, category);
   }else if (action->type == SIMIX_ACTION_COMMUNICATE){
-    surf_workstation_model->set_category(action->comm.surf_comm, category);
+    ws_model->set_category(action->comm.surf_comm, category);
   }
 }
 #endif
 
+
+/**
+ * \brief Function to get the parameters of the given the SIMIX host.
+ *
+ * \param host the host to get_phys_host (a smx_host_t)
+ * \param param the parameter object space to be overwritten (a ws_params_t)
+ */
+void SIMIX_host_get_params(smx_host_t ind_vm, ws_params_t params)
+{
+  /* jump to ws_get_params(). */
+  surf_workstation_model->extension.workstation.get_params(ind_vm, params);
+}
+
+void SIMIX_pre_host_get_params(smx_simcall_t simcall, smx_host_t ind_vm, ws_params_t params)
+{
+  SIMIX_host_get_params(ind_vm, params);
+  SIMIX_simcall_answer(simcall);
+}
+
+void SIMIX_host_set_params(smx_host_t ind_vm, ws_params_t params)
+{
+  /* jump to ws_set_params(). */
+  surf_workstation_model->extension.workstation.set_params(ind_vm, params);
+}
+
+void SIMIX_pre_host_set_params(smx_simcall_t simcall, smx_host_t ind_vm, ws_params_t params)
+{
+  SIMIX_host_set_params(ind_vm, params);
+  SIMIX_simcall_answer(simcall);
+}
index adb53b8..4ed05a1 100644 (file)
@@ -42,8 +42,10 @@ int SIMIX_host_get_core(smx_host_t host);
 double SIMIX_host_get_speed(smx_host_t host);
 double SIMIX_host_get_available_speed(smx_host_t host);
 int SIMIX_host_get_state(smx_host_t host);
+void SIMIX_host_on(smx_host_t host);
+void SIMIX_host_off(smx_host_t host);
 smx_action_t SIMIX_host_execute(const char *name,
-    smx_host_t host, double computation_amount, double priority);
+    smx_host_t host, double computation_amount, double priority, double bound);
 smx_action_t SIMIX_host_parallel_execute(const char *name,
     int host_nb, smx_host_t *host_list,
     double *computation_amount, double *communication_amount,
@@ -53,12 +55,15 @@ void SIMIX_host_execution_cancel(smx_action_t action);
 double SIMIX_host_execution_get_remains(smx_action_t action);
 e_smx_state_t SIMIX_host_execution_get_state(smx_action_t action);
 void SIMIX_host_execution_set_priority(smx_action_t action, double priority);
+void SIMIX_host_execution_set_bound(smx_action_t action, double bound);
 void SIMIX_pre_host_execution_wait(smx_simcall_t simcall, smx_action_t action);
 
 // pre prototypes
 smx_host_t SIMIX_pre_host_get_by_name(smx_simcall_t, const char*);
 const char* SIMIX_pre_host_self_get_name(smx_simcall_t);
 const char* SIMIX_pre_host_get_name(smx_simcall_t, smx_host_t);
+void SIMIX_pre_host_on(smx_simcall_t, smx_host_t host);
+void SIMIX_pre_host_off(smx_simcall_t, smx_host_t host);
 xbt_dict_t SIMIX_pre_host_get_properties(smx_simcall_t, smx_host_t);
 int SIMIX_pre_host_get_core(smx_simcall_t, smx_host_t);
 double SIMIX_pre_host_get_speed(smx_simcall_t, smx_host_t);
@@ -67,7 +72,7 @@ int SIMIX_pre_host_get_state(smx_simcall_t, smx_host_t);
 void* SIMIX_pre_host_self_get_data(smx_simcall_t);
 void* SIMIX_pre_host_get_data(smx_simcall_t, smx_host_t);
 void SIMIX_pre_host_set_data(smx_simcall_t, smx_host_t, void*);
-smx_action_t SIMIX_pre_host_execute(smx_simcall_t, const char*, smx_host_t, double, double);
+smx_action_t SIMIX_pre_host_execute(smx_simcall_t, const char*, smx_host_t, double, double, double);
 smx_action_t SIMIX_pre_host_parallel_execute(smx_simcall_t, const char*, int, smx_host_t*,
                                              double*, double*, double, double);
 void SIMIX_pre_host_execution_destroy(smx_simcall_t, smx_action_t);
@@ -75,6 +80,7 @@ void SIMIX_pre_host_execution_cancel(smx_simcall_t, smx_action_t);
 double SIMIX_pre_host_execution_get_remains(smx_simcall_t, smx_action_t);
 e_smx_state_t SIMIX_pre_host_execution_get_state(smx_simcall_t, smx_action_t);
 void SIMIX_pre_host_execution_set_priority(smx_simcall_t, smx_action_t, double);
+void SIMIX_pre_host_execution_set_bound(smx_simcall_t simcall, smx_action_t action, double bound);
 
 void SIMIX_host_execution_suspend(smx_action_t action);
 void SIMIX_host_execution_resume(smx_action_t action);
@@ -87,5 +93,53 @@ void SIMIX_pre_set_category(smx_simcall_t simcall, smx_action_t action,
 void SIMIX_set_category(smx_action_t action, const char *category);
 #endif
 
+
+
+/* vm related stuff */
+smx_host_t SIMIX_vm_create(const char *name, smx_host_t ind_phys_host);
+smx_host_t SIMIX_pre_vm_create(smx_simcall_t simcall, const char *name, smx_host_t ind_phys_host);
+
+void SIMIX_vm_destroy(smx_host_t ind_vm);
+void SIMIX_pre_vm_destroy(smx_simcall_t simcall, smx_host_t ind_vm);
+// --
+void SIMIX_vm_resume(smx_host_t ind_vm, smx_process_t issuer);
+void SIMIX_pre_vm_resume(smx_simcall_t simcall, smx_host_t ind_vm);
+
+void SIMIX_vm_suspend(smx_host_t ind_vm, smx_process_t issuer);
+void SIMIX_pre_vm_suspend(smx_simcall_t simcall, smx_host_t ind_vm);
+// --
+void SIMIX_vm_save(smx_host_t ind_vm, smx_process_t issuer);
+void SIMIX_pre_vm_save(smx_simcall_t simcall, smx_host_t ind_vm);
+
+void SIMIX_vm_restore(smx_host_t ind_vm, smx_process_t issuer);
+void SIMIX_pre_vm_restore(smx_simcall_t simcall, smx_host_t ind_vm);
+// --
+void SIMIX_vm_start(smx_host_t ind_vm);
+void SIMIX_pre_vm_start(smx_simcall_t simcall, smx_host_t ind_vm);
+
+void SIMIX_vm_shutdown(smx_host_t ind_vm, smx_process_t issuer);
+void SIMIX_pre_vm_shutdown(smx_simcall_t simcall, smx_host_t ind_vm);
+// --
+void SIMIX_vm_set_state(smx_host_t ind_vm, int state);
+void SIMIX_pre_vm_set_state(smx_simcall_t simcall, smx_host_t ind_vm, int state);
+
+int SIMIX_vm_get_state(smx_host_t ind_vm);
+int SIMIX_pre_vm_get_state(smx_simcall_t simcall, smx_host_t ind_vm);
+// --
+void SIMIX_vm_migrate(smx_host_t ind_vm, smx_host_t ind_dst_pm);
+void SIMIX_pre_vm_migrate(smx_simcall_t simcall, smx_host_t ind_vm, smx_host_t ind_dst_pm);
+
+void *SIMIX_vm_get_pm(smx_host_t ind_vm);
+void *SIMIX_pre_vm_get_pm(smx_simcall_t simcall, smx_host_t ind_vm);
+
+void SIMIX_vm_set_bound(smx_host_t ind_vm, double bound);
+void SIMIX_pre_vm_set_bound(smx_simcall_t simcall, smx_host_t ind_vm, double bound);
+
+void SIMIX_host_get_params(smx_host_t ind_vm, ws_params_t params);
+void SIMIX_pre_host_get_params(smx_simcall_t simcall, smx_host_t ind_vm, ws_params_t params);
+
+void SIMIX_host_set_params(smx_host_t ind_vm, ws_params_t params);
+void SIMIX_pre_host_set_params(smx_simcall_t simcall, smx_host_t ind_vm, ws_params_t params);
+
 #endif
 
index 9f4f6dc..8e5f1cb 100644 (file)
@@ -308,7 +308,7 @@ void SIMIX_io_destroy(smx_action_t action)
 {
   XBT_DEBUG("Destroy action %p", action);
   if (action->io.surf_io)
-    action->io.surf_io->model_type->action_unref(action->io.surf_io);
+    action->io.surf_io->model_obj->action_unref(action->io.surf_io);
   xbt_mallocator_release(simix_global->action_mallocator, action);
 }
 
index 3be4eb5..7f90b67 100644 (file)
@@ -340,17 +340,17 @@ void SIMIX_comm_destroy_internal_actions(smx_action_t action)
 #ifdef HAVE_LATENCY_BOUND_TRACKING
     action->latency_limited = SIMIX_comm_is_latency_bounded(action);
 #endif
-    action->comm.surf_comm->model_type->action_unref(action->comm.surf_comm);
+    action->comm.surf_comm->model_obj->action_unref(action->comm.surf_comm);
     action->comm.surf_comm = NULL;
   }
 
   if (action->comm.src_timeout){
-    action->comm.src_timeout->model_type->action_unref(action->comm.src_timeout);
+    action->comm.src_timeout->model_obj->action_unref(action->comm.src_timeout);
     action->comm.src_timeout = NULL;
   }
 
   if (action->comm.dst_timeout){
-    action->comm.dst_timeout->model_type->action_unref(action->comm.dst_timeout);
+    action->comm.dst_timeout->model_obj->action_unref(action->comm.dst_timeout);
     action->comm.dst_timeout = NULL;
   }
 }
index acafb0e..5f7fcc6 100644 (file)
@@ -93,7 +93,7 @@ void SIMIX_new_api_destroy(smx_action_t action)
 {
   XBT_DEBUG("Destroy action %p", action);
   if (action->new_api.surf_new_api)
-    action->new_api.surf_new_api->model_type->action_unref(action->new_api.surf_new_api);
+    action->new_api.surf_new_api->model_obj->action_unref(action->new_api.surf_new_api);
   xbt_mallocator_release(simix_global->action_mallocator, action);
 }
 
index 4899f91..aa7434a 100644 (file)
@@ -487,7 +487,8 @@ smx_action_t SIMIX_process_suspend(smx_process_t process, smx_process_t issuer)
       return NULL;
     }
   } else {
-    return SIMIX_host_execute("suspend", process->smx_host, 0.0, 1.0);
+    /* FIXME: computation size is zero. Is it okay that bound is zero ? */
+    return SIMIX_host_execute("suspend", process->smx_host, 0.0, 1.0, 0.0);
   }
 }
 
@@ -689,9 +690,10 @@ smx_action_t SIMIX_process_sleep(smx_process_t process, double duration)
 {
   smx_action_t action;
   smx_host_t host = process->smx_host;
+  surf_model_t ws_model = surf_resource_model(host, SURF_WKS_LEVEL);
 
   /* check if the host is active */
-  if (surf_workstation_model->extension.
+  if (ws_model->extension.
       workstation.get_state(host) != SURF_RESOURCE_ON) {
     THROWF(host_error, 0, "Host %s failed, you cannot call this function",
            sg_host_name(host));
@@ -706,9 +708,9 @@ smx_action_t SIMIX_process_sleep(smx_process_t process, double duration)
 
   action->sleep.host = host;
   action->sleep.surf_sleep =
-      surf_workstation_model->extension.workstation.sleep(host, duration);
+      ws_model->extension.workstation.sleep(host, duration);
 
-  surf_workstation_model->action_data_set(action->sleep.surf_sleep, action);
+  ws_model->action_data_set(action->sleep.surf_sleep, action);
   XBT_DEBUG("Create sleep action %p", action);
 
   return action;
@@ -719,9 +721,13 @@ void SIMIX_post_process_sleep(smx_action_t action)
   smx_simcall_t simcall;
   e_smx_state_t state;
 
+  xbt_assert(action->type == SIMIX_ACTION_SLEEP);
+  smx_host_t host = action->sleep.host;
+  surf_model_t ws_model = surf_resource_model(host, SURF_WKS_LEVEL);
+
   while ((simcall = xbt_fifo_shift(action->simcalls))) {
 
-    switch(surf_workstation_model->action_state_get(action->sleep.surf_sleep)){
+    switch(ws_model->action_state_get(action->sleep.surf_sleep)){
       case SURF_ACTION_FAILED:
         simcall->issuer->context->iwannadie = 1;
         //SMX_EXCEPTION(simcall->issuer, host_error, 0, "Host failed");
@@ -736,7 +742,7 @@ void SIMIX_post_process_sleep(smx_action_t action)
         THROW_IMPOSSIBLE;
         break;
     }
-    if (surf_workstation_model->extension.
+    if (ws_model->extension.
         workstation.get_state(simcall->issuer->smx_host) != SURF_RESOURCE_ON) {
       simcall->issuer->context->iwannadie = 1;
     }
@@ -751,19 +757,30 @@ void SIMIX_post_process_sleep(smx_action_t action)
 void SIMIX_process_sleep_destroy(smx_action_t action)
 {
   XBT_DEBUG("Destroy action %p", action);
+  xbt_assert(action->type == SIMIX_ACTION_SLEEP);
+
   if (action->sleep.surf_sleep)
-    action->sleep.surf_sleep->model_type->action_unref(action->sleep.surf_sleep);
+    action->sleep.surf_sleep->model_obj->action_unref(action->sleep.surf_sleep);
   xbt_mallocator_release(simix_global->action_mallocator, action);
 }
 
 void SIMIX_process_sleep_suspend(smx_action_t action)
 {
-  surf_workstation_model->suspend(action->sleep.surf_sleep);
+  xbt_assert(action->type == SIMIX_ACTION_SLEEP);
+  smx_host_t host = action->sleep.host;
+  surf_model_t ws_model = surf_resource_model(host, SURF_WKS_LEVEL);
+
+  ws_model->suspend(action->sleep.surf_sleep);
 }
 
 void SIMIX_process_sleep_resume(smx_action_t action)
 {
-  surf_workstation_model->resume(action->sleep.surf_sleep);
+  xbt_assert(action->type == SIMIX_ACTION_SLEEP);
+  smx_host_t host = action->sleep.host;
+  surf_model_t ws_model = surf_resource_model(host, SURF_WKS_LEVEL);
+  XBT_DEBUG("%p ws_model", ws_model);
+
+  ws_model->resume(action->sleep.surf_sleep);
 }
 
 /** 
index 1f5f540..ab94860 100644 (file)
 #define SIMCALL_LIST1(ACTION, sep) \
 ACTION(SIMCALL_HOST_GET_BY_NAME, host_get_by_name, WITH_ANSWER, TSPEC(result, smx_host_t), TSTRING(name)) sep \
 ACTION(SIMCALL_HOST_GET_NAME, host_get_name, WITH_ANSWER, TSTRING(result), TSPEC(host, smx_host_t)) sep \
+ACTION(SIMCALL_HOST_ON, host_on, WITH_ANSWER, TVOID(result), TSPEC(host, smx_host_t)) sep \
+ACTION(SIMCALL_HOST_OFF, host_off, WITH_ANSWER, TVOID(result), TSPEC(host, smx_host_t)) sep \
 ACTION(SIMCALL_HOST_GET_PROPERTIES, host_get_properties, WITH_ANSWER, TSPEC(result, xbt_dict_t), TSPEC(host, smx_host_t)) sep \
 ACTION(SIMCALL_HOST_GET_CORE, host_get_core, WITH_ANSWER, TINT(result), TSPEC(host, smx_host_t)) sep \
 ACTION(SIMCALL_HOST_GET_SPEED, host_get_speed, WITH_ANSWER, TDOUBLE(result), TSPEC(host, smx_host_t)) sep \
@@ -268,14 +270,30 @@ ACTION(SIMCALL_HOST_GET_AVAILABLE_SPEED, host_get_available_speed, WITH_ANSWER,
 ACTION(SIMCALL_HOST_GET_STATE, host_get_state, WITH_ANSWER, TINT(result), TSPEC(host, smx_host_t)) sep \
 ACTION(SIMCALL_HOST_GET_DATA, host_get_data, WITH_ANSWER, TPTR(result), TSPEC(host, smx_host_t)) sep \
 ACTION(SIMCALL_HOST_SET_DATA, host_set_data, WITH_ANSWER, TVOID(result), TSPEC(host, smx_host_t), TPTR(data)) sep \
-ACTION(SIMCALL_HOST_EXECUTE, host_execute, WITH_ANSWER, TSPEC(result, smx_action_t), TSTRING(name), TSPEC(host, smx_host_t), TDOUBLE(computation_amount), TDOUBLE(priority)) sep \
+ACTION(SIMCALL_HOST_EXECUTE, host_execute, WITH_ANSWER, TSPEC(result, smx_action_t), TSTRING(name), TSPEC(host, smx_host_t), TDOUBLE(computation_amount), TDOUBLE(priority), TDOUBLE(bound)) sep \
 ACTION(SIMCALL_HOST_PARALLEL_EXECUTE, host_parallel_execute, WITH_ANSWER, TSPEC(result, smx_action_t), TSTRING(name), TINT(host_nb), TSPEC(host_list, smx_host_t*), TSPEC(computation_amount, double*), TSPEC(communication_amount, double*), TDOUBLE(amount), TDOUBLE(rate)) sep \
 ACTION(SIMCALL_HOST_EXECUTION_DESTROY, host_execution_destroy, WITH_ANSWER, TVOID(result), TSPEC(execution, smx_action_t)) sep \
 ACTION(SIMCALL_HOST_EXECUTION_CANCEL, host_execution_cancel, WITH_ANSWER, TVOID(result), TSPEC(execution, smx_action_t)) sep \
 ACTION(SIMCALL_HOST_EXECUTION_GET_REMAINS, host_execution_get_remains, WITH_ANSWER, TDOUBLE(result), TSPEC(execution, smx_action_t)) sep \
 ACTION(SIMCALL_HOST_EXECUTION_GET_STATE, host_execution_get_state, WITH_ANSWER, TINT(result), TSPEC(execution, smx_action_t)) sep \
 ACTION(SIMCALL_HOST_EXECUTION_SET_PRIORITY, host_execution_set_priority, WITH_ANSWER, TVOID(result), TSPEC(execution, smx_action_t), TDOUBLE(priority)) sep \
+ACTION(SIMCALL_HOST_EXECUTION_SET_BOUND, host_execution_set_bound, WITHOUT_ANSWER, TVOID(result), TSPEC(execution, smx_action_t), TDOUBLE(bound)) sep \
 ACTION(SIMCALL_HOST_EXECUTION_WAIT, host_execution_wait, WITHOUT_ANSWER, TINT(result), TSPEC(execution, smx_action_t)) sep \
+ACTION(SIMCALL_HOST_GET_PARAMS, host_get_params, WITHOUT_ANSWER, TVOID(result), TSPEC(ind_vm, smx_host_t), TSPEC(params, ws_params_t)) sep \
+ACTION(SIMCALL_HOST_SET_PARAMS, host_set_params, WITHOUT_ANSWER, TVOID(result), TSPEC(ind_vm, smx_host_t), TSPEC(params, ws_params_t)) sep \
+ACTION(SIMCALL_VM_CREATE,    vm_create,    WITH_ANSWER,    TPTR(result),  TSTRING(name), TSPEC(ind_pm, smx_host_t)) sep \
+ACTION(SIMCALL_VM_START,     vm_start,     WITHOUT_ANSWER, TVOID(result), TSPEC(ind_vm, smx_host_t)) sep \
+ACTION(SIMCALL_VM_SET_STATE, vm_set_state, WITHOUT_ANSWER, TVOID(result), TSPEC(ind_vm, smx_host_t), TINT(state)) sep \
+ACTION(SIMCALL_VM_GET_STATE, vm_get_state, WITH_ANSWER,    TINT(result),  TSPEC(ind_vm, smx_host_t)) sep \
+ACTION(SIMCALL_VM_MIGRATE,   vm_migrate,   WITHOUT_ANSWER, TVOID(result), TSPEC(ind_vm, smx_host_t), TSPEC(ind_dst_pm, smx_host_t)) sep \
+ACTION(SIMCALL_VM_GET_PM,    vm_get_pm,    WITH_ANSWER,    TPTR(result),  TSPEC(ind_vm, smx_host_t)) sep \
+ACTION(SIMCALL_VM_SET_BOUND, vm_set_bound, WITHOUT_ANSWER, TVOID(result), TSPEC(ind_vm, smx_host_t), TDOUBLE(bound)) sep \
+ACTION(SIMCALL_VM_DESTROY,   vm_destroy,   WITHOUT_ANSWER, TVOID(result), TSPEC(ind_vm, smx_host_t)) sep \
+ACTION(SIMCALL_VM_SUSPEND,   vm_suspend,   WITHOUT_ANSWER, TVOID(result), TSPEC(ind_vm, smx_host_t)) sep \
+ACTION(SIMCALL_VM_RESUME,    vm_resume,    WITHOUT_ANSWER, TVOID(result), TSPEC(ind_vm, smx_host_t)) sep \
+ACTION(SIMCALL_VM_SHUTDOWN,  vm_shutdown,  WITHOUT_ANSWER, TVOID(result), TSPEC(ind_vm, smx_host_t)) sep \
+ACTION(SIMCALL_VM_SAVE,      vm_save,      WITHOUT_ANSWER, TVOID(result), TSPEC(ind_vm, smx_host_t)) sep \
+ACTION(SIMCALL_VM_RESTORE,   vm_restore,   WITHOUT_ANSWER, TVOID(result), TSPEC(ind_vm, smx_host_t)) sep \
 ACTION(SIMCALL_PROCESS_CREATE, process_create, WITH_ANSWER, TVOID(result), TSPEC(process, smx_process_t*), TSTRING(name), TSPEC(code, xbt_main_func_t), TPTR(data), TSTRING(hostname), TDOUBLE(kill_time), TINT(argc), TSPEC(argv, char**), TSPEC(properties, xbt_dict_t), TINT(auto_restart)) sep \
 ACTION(SIMCALL_PROCESS_KILL, process_kill, WITH_ANSWER, TVOID(result), TSPEC(process, smx_process_t)) sep \
 ACTION(SIMCALL_PROCESS_KILLALL, process_killall, WITH_ANSWER, TVOID(result), TINT(reset_pid)) sep \
index aee4eeb..c0eba11 100644 (file)
@@ -23,14 +23,16 @@ static void _SIMIX_sem_wait(smx_sem_t sem, double timeout, smx_process_t issuer,
 static smx_action_t SIMIX_synchro_wait(smx_host_t smx_host, double timeout)
 {
   XBT_IN("(%p, %f)",smx_host,timeout);
+  surf_model_t ws_model = surf_resource_model(smx_host, SURF_WKS_LEVEL);
+
   smx_action_t action;
   action = xbt_mallocator_get(simix_global->action_mallocator);
   action->type = SIMIX_ACTION_SYNCHRO;
   action->name = xbt_strdup("synchro");
   action->synchro.sleep = 
-    surf_workstation_model->extension.workstation.sleep(smx_host, timeout);
+    ws_model->extension.workstation.sleep(smx_host, timeout);
 
-  surf_workstation_model->action_data_set(action->synchro.sleep, action);
+  ws_model->action_data_set(action->synchro.sleep, action);
   XBT_OUT();
   return action;
 }
@@ -70,7 +72,9 @@ void SIMIX_synchro_destroy(smx_action_t action)
 {
   XBT_IN("(%p)",action);
   XBT_DEBUG("Destroying synchro %p", action);
-  action->synchro.sleep->model_type->action_unref(action->synchro.sleep);
+  xbt_assert(action->type == SIMIX_ACTION_SYNCHRO);
+
+  action->synchro.sleep->model_obj->action_unref(action->synchro.sleep);
   xbt_free(action->name);
   xbt_mallocator_release(simix_global->action_mallocator, action);
   XBT_OUT();
@@ -79,9 +83,12 @@ void SIMIX_synchro_destroy(smx_action_t action)
 void SIMIX_post_synchro(smx_action_t action)
 {
   XBT_IN("(%p)",action);
-  if (surf_workstation_model->action_state_get(action->synchro.sleep) == SURF_ACTION_FAILED)
+  xbt_assert(action->type == SIMIX_ACTION_SYNCHRO);
+  surf_model_t ws_model = action->synchro.sleep->model_obj;
+
+  if (ws_model->action_state_get(action->synchro.sleep) == SURF_ACTION_FAILED)
     action->state = SIMIX_FAILED;
-  else if(surf_workstation_model->action_state_get(action->synchro.sleep) == SURF_ACTION_DONE)
+  else if(ws_model->action_state_get(action->synchro.sleep) == SURF_ACTION_DONE)
     action->state = SIMIX_SRC_TIMEOUT;
 
   SIMIX_synchro_finish(action);  
index d42275c..9fc7d4c 100644 (file)
@@ -44,6 +44,28 @@ const char* simcall_host_get_name(smx_host_t host)
   return simcall_BODY_host_get_name(host);
 }
 
+/**
+ * \ingroup simix_host_management
+ * \brief Start the host if it is off
+ *
+ * \param host A SIMIX host
+ */
+void simcall_host_on(smx_host_t host)
+{
+  simcall_BODY_host_on(host);
+}
+
+/**
+ * \ingroup simix_host_management
+ * \brief Stop the host if it is on
+ *
+ * \param host A SIMIX host
+ */
+void simcall_host_off(smx_host_t host)
+{
+  simcall_BODY_host_off(host);
+}
+
 /**
  * \ingroup simix_host_management
  * \brief Returns a dict of the properties assigned to a host.
@@ -161,13 +183,13 @@ void simcall_host_set_data(smx_host_t host, void *data)
 
 smx_action_t simcall_host_execute(const char *name, smx_host_t host,
                                     double computation_amount,
-                                    double priority)
+                                    double priority, double bound)
 {
   /* checking for infinite values */
   xbt_assert(isfinite(computation_amount), "computation_amount is not finite!");
   xbt_assert(isfinite(priority), "priority is not finite!");
   
-  return simcall_BODY_host_execute(name, host, computation_amount, priority);
+  return simcall_BODY_host_execute(name, host, computation_amount, priority, bound);
 }
 
 /**
@@ -277,6 +299,19 @@ void simcall_host_execution_set_priority(smx_action_t execution, double priority
   simcall_BODY_host_execution_set_priority(execution, priority);
 }
 
+/**
+ * \ingroup simix_host_management
+ * \brief Changes the capping (the maximum CPU utilization) of an execution action.
+ *
+ * This functions changes the capping only. It calls a surf function.
+ * \param execution The execution action
+ * \param bound The new bound
+ */
+void simcall_host_execution_set_bound(smx_action_t execution, double bound)
+{
+  simcall_BODY_host_execution_set_bound(execution, bound);
+}
+
 /**
  * \ingroup simix_host_management
  * \brief Waits for the completion of an execution action and destroy it.
@@ -288,6 +323,163 @@ e_smx_state_t simcall_host_execution_wait(smx_action_t execution)
   return simcall_BODY_host_execution_wait(execution);
 }
 
+
+/**
+ * \ingroup simix_vm_management
+ * \brief Create a VM on the given physical host.
+ *
+ * \param name VM name
+ * \param host Physical host
+ *
+ * \return The host object of the VM
+ */
+void* simcall_vm_create(const char *name, smx_host_t phys_host){
+  /* will jump to SIMIX_pre_vm_create() in src/simix/smx_smurf_private.h */
+  return simcall_BODY_vm_create(name, phys_host);
+}
+
+/**
+ * \ingroup simix_vm_management
+ * \brief Start the given VM to the given physical host
+ *
+ * \param vm VM
+ */
+void simcall_vm_start(smx_host_t vm)
+{
+  /* will jump to SIMIX_pre_vm_start in src/simix/smx_smurf_private.h */
+  simcall_BODY_vm_start(vm);
+}
+
+/**
+ * \ingroup simix_vm_management
+ * \brief Get the state of the given VM
+ *
+ * \param vm VM
+ * \return The state of the VM
+ */
+int simcall_vm_get_state(smx_host_t vm)
+{
+  /* will jump to SIMIX_pre_vm_get_state in src/simix/smx_smurf_private.h */
+  return simcall_BODY_vm_get_state(vm);
+}
+
+/**
+ * \ingroup simix_vm_management
+ * \brief Get the name of the physical host on which the given VM runs.
+ *
+ * \param vm VM
+ * \return The name of the physical host
+ */
+void *simcall_vm_get_pm(smx_host_t vm)
+{
+  /* will jump to SIMIX_pre_vm_migrate in src/simix/smx_smurf_private.h */
+  return simcall_BODY_vm_get_pm(vm);
+}
+
+void simcall_vm_set_bound(smx_host_t vm, double bound)
+{
+  /* will jump to SIMIX_pre_vm_set_bound in src/simix/smx_smurf_private.h */
+  simcall_BODY_vm_set_bound(vm, bound);
+}
+
+void simcall_host_get_params(smx_host_t vm, ws_params_t params)
+{
+  /* will jump to SIMIX_pre_host_get_params in src/simix/smx_smurf_private.h */
+  simcall_BODY_host_get_params(vm, params);
+}
+
+void simcall_host_set_params(smx_host_t vm, ws_params_t params)
+{
+  /* will jump to SIMIX_pre_host_set_params in src/simix/smx_smurf_private.h */
+  simcall_BODY_host_set_params(vm, params);
+}
+
+/**
+ * \ingroup simix_vm_management
+ * \brief Migrate the given VM to the given physical host
+ *
+ * \param vm VM
+ * \param host Destination physical host
+ */
+void simcall_vm_migrate(smx_host_t vm, smx_host_t host)
+{
+  /* will jump to SIMIX_pre_vm_migrate in src/simix/smx_smurf_private.h */
+  simcall_BODY_vm_migrate(vm, host);
+}
+
+/**
+ * \ingroup simix_vm_management
+ * \brief Suspend the given VM
+ *
+ * \param vm VM
+ */
+void simcall_vm_suspend(smx_host_t vm)
+{
+  /* will jump to SIMIX_pre_vm_suspend in src/simix/smx_smurf_private.h */
+  simcall_BODY_vm_suspend(vm);
+}
+
+/**
+ * \ingroup simix_vm_management
+ * \brief Resume the given VM
+ *
+ * \param vm VM
+ */
+void simcall_vm_resume(smx_host_t vm)
+{
+  /* will jump to SIMIX_pre_vm_resume in src/simix/smx_smurf_private.h */
+  simcall_BODY_vm_resume(vm);
+}
+
+/**
+ * \ingroup simix_vm_management
+ * \brief Save the given VM
+ *
+ * \param vm VM
+ */
+void simcall_vm_save(smx_host_t vm)
+{
+  /* will jump to SIMIX_pre_vm_save in src/simix/smx_smurf_private.h */
+  simcall_BODY_vm_save(vm);
+}
+
+/**
+ * \ingroup simix_vm_management
+ * \brief Restore the given VM
+ *
+ * \param vm VM
+ */
+void simcall_vm_restore(smx_host_t vm)
+{
+  /* will jump to SIMIX_pre_vm_restore in src/simix/smx_smurf_private.h */
+  simcall_BODY_vm_restore(vm);
+}
+
+/**
+ * \ingroup simix_vm_management
+ * \brief Shutdown the given VM
+ *
+ * \param vm VM
+ */
+void simcall_vm_shutdown(smx_host_t vm)
+{
+  /* will jump to SIMIX_pre_vm_shutdown in src/simix/smx_smurf_private.h */
+  simcall_BODY_vm_shutdown(vm);
+}
+
+/**
+ * \ingroup simix_vm_management
+ * \brief Destroy the given VM
+ *
+ * \param vm VM
+ */
+void simcall_vm_destroy(smx_host_t vm)
+{
+   /* will jump to SIMIX_pre_vm_destroy in src/simix/smx_smurf_private.h */
+  simcall_BODY_vm_destroy(vm);
+}
+
+
 /**
  * \ingroup simix_process_management
  * \brief Creates and runs a new SIMIX process.
diff --git a/src/simix/smx_vm.c b/src/simix/smx_vm.c
new file mode 100644 (file)
index 0000000..f53c188
--- /dev/null
@@ -0,0 +1,393 @@
+/* Copyright (c) 2007-2012. 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 "smx_private.h"
+#include "xbt/sysdep.h"
+#include "xbt/log.h"
+#include "xbt/dict.h"
+#include "mc/mc.h"
+
+//If you need to log some stuffs, just uncomment these two lines and uses XBT_DEBUG for instance
+XBT_LOG_NEW_DEFAULT_SUBCATEGORY(simix_vm, simix, "Logging specific to SIMIX (vms)");
+
+/* **** create a VM **** */
+
+/**
+ * \brief Internal function to create a SIMIX host.
+ * \param name name of the host to create
+ * \param data some user data (may be NULL)
+ */
+smx_host_t SIMIX_vm_create(const char *name, smx_host_t ind_phys_host)
+{
+  /* Create surf associated resource */
+  surf_vm_workstation_model->extension.vm_workstation.create(name, ind_phys_host);
+
+  smx_host_t smx_host = SIMIX_host_create(name, ind_phys_host, NULL);
+
+  /* We will be able to register the VM to its physical host, so that we can promptly
+   * retrieve the list VMs on the physical host. */
+
+  return smx_host;
+}
+
+
+smx_host_t SIMIX_pre_vm_create(smx_simcall_t simcall, const char *name, smx_host_t ind_phys_host)
+{
+  return SIMIX_vm_create(name, ind_phys_host);
+}
+
+
+/* works for VMs and PMs */
+static long host_get_ramsize(smx_host_t vm, int *overcommit)
+{
+  s_ws_params_t params;
+  surf_workstation_model->extension.workstation.get_params(vm, &params);
+
+  if (overcommit)
+    *overcommit = params.overcommit;
+
+  return params.ramsize;
+}
+
+/* **** start a VM **** */
+static int __can_be_started(smx_host_t vm)
+{
+  smx_host_t pm = surf_vm_workstation_model->extension.vm_workstation.get_pm(vm);
+
+  int pm_overcommit = 0;
+  long pm_ramsize = host_get_ramsize(pm, &pm_overcommit);
+  long vm_ramsize = host_get_ramsize(vm, NULL);
+
+  if (!pm_ramsize) {
+    /* We assume users do not want to care about ramsize. */
+    return 1;
+  }
+
+  if (pm_overcommit) {
+    XBT_INFO("%s allows memory overcommit.", pm->key);
+    return 1;
+  }
+
+  long total_ramsize_of_vms = 0;
+  xbt_dynar_t dyn_vms = surf_workstation_model->extension.workstation.get_vms(pm);
+  {
+    unsigned int cursor = 0;
+    smx_host_t another_vm;
+    xbt_dynar_foreach(dyn_vms, cursor, another_vm) {
+      long another_vm_ramsize = host_get_ramsize(vm, NULL);
+      total_ramsize_of_vms += another_vm_ramsize;
+    }
+  }
+
+  if (vm_ramsize > pm_ramsize - total_ramsize_of_vms) {
+    XBT_WARN("cannnot start %s@%s due to memory shortage: vm_ramsize %ld, free %ld, pm_ramsize %ld (bytes).",
+        vm->key, pm->key, vm_ramsize, pm_ramsize - total_ramsize_of_vms, pm_ramsize);
+    xbt_dynar_free(&dyn_vms);
+    return 0;
+  }
+
+  xbt_dynar_free(&dyn_vms);
+       return 1;
+}
+
+void SIMIX_vm_start(smx_host_t ind_vm)
+{
+  if (__can_be_started(ind_vm))
+    SIMIX_vm_set_state(ind_vm, SURF_VM_STATE_RUNNING);
+  else
+    THROWF(vm_error, 0, "The VM %s cannot be started", SIMIX_host_get_name(ind_vm));
+}
+
+
+
+void SIMIX_pre_vm_start(smx_simcall_t simcall, smx_host_t ind_vm)
+{
+  SIMIX_vm_start(ind_vm);
+  SIMIX_simcall_answer(simcall);
+}
+
+/* ***** set/get state of a VM ***** */
+void SIMIX_vm_set_state(smx_host_t ind_vm, int state)
+{
+  /* jump to vm_ws_set_state */
+  surf_vm_workstation_model->extension.vm_workstation.set_state(ind_vm, state);
+}
+
+void SIMIX_pre_vm_set_state(smx_simcall_t simcall, smx_host_t ind_vm, int state)
+{
+  SIMIX_vm_set_state(ind_vm, state);
+}
+
+int SIMIX_vm_get_state(smx_host_t ind_vm)
+{
+  return surf_vm_workstation_model->extension.vm_workstation.get_state(ind_vm);
+}
+
+int SIMIX_pre_vm_get_state(smx_simcall_t simcall, smx_host_t ind_vm)
+{
+  return SIMIX_vm_get_state(ind_vm);
+}
+
+
+/**
+ * \brief Function to migrate a SIMIX VM host. 
+ *
+ * \param host the vm host to migrate (a smx_host_t)
+ */
+void SIMIX_vm_migrate(smx_host_t ind_vm, smx_host_t ind_dst_pm)
+{
+  /* precopy migration makes the VM temporally paused */
+  e_surf_vm_state_t state = SIMIX_vm_get_state(ind_vm);
+  xbt_assert(state == SURF_VM_STATE_SUSPENDED);
+
+  /* jump to vm_ws_migrate(). this will update the vm location. */
+  surf_vm_workstation_model->extension.vm_workstation.migrate(ind_vm, ind_dst_pm);
+}
+
+void SIMIX_pre_vm_migrate(smx_simcall_t simcall, smx_host_t ind_vm, smx_host_t ind_dst_pm)
+{
+  SIMIX_vm_migrate(ind_vm, ind_dst_pm);
+  SIMIX_simcall_answer(simcall);
+}
+
+
+/**
+ * \brief Function to get the physical host of the given SIMIX VM host.
+ *
+ * \param host the vm host to get_phys_host (a smx_host_t)
+ */
+void *SIMIX_vm_get_pm(smx_host_t ind_vm)
+{
+  /* jump to vm_ws_get_pm(). this will return the vm name. */
+  return surf_vm_workstation_model->extension.vm_workstation.get_pm(ind_vm);
+}
+
+void *SIMIX_pre_vm_get_pm(smx_simcall_t simcall, smx_host_t ind_vm)
+{
+  return SIMIX_vm_get_pm(ind_vm);
+}
+
+
+/**
+ * \brief Function to set the CPU bound of the given SIMIX VM host.
+ *
+ * \param host the vm host (a smx_host_t)
+ * \param bound bound (a double)
+ */
+void SIMIX_vm_set_bound(smx_host_t ind_vm, double bound)
+{
+  /* jump to vm_ws_set_vm_bound(). */
+  surf_vm_workstation_model->extension.vm_workstation.set_vm_bound(ind_vm, bound);
+}
+
+void SIMIX_pre_vm_set_bound(smx_simcall_t simcall, smx_host_t ind_vm, double bound)
+{
+  SIMIX_vm_set_bound(ind_vm, bound);
+  SIMIX_simcall_answer(simcall);
+}
+
+
+/**
+ * \brief Function to suspend a SIMIX VM host. This function stops the exection of the
+ * VM. All the processes on this VM will pause. The state of the VM is
+ * preserved on memory. We can later resume it again.
+ *
+ * \param host the vm host to suspend (a smx_host_t)
+ */
+void SIMIX_vm_suspend(smx_host_t ind_vm, smx_process_t issuer)
+{
+  const char *name = SIMIX_host_get_name(ind_vm);
+
+  if (SIMIX_vm_get_state(ind_vm) != SURF_VM_STATE_RUNNING)
+    THROWF(vm_error, 0, "VM(%s) is not running", name);
+
+  XBT_DEBUG("suspend VM(%s), where %d processes exist", name, xbt_swag_size(SIMIX_host_priv(ind_vm)->process_list));
+
+  /* jump to vm_ws_suspend. The state will be set. */
+  surf_vm_workstation_model->extension.vm_workstation.suspend(ind_vm);
+
+  smx_process_t smx_process, smx_process_safe;
+  xbt_swag_foreach_safe(smx_process, smx_process_safe, SIMIX_host_priv(ind_vm)->process_list) {
+    XBT_DEBUG("suspend %s", smx_process->name);
+    SIMIX_process_suspend(smx_process, issuer);
+  }
+
+  XBT_DEBUG("suspend all processes on the VM done done");
+}
+
+void SIMIX_pre_vm_suspend(smx_simcall_t simcall, smx_host_t ind_vm)
+{
+  if (simcall->issuer->smx_host == ind_vm) {
+    XBT_ERROR("cannot suspend the VM where I run");
+    DIE_IMPOSSIBLE;
+  }
+
+  SIMIX_vm_suspend(ind_vm, simcall->issuer);
+
+  /* without this, simcall_vm_suspend() does not return to the userland. why? */
+  SIMIX_simcall_answer(simcall);
+
+  XBT_DEBUG("SIMIX_pre_vm_suspend done");
+}
+
+
+/**
+ * \brief Function to resume a SIMIX VM host. This function restart the execution of the
+ * VM. All the processes on this VM will run again. 
+ *
+ * \param host the vm host to resume (a smx_host_t)
+ */
+void SIMIX_vm_resume(smx_host_t ind_vm, smx_process_t issuer)
+{
+  const char *name = SIMIX_host_get_name(ind_vm);
+
+  if (SIMIX_vm_get_state(ind_vm) != SURF_VM_STATE_SUSPENDED)
+    THROWF(vm_error, 0, "VM(%s) was not suspended", name);
+
+  XBT_DEBUG("resume VM(%s), where %d processes exist", name, xbt_swag_size(SIMIX_host_priv(ind_vm)->process_list));
+
+  /* jump to vm_ws_resume() */
+  surf_vm_workstation_model->extension.vm_workstation.resume(ind_vm);
+
+  smx_process_t smx_process, smx_process_safe;
+  xbt_swag_foreach_safe(smx_process, smx_process_safe, SIMIX_host_priv(ind_vm)->process_list) {
+    XBT_DEBUG("resume %s", smx_process->name);
+    SIMIX_process_resume(smx_process, issuer);
+  }
+}
+
+void SIMIX_pre_vm_resume(smx_simcall_t simcall, smx_host_t ind_vm)
+{
+  SIMIX_vm_resume(ind_vm, simcall->issuer);
+  SIMIX_simcall_answer(simcall);
+}
+
+
+/**
+ * \brief Function to save a SIMIX VM host.
+ * This function is the same as vm_suspend, but the state of the VM is saved to the disk, and not preserved on memory.
+ * We can later restore it again.
+ *
+ * \param host the vm host to save (a smx_host_t)
+ */
+void SIMIX_vm_save(smx_host_t ind_vm, smx_process_t issuer)
+{
+  const char *name = SIMIX_host_get_name(ind_vm);
+
+  if (SIMIX_vm_get_state(ind_vm) != SURF_VM_STATE_RUNNING)
+    THROWF(vm_error, 0, "VM(%s) is not running", name);
+
+
+  XBT_DEBUG("save VM(%s), where %d processes exist", name, xbt_swag_size(SIMIX_host_priv(ind_vm)->process_list));
+
+  /* jump to vm_ws_save() */
+  surf_vm_workstation_model->extension.vm_workstation.save(ind_vm);
+
+  smx_process_t smx_process, smx_process_safe;
+  xbt_swag_foreach_safe(smx_process, smx_process_safe, SIMIX_host_priv(ind_vm)->process_list) {
+    XBT_DEBUG("suspend %s", smx_process->name);
+    SIMIX_process_suspend(smx_process, issuer);
+  }
+}
+
+void SIMIX_pre_vm_save(smx_simcall_t simcall, smx_host_t ind_vm)
+{
+  SIMIX_vm_save(ind_vm, simcall->issuer);
+
+  /* without this, simcall_vm_suspend() does not return to the userland. why? */
+  SIMIX_simcall_answer(simcall);
+}
+
+
+/**
+ * \brief Function to restore a SIMIX VM host. This function restart the execution of the
+ * VM. All the processes on this VM will run again. 
+ *
+ * \param host the vm host to restore (a smx_host_t)
+ */
+void SIMIX_vm_restore(smx_host_t ind_vm, smx_process_t issuer)
+{
+  const char *name = SIMIX_host_get_name(ind_vm);
+
+  if (SIMIX_vm_get_state(ind_vm) != SURF_VM_STATE_SAVED)
+    THROWF(vm_error, 0, "VM(%s) was not saved", name);
+
+  XBT_DEBUG("restore VM(%s), where %d processes exist", name, xbt_swag_size(SIMIX_host_priv(ind_vm)->process_list));
+
+  /* jump to vm_ws_restore() */
+  surf_vm_workstation_model->extension.vm_workstation.resume(ind_vm);
+
+  smx_process_t smx_process, smx_process_safe;
+  xbt_swag_foreach_safe(smx_process, smx_process_safe, SIMIX_host_priv(ind_vm)->process_list) {
+    XBT_DEBUG("resume %s", smx_process->name);
+    SIMIX_process_resume(smx_process, issuer);
+  }
+}
+
+void SIMIX_pre_vm_restore(smx_simcall_t simcall, smx_host_t ind_vm)
+{
+  SIMIX_vm_restore(ind_vm, simcall->issuer);
+  SIMIX_simcall_answer(simcall);
+}
+
+
+/**
+ * \brief Function to shutdown a SIMIX VM host. This function powers off the
+ * VM. All the processes on this VM will be killed. But, the state of the VM is
+ * preserved on memory. We can later start it again.
+ *
+ * \param host the vm host to shutdown (a smx_host_t)
+ */
+void SIMIX_vm_shutdown(smx_host_t ind_vm, smx_process_t issuer)
+{
+  const char *name = SIMIX_host_get_name(ind_vm);
+
+  if (SIMIX_vm_get_state(ind_vm) != SURF_VM_STATE_RUNNING)
+    THROWF(vm_error, 0, "VM(%s) is not running", name);
+
+  XBT_DEBUG("%d processes in the VM", xbt_swag_size(SIMIX_host_priv(ind_vm)->process_list));
+
+  smx_process_t smx_process, smx_process_safe;
+  xbt_swag_foreach_safe(smx_process, smx_process_safe, SIMIX_host_priv(ind_vm)->process_list) {
+    XBT_DEBUG("shutdown %s", name);
+    SIMIX_process_kill(smx_process, issuer);
+  }
+
+  /* FIXME: we may have to do something at the surf layer, e.g., vcpu action */
+  SIMIX_vm_set_state(ind_vm, SURF_VM_STATE_CREATED);
+}
+
+void SIMIX_pre_vm_shutdown(smx_simcall_t simcall, smx_host_t ind_vm)
+{
+  SIMIX_vm_shutdown(ind_vm, simcall->issuer);
+  SIMIX_simcall_answer(simcall);
+}
+
+
+/**
+ * \brief Function to destroy a SIMIX VM host.
+ *
+ * \param host the vm host to destroy (a smx_host_t)
+ */
+void SIMIX_vm_destroy(smx_host_t ind_vm)
+{
+  /* this code basically performs a similar thing like SIMIX_host_destroy() */
+
+  xbt_assert((ind_vm != NULL), "Invalid parameters");
+  const char *hostname = SIMIX_host_get_name(ind_vm);
+
+  /* this will call the registered callback function, i.e., SIMIX_host_destroy().  */
+  xbt_lib_unset(host_lib, hostname, SIMIX_HOST_LEVEL, 1);
+
+  /* jump to vm_ws_destroy(). The surf level resource will be freed. */
+  surf_vm_workstation_model->extension.vm_workstation.destroy(ind_vm);
+}
+
+void SIMIX_pre_vm_destroy(smx_simcall_t simcall, smx_host_t ind_vm)
+{
+  SIMIX_vm_destroy(ind_vm);
+  SIMIX_simcall_answer(simcall);
+}
index f704612..cae096c 100644 (file)
@@ -8,8 +8,11 @@
 #include "surf/surf_resource.h"
 #include "maxmin_private.h"
 #include "simgrid/sg_config.h"
+#include "surf/cpu_cas01_private.h"
 
-surf_model_t surf_cpu_model = NULL;
+/* the model objects for physical machines and virtual machines */
+surf_model_t surf_cpu_model_pm = NULL;
+surf_model_t surf_cpu_model_vm = NULL;
 
 #undef GENERIC_LMM_ACTION
 #undef GENERIC_ACTION
@@ -22,18 +25,6 @@ typedef struct surf_action_cpu_cas01 {
   s_surf_action_lmm_t generic_lmm_action;
 } s_surf_action_cpu_Cas01_t, *surf_action_cpu_Cas01_t;
 
-typedef struct cpu_Cas01 {
-  s_surf_resource_t generic_resource;
-  s_xbt_swag_hookup_t modified_cpu_hookup;
-  double power_peak;
-  double power_scale;
-  tmgr_trace_event_t power_event;
-  int core;
-  e_surf_resource_state_t state_current;
-  tmgr_trace_event_t state_event;
-  lmm_constraint_t constraint;
-} s_cpu_Cas01_t, *cpu_Cas01_t;
-
 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(surf_cpu, surf,
                                 "Logging specific to the SURF CPU IMPROVED module");
 
@@ -41,14 +32,14 @@ static xbt_swag_t
     cpu_running_action_set_that_does_not_need_being_checked = NULL;
 
 
-/* This function is registered as a callback to sg_platf_new_host() and never called directly */
-static void *cpu_create_resource(const char *name, double power_peak,
+void *cpu_cas01_create_resource(const char *name, double power_peak,
                                  double power_scale,
                                  tmgr_trace_t power_trace,
                                  int core,
                                  e_surf_resource_state_t state_initial,
                                  tmgr_trace_t state_trace,
-                                 xbt_dict_t cpu_properties)
+                                 xbt_dict_t cpu_properties,
+                                 surf_model_t cpu_model)
 {
   cpu_Cas01_t cpu = NULL;
 
@@ -56,7 +47,7 @@ static void *cpu_create_resource(const char *name, double power_peak,
              "Host '%s' declared several times in the platform file",
              name);
   cpu = (cpu_Cas01_t) surf_resource_new(sizeof(s_cpu_Cas01_t),
-                                        surf_cpu_model, name,
+                                        cpu_model, name,
                                         cpu_properties);
   cpu->power_peak = power_peak;
   xbt_assert(cpu->power_peak > 0, "Power has to be >0");
@@ -74,7 +65,7 @@ static void *cpu_create_resource(const char *name, double power_peak,
         tmgr_history_add_trace(history, state_trace, 0.0, 0, cpu);
 
   cpu->constraint =
-      lmm_constraint_new(surf_cpu_model->model_private->maxmin_system, cpu,
+      lmm_constraint_new(cpu_model->model_private->maxmin_system, cpu,
                          cpu->core * cpu->power_scale * cpu->power_peak);
 
   xbt_lib_set(host_lib, name, SURF_CPU_LEVEL, cpu);
@@ -85,13 +76,17 @@ static void *cpu_create_resource(const char *name, double power_peak,
 
 static void parse_cpu_init(sg_platf_host_cbarg_t host)
 {
-  cpu_create_resource(host->id,
+  /* This function is called when a platform file is parsed. Physical machines
+   * are defined there. Thus, we use the cpu model object for the physical
+   * machine layer. */
+  cpu_cas01_create_resource(host->id,
                       host->power_peak,
                       host->power_scale,
                       host->power_trace,
                       host->core_amount,
                       host->initial_state,
-                      host->state_trace, host->properties);
+                      host->state_trace, host->properties,
+                      surf_cpu_model_pm);
 }
 
 static void cpu_add_traces_cpu(void)
@@ -127,7 +122,7 @@ static void cpu_add_traces_cpu(void)
   }
 }
 
-static void cpu_define_callbacks()
+static void cpu_define_callbacks_cas01()
 {
   sg_platf_host_add_cb(parse_cpu_init);
   sg_platf_postparse_add_cb(cpu_add_traces_cpu);
@@ -135,34 +130,36 @@ static void cpu_define_callbacks()
 
 static int cpu_resource_used(void *resource)
 {
-  return lmm_constraint_used(surf_cpu_model->model_private->maxmin_system,
+  surf_model_t cpu_model = ((surf_resource_t) resource)->model;
+
+  return lmm_constraint_used(cpu_model->model_private->maxmin_system,
                              ((cpu_Cas01_t) resource)->constraint);
 }
 
-static double cpu_share_resources_lazy(double now)
+static double cpu_share_resources_lazy(surf_model_t cpu_model, double now)
 {
-  return generic_share_resources_lazy(now, surf_cpu_model);
+  return generic_share_resources_lazy(now, cpu_model);
 }
 
-static double cpu_share_resources_full(double now)
+static double cpu_share_resources_full(surf_model_t cpu_model, double now)
 {
   s_surf_action_cpu_Cas01_t action;
-  return generic_maxmin_share_resources(surf_cpu_model->states.
+  return generic_maxmin_share_resources(cpu_model->states.
                                         running_action_set,
                                         xbt_swag_offset(action,
                                                         generic_lmm_action.
                                                         variable),
-                                        surf_cpu_model->model_private->maxmin_system, lmm_solve);
+                                        cpu_model->model_private->maxmin_system, lmm_solve);
 }
 
-static void cpu_update_actions_state_lazy(double now, double delta)
+static void cpu_update_actions_state_lazy(surf_model_t cpu_model, double now, double delta)
 {
-  generic_update_actions_state_lazy(now, delta, surf_cpu_model);
+  generic_update_actions_state_lazy(now, delta, cpu_model);
 }
 
-static void cpu_update_actions_state_full(double now, double delta)
+static void cpu_update_actions_state_full(surf_model_t cpu_model, double now, double delta)
 {
-  generic_update_actions_state_full(now, delta, surf_cpu_model);
+  generic_update_actions_state_full(now, delta, cpu_model);
 }
 
 static void cpu_update_resource_state(void *id,
@@ -172,12 +169,13 @@ static void cpu_update_resource_state(void *id,
   cpu_Cas01_t cpu = id;
   lmm_variable_t var = NULL;
   lmm_element_t elem = NULL;
+  surf_model_t cpu_model = ((surf_resource_t) cpu)->model;
 
   surf_watched_hosts();
 
   if (event_type == cpu->power_event) {
     cpu->power_scale = value;
-    lmm_update_constraint_bound(surf_cpu_model->model_private->maxmin_system, cpu->constraint,
+    lmm_update_constraint_bound(cpu_model->model_private->maxmin_system, cpu->constraint,
                                 cpu->core * cpu->power_scale *
                                 cpu->power_peak);
 #ifdef HAVE_TRACING
@@ -186,9 +184,9 @@ static void cpu_update_resource_state(void *id,
                               cpu->power_peak);
 #endif
     while ((var = lmm_get_var_from_cnst
-            (surf_cpu_model->model_private->maxmin_system, cpu->constraint, &elem))) {
+            (cpu_model->model_private->maxmin_system, cpu->constraint, &elem))) {
       surf_action_cpu_Cas01_t action = lmm_variable_id(var);
-      lmm_update_variable_bound(surf_cpu_model->model_private->maxmin_system,
+      lmm_update_variable_bound(cpu_model->model_private->maxmin_system,
                                 GENERIC_LMM_ACTION(action).variable,
                                 cpu->power_scale * cpu->power_peak);
     }
@@ -202,7 +200,7 @@ static void cpu_update_resource_state(void *id,
 
       cpu->state_current = SURF_RESOURCE_OFF;
 
-      while ((var = lmm_get_var_from_cnst(surf_cpu_model->model_private->maxmin_system, cnst, &elem))) {
+      while ((var = lmm_get_var_from_cnst(cpu_model->model_private->maxmin_system, cnst, &elem))) {
         surf_action_t action = lmm_variable_id(var);
 
         if (surf_action_state_get(action) == SURF_ACTION_RUNNING ||
@@ -228,26 +226,27 @@ static surf_action_t cpu_execute(void *cpu, double size)
 {
   surf_action_cpu_Cas01_t action = NULL;
   cpu_Cas01_t CPU = surf_cpu_resource_priv(cpu);
+  surf_model_t cpu_model = ((surf_resource_t) CPU)->model;
 
   XBT_IN("(%s,%g)", surf_resource_name(CPU), size);
   action =
       surf_action_new(sizeof(s_surf_action_cpu_Cas01_t), size,
-                      surf_cpu_model,
+                      cpu_model,
                       CPU->state_current != SURF_RESOURCE_ON);
 
   GENERIC_LMM_ACTION(action).suspended = 0;     /* Should be useless because of the
                                                    calloc but it seems to help valgrind... */
 
   GENERIC_LMM_ACTION(action).variable =
-      lmm_variable_new(surf_cpu_model->model_private->maxmin_system, action,
+      lmm_variable_new(cpu_model->model_private->maxmin_system, action,
                        GENERIC_ACTION(action).priority,
                        CPU->power_scale * CPU->power_peak, 1);
-  if (surf_cpu_model->model_private->update_mechanism == UM_LAZY) {
+  if (cpu_model->model_private->update_mechanism == UM_LAZY) {
     GENERIC_LMM_ACTION(action).index_heap = -1;
     GENERIC_LMM_ACTION(action).last_update = surf_get_clock();
     GENERIC_LMM_ACTION(action).last_value = 0.0;
   }
-  lmm_expand(surf_cpu_model->model_private->maxmin_system, CPU->constraint,
+  lmm_expand(cpu_model->model_private->maxmin_system, CPU->constraint,
              GENERIC_LMM_ACTION(action).variable, 1.0);
   XBT_OUT();
   return (surf_action_t) action;
@@ -256,6 +255,8 @@ static surf_action_t cpu_execute(void *cpu, double size)
 static surf_action_t cpu_action_sleep(void *cpu, double duration)
 {
   surf_action_cpu_Cas01_t action = NULL;
+  cpu_Cas01_t CPU = surf_cpu_resource_priv(cpu);
+  surf_model_t cpu_model = ((surf_resource_t) CPU)->model;
 
   if (duration > 0)
     duration = MAX(duration, MAXMIN_PRECISION);
@@ -274,14 +275,14 @@ static surf_action_t cpu_action_sleep(void *cpu, double duration)
     xbt_swag_insert(action, ((surf_action_t) action)->state_set);
   }
 
-  lmm_update_variable_weight(surf_cpu_model->model_private->maxmin_system,
+  lmm_update_variable_weight(cpu_model->model_private->maxmin_system,
                              GENERIC_LMM_ACTION(action).variable, 0.0);
-  if (surf_cpu_model->model_private->update_mechanism == UM_LAZY) {     // remove action from the heap
-    surf_action_lmm_heap_remove(surf_cpu_model->model_private->action_heap,(surf_action_lmm_t)action);
+  if (cpu_model->model_private->update_mechanism == UM_LAZY) {     // remove action from the heap
+    surf_action_lmm_heap_remove(cpu_model->model_private->action_heap,(surf_action_lmm_t)action);
     // this is necessary for a variable with weight 0 since such
     // variables are ignored in lmm and we need to set its max_duration
     // correctly at the next call to share_resources
-    xbt_swag_insert_at_head(action,surf_cpu_model->model_private->modified_set);
+    xbt_swag_insert_at_head(action, cpu_model->model_private->modified_set);
   }
 
   XBT_OUT();
@@ -293,6 +294,11 @@ static e_surf_resource_state_t cpu_get_state(void *cpu)
   return ((cpu_Cas01_t)surf_cpu_resource_priv(cpu))->state_current;
 }
 
+static void cpu_set_state(void *cpu, e_surf_resource_state_t state)
+{
+  ((cpu_Cas01_t)surf_cpu_resource_priv(cpu))->state_current = state;
+}
+
 static double cpu_get_speed(void *cpu, double load)
 {
   return load * ((cpu_Cas01_t)surf_cpu_resource_priv(cpu))->power_peak;
@@ -302,31 +308,29 @@ static int cpu_get_core(void *cpu)
 {
   return ((cpu_Cas01_t)surf_cpu_resource_priv(cpu))->core;
 }
-
-
 static double cpu_get_available_speed(void *cpu)
 {
   /* number between 0 and 1 */
   return ((cpu_Cas01_t)surf_cpu_resource_priv(cpu))->power_scale;
 }
 
-static void cpu_finalize(void)
+static void cpu_finalize(surf_model_t cpu_model)
 {
-  lmm_system_free(surf_cpu_model->model_private->maxmin_system);
-  surf_cpu_model->model_private->maxmin_system = NULL;
+  lmm_system_free(cpu_model->model_private->maxmin_system);
+  cpu_model->model_private->maxmin_system = NULL;
 
-  if (surf_cpu_model->model_private->action_heap)
-    xbt_heap_free(surf_cpu_model->model_private->action_heap);
-  xbt_swag_free(surf_cpu_model->model_private->modified_set);
+  if (cpu_model->model_private->action_heap)
+    xbt_heap_free(cpu_model->model_private->action_heap);
+  xbt_swag_free(cpu_model->model_private->modified_set);
 
-  surf_model_exit(surf_cpu_model);
-  surf_cpu_model = NULL;
+  surf_model_exit(cpu_model);
+  cpu_model = NULL;
 
   xbt_swag_free(cpu_running_action_set_that_does_not_need_being_checked);
   cpu_running_action_set_that_does_not_need_being_checked = NULL;
 }
 
-static void surf_cpu_model_init_internal()
+static surf_model_t surf_cpu_model_init_cas01(void)
 {
   s_surf_action_t action;
   s_surf_action_cpu_Cas01_t comp;
@@ -335,14 +339,14 @@ static void surf_cpu_model_init_internal()
   int select =
       xbt_cfg_get_boolean(_sg_cfg_set, "cpu/maxmin_selective_update");
 
-  surf_cpu_model = surf_model_init();
+  surf_model_t cpu_model = surf_model_init();
 
   if (!strcmp(optim, "Full")) {
-    surf_cpu_model->model_private->update_mechanism = UM_FULL;
-    surf_cpu_model->model_private->selective_update = select;
+    cpu_model->model_private->update_mechanism = UM_FULL;
+    cpu_model->model_private->selective_update = select;
   } else if (!strcmp(optim, "Lazy")) {
-    surf_cpu_model->model_private->update_mechanism = UM_LAZY;
-    surf_cpu_model->model_private->selective_update = 1;
+    cpu_model->model_private->update_mechanism = UM_LAZY;
+    cpu_model->model_private->selective_update = 1;
     xbt_assert((select == 1)
                ||
                (xbt_cfg_is_default_value
@@ -355,62 +359,67 @@ static void surf_cpu_model_init_internal()
   cpu_running_action_set_that_does_not_need_being_checked =
       xbt_swag_new(xbt_swag_offset(action, state_hookup));
 
-  surf_cpu_model->name = "cpu";
+  cpu_model->name = "cpu";
+  cpu_model->type = SURF_MODEL_TYPE_CPU;
 
-  surf_cpu_model->action_unref = surf_action_unref;
-  surf_cpu_model->action_cancel = surf_action_cancel;
-  surf_cpu_model->action_state_set = surf_action_state_set;
+  cpu_model->action_unref = surf_action_unref;
+  cpu_model->action_cancel = surf_action_cancel;
+  cpu_model->action_state_set = surf_action_state_set;
 
-  surf_cpu_model->model_private->resource_used = cpu_resource_used;
+  cpu_model->model_private->resource_used = cpu_resource_used;
 
-  if (surf_cpu_model->model_private->update_mechanism == UM_LAZY) {
-    surf_cpu_model->model_private->share_resources =
+  if (cpu_model->model_private->update_mechanism == UM_LAZY) {
+    cpu_model->model_private->share_resources =
         cpu_share_resources_lazy;
-    surf_cpu_model->model_private->update_actions_state =
+    cpu_model->model_private->update_actions_state =
         cpu_update_actions_state_lazy;
-  } else if (surf_cpu_model->model_private->update_mechanism == UM_FULL) {
-    surf_cpu_model->model_private->share_resources =
+  } else if (cpu_model->model_private->update_mechanism == UM_FULL) {
+    cpu_model->model_private->share_resources =
         cpu_share_resources_full;
-    surf_cpu_model->model_private->update_actions_state =
+    cpu_model->model_private->update_actions_state =
         cpu_update_actions_state_full;
   } else
     xbt_die("Invalid cpu update mechanism!");
 
-  surf_cpu_model->model_private->update_resource_state =
+  cpu_model->model_private->update_resource_state =
       cpu_update_resource_state;
-  surf_cpu_model->model_private->finalize = cpu_finalize;
-
-  surf_cpu_model->suspend = surf_action_suspend;
-  surf_cpu_model->resume = surf_action_resume;
-  surf_cpu_model->is_suspended = surf_action_is_suspended;
-  surf_cpu_model->set_max_duration = surf_action_set_max_duration;
-  surf_cpu_model->set_priority = surf_action_set_priority;
+  cpu_model->model_private->finalize = cpu_finalize;
+
+  cpu_model->suspend = surf_action_suspend;
+  cpu_model->resume = surf_action_resume;
+  cpu_model->is_suspended = surf_action_is_suspended;
+  cpu_model->set_max_duration = surf_action_set_max_duration;
+  cpu_model->set_priority = surf_action_set_priority;
+  cpu_model->set_bound = surf_action_set_bound;
 #ifdef HAVE_TRACING
-  surf_cpu_model->set_category = surf_action_set_category;
+  cpu_model->set_category = surf_action_set_category;
 #endif
-  surf_cpu_model->get_remains = surf_action_get_remains;
+  cpu_model->get_remains = surf_action_get_remains;
 
-  surf_cpu_model->extension.cpu.execute = cpu_execute;
-  surf_cpu_model->extension.cpu.sleep = cpu_action_sleep;
+  cpu_model->extension.cpu.execute = cpu_execute;
+  cpu_model->extension.cpu.sleep = cpu_action_sleep;
 
-  surf_cpu_model->extension.cpu.get_state = cpu_get_state;
-  surf_cpu_model->extension.cpu.get_core = cpu_get_core;
-  surf_cpu_model->extension.cpu.get_speed = cpu_get_speed;
-  surf_cpu_model->extension.cpu.get_available_speed =
+  cpu_model->extension.cpu.get_state = cpu_get_state;
+  cpu_model->extension.cpu.set_state = cpu_set_state;
+  cpu_model->extension.cpu.get_core = cpu_get_core;
+  cpu_model->extension.cpu.get_speed = cpu_get_speed;
+  cpu_model->extension.cpu.get_available_speed =
       cpu_get_available_speed;
-  surf_cpu_model->extension.cpu.add_traces = cpu_add_traces_cpu;
+  cpu_model->extension.cpu.add_traces = cpu_add_traces_cpu;
 
-  if (!surf_cpu_model->model_private->maxmin_system) {
-    surf_cpu_model->model_private->maxmin_system = lmm_system_new(surf_cpu_model->model_private->selective_update);
+  if (!cpu_model->model_private->maxmin_system) {
+    cpu_model->model_private->maxmin_system = lmm_system_new(cpu_model->model_private->selective_update);
   }
-  if (surf_cpu_model->model_private->update_mechanism == UM_LAZY) {
-    surf_cpu_model->model_private->action_heap = xbt_heap_new(8, NULL);
-    xbt_heap_set_update_callback(surf_cpu_model->model_private->action_heap,
+  if (cpu_model->model_private->update_mechanism == UM_LAZY) {
+    cpu_model->model_private->action_heap = xbt_heap_new(8, NULL);
+    xbt_heap_set_update_callback(cpu_model->model_private->action_heap,
         surf_action_lmm_update_index_heap);
-    surf_cpu_model->model_private->modified_set =
+    cpu_model->model_private->modified_set =
         xbt_swag_new(xbt_swag_offset(comp, generic_lmm_action.action_list_hookup));
-    surf_cpu_model->model_private->maxmin_system->keep_track = surf_cpu_model->model_private->modified_set;
+    cpu_model->model_private->maxmin_system->keep_track = cpu_model->model_private->modified_set;
   }
+
+  return cpu_model;
 }
 
 /*********************************************************************/
@@ -429,19 +438,38 @@ static void surf_cpu_model_init_internal()
 /*                  \url{http://grail.sdsc.edu/papers/simgrid_ccgrid01.ps.gz}." */
 /* } */
 
-void surf_cpu_model_init_Cas01()
+
+void surf_cpu_model_init_Cas01(void)
 {
   char *optim = xbt_cfg_get_string(_sg_cfg_set, "cpu/optim");
 
-  if (surf_cpu_model)
-    return;
+  xbt_assert(!surf_cpu_model_pm);
+  xbt_assert(!surf_cpu_model_vm);
 
-  if (!strcmp(optim, "TI")) {
-    surf_cpu_model_init_ti();
-    return;
+  if (strcmp(optim, "TI") == 0) {
+    /* FIXME: do we have to supprot TI? for VM */
+    surf_cpu_model_pm = surf_cpu_model_init_ti();
+    XBT_INFO("TI model is used (it will crashed since this is the hypervisor branch)");
+  } else {
+    surf_cpu_model_pm  = surf_cpu_model_init_cas01();
+    surf_cpu_model_vm  = surf_cpu_model_init_cas01();
+
+    /* cpu_model is registered only to model_list, and not to
+     * model_list_invoke. The shared_resource callback function will be called
+     * from that of the workstation model. */
+    xbt_dynar_push(model_list, &surf_cpu_model_pm);
+    xbt_dynar_push(model_list, &surf_cpu_model_vm);
+
+    cpu_define_callbacks_cas01();
   }
+}
 
-  surf_cpu_model_init_internal();
-  cpu_define_callbacks();
-  xbt_dynar_push(model_list, &surf_cpu_model);
+/* TODO: do we address nested virtualization later? */
+#if 0
+surf_model_t cpu_model_cas01(int level){
+       // TODO this table should be allocated
+       if(!surf_cpu_model[level])
+        // allocate it
+       return surf_cpu_model[level];
 }
+#endif
diff --git a/src/surf/cpu_cas01_private.h b/src/surf/cpu_cas01_private.h
new file mode 100644 (file)
index 0000000..5d84572
--- /dev/null
@@ -0,0 +1,33 @@
+
+/* Copyright (c) 2013. 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. */
+
+#ifndef _SURF_CPU_CAS01_PRIVATE_H
+#define _SURF_CPU_CAS01_PRIVATE_H
+
+typedef struct cpu_Cas01 {
+  s_surf_resource_t generic_resource;
+  s_xbt_swag_hookup_t modified_cpu_hookup;
+  double power_peak;
+  double power_scale;
+  tmgr_trace_event_t power_event;
+  int core;
+  e_surf_resource_state_t state_current;
+  tmgr_trace_event_t state_event;
+  lmm_constraint_t constraint;
+} s_cpu_Cas01_t, *cpu_Cas01_t;
+
+void *cpu_cas01_create_resource(const char *name,
+    double power_peak,
+    double power_scale,
+    tmgr_trace_t power_trace,
+    int core,
+    e_surf_resource_state_t state_initial,
+    tmgr_trace_t state_trace,
+    xbt_dict_t cpu_properties,
+    surf_model_t cpu_model);
+
+#endif                          /* _SURF_CPU_CAS01_PRIVATE_H */
index b44fd4d..8ba0f40 100644 (file)
@@ -148,7 +148,8 @@ static void* cpu_ti_create_resource(const char *name, double power_peak,
                            int core,
                            e_surf_resource_state_t state_initial,
                            tmgr_trace_t state_trace,
-                           xbt_dict_t cpu_properties)
+                           xbt_dict_t cpu_properties,
+                           surf_model_t cpu_model)
 {
   tmgr_trace_t empty_trace;
   s_tmgr_event_t val;
@@ -160,7 +161,7 @@ static void* cpu_ti_create_resource(const char *name, double power_peak,
               name);
   xbt_assert(core==1,"Multi-core not handled with this model yet");
   cpu = (cpu_ti_t) surf_resource_new(sizeof(s_cpu_ti_t),
-          surf_cpu_model, name,cpu_properties);
+          cpu_model, name,cpu_properties);
   cpu->action_set =
       xbt_swag_new(xbt_swag_offset(ti_action, cpu_list_hookup));
   cpu->power_peak = power_peak;
@@ -198,7 +199,8 @@ static void parse_cpu_ti_init(sg_platf_host_cbarg_t host)
         host->core_amount,
         host->initial_state,
         host->state_trace,
-        host->properties);
+        host->properties,
+        surf_cpu_model_pm);
 
 }
 
@@ -311,7 +313,7 @@ static void cpu_ti_action_state_set(surf_action_t action,
 * \param  cpu    Cpu on which the actions are running
 * \param  now    Current time
 */
-static void cpu_ti_update_remaining_amount(cpu_ti_t cpu, double now)
+static void cpu_ti_update_remaining_amount(surf_model_t cpu_model, cpu_ti_t cpu, double now)
 {
   double area_total;
   surf_action_cpu_ti_t action;
@@ -331,7 +333,7 @@ static void cpu_ti_update_remaining_amount(cpu_ti_t cpu, double now)
     surf_action_t generic = (surf_action_t)action;
     /* action not running, skip it */
     if (generic->state_set !=
-        surf_cpu_model->states.running_action_set)
+        cpu_model->states.running_action_set)
       continue;
 
     /* bogus priority, skip it */
@@ -368,19 +370,19 @@ static void cpu_ti_update_remaining_amount(cpu_ti_t cpu, double now)
 * \param  cpu    Cpu on which the actions are running
 * \param  now    Current time
 */
-static void cpu_ti_update_action_finish_date(cpu_ti_t cpu, double now)
+static void cpu_ti_update_action_finish_date(surf_model_t cpu_model, cpu_ti_t cpu, double now)
 {
 #define GENERIC_ACTION(action) action->generic_action
   surf_action_cpu_ti_t action;
   double sum_priority = 0.0, total_area, min_finish = -1;
 
 /* update remaning amount of actions */
-  cpu_ti_update_remaining_amount(cpu, now);
+  cpu_ti_update_remaining_amount(cpu_model, cpu, now);
 
   xbt_swag_foreach(action, cpu->action_set) {
     /* action not running, skip it */
     if (GENERIC_ACTION(action).state_set !=
-        surf_cpu_model->states.running_action_set)
+        cpu_model->states.running_action_set)
       continue;
 
     /* bogus priority, skip it */
@@ -399,7 +401,7 @@ static void cpu_ti_update_action_finish_date(cpu_ti_t cpu, double now)
     min_finish = -1;
     /* action not running, skip it */
     if (GENERIC_ACTION(action).state_set !=
-        surf_cpu_model->states.running_action_set)
+        cpu_model->states.running_action_set)
       continue;
 
     /* verify if the action is really running on cpu */
@@ -451,14 +453,20 @@ static void cpu_ti_update_action_finish_date(cpu_ti_t cpu, double now)
 #undef GENERIC_ACTION
 }
 
-static double cpu_ti_share_resources(double now)
+static double cpu_ti_share_resources(surf_model_t cpu_model, double now)
 {
   cpu_ti_t cpu, cpu_next;
   double min_action_duration = -1;
 
 /* iterates over modified cpus to update share resources */
   xbt_swag_foreach_safe(cpu, cpu_next, cpu_ti_modified_cpu) {
-    cpu_ti_update_action_finish_date(cpu, now);
+    /* FIXME: cpu_ti_modified_cpu is a global object. But, now we have multiple
+     * cpu_model objects in the system. Do we have to create this
+     * swag for each cpu model object?
+     *
+     * We should revisit here after we know what cpu_ti is.
+     **/
+    cpu_ti_update_action_finish_date(cpu_model, cpu, now);
   }
 /* get the min next event if heap not empty */
   if (xbt_heap_size(cpu_ti_action_heap) > 0)
@@ -469,8 +477,10 @@ static double cpu_ti_share_resources(double now)
   return min_action_duration;
 }
 
-static void cpu_ti_update_actions_state(double now, double delta)
+static void cpu_ti_update_actions_state(surf_model_t cpu_model, double now, double delta)
 {
+  /* FIXME: cpu_ti_action_heap is global. Is this okay for VM support? */
+
 #define GENERIC_ACTION(action) action->generic_action
   surf_action_cpu_ti_t action;
   while ((xbt_heap_size(cpu_ti_action_heap) > 0)
@@ -482,7 +492,7 @@ static void cpu_ti_update_actions_state(double now, double delta)
     GENERIC_ACTION(action).remains = 0;
     cpu_ti_action_state_set((surf_action_t) action, SURF_ACTION_DONE);
     /* update remaining amout of all actions */
-    cpu_ti_update_remaining_amount(surf_cpu_resource_priv(action->cpu), surf_get_clock());
+    cpu_ti_update_remaining_amount(cpu_model, surf_cpu_resource_priv(action->cpu), surf_get_clock());
   }
 #undef GENERIC_ACTION
 }
@@ -492,6 +502,7 @@ static void cpu_ti_update_resource_state(void *id,
                                          double value, double date)
 {
   cpu_ti_t cpu = id;
+  surf_model_t cpu_model = ((surf_resource_t) cpu)->model;
   surf_action_cpu_ti_t action;
 
   surf_watched_hosts();
@@ -504,7 +515,7 @@ static void cpu_ti_update_resource_state(void *id,
     XBT_DEBUG("Finish trace date: %lf value %lf date %lf", surf_get_clock(),
            value, date);
     /* update remaining of actions and put in modified cpu swag */
-    cpu_ti_update_remaining_amount(cpu, date);
+    cpu_ti_update_remaining_amount(cpu_model, cpu, date);
     xbt_swag_insert(cpu, cpu_ti_modified_cpu);
 
     power_trace = cpu->avail_trace->power_trace;
@@ -564,10 +575,11 @@ static surf_action_t cpu_ti_execute(void *cpu, double size)
 {
   surf_action_cpu_ti_t action = NULL;
   cpu_ti_t CPU = surf_cpu_resource_priv(cpu);
+  surf_model_t cpu_model = ((surf_resource_t) CPU)->model;
 
   XBT_IN("(%s,%g)", surf_resource_name(CPU), size);
   action =
-      surf_action_new(sizeof(s_surf_action_cpu_ti_t), size, surf_cpu_model,
+      surf_action_new(sizeof(s_surf_action_cpu_ti_t), size, cpu_model,
                       CPU->state_current != SURF_RESOURCE_ON);
   action->cpu = cpu;
   action->index_heap = -1;
@@ -679,9 +691,10 @@ static void cpu_ti_action_set_priority(surf_action_t action,
 
 static double cpu_ti_action_get_remains(surf_action_t action)
 {
+  surf_model_t cpu_model = action->model_obj;
   XBT_IN("(%p)", action);
-  cpu_ti_update_remaining_amount((cpu_ti_t)
-                                 ((surf_action_cpu_ti_t) action)->cpu,
+
+  cpu_ti_update_remaining_amount(cpu_model, (cpu_ti_t) ((surf_action_cpu_ti_t) action)->cpu,
                                  surf_get_clock());
   XBT_OUT();
   return action->remains;
@@ -692,6 +705,11 @@ static e_surf_resource_state_t cpu_ti_get_state(void *cpu)
   return ((cpu_ti_t)surf_cpu_resource_priv(cpu))->state_current;
 }
 
+static void cpu_ti_set_state(void *cpu, e_surf_resource_state_t state)
+{
+  ((cpu_ti_t)surf_cpu_resource_priv(cpu))->state_current = state;
+}
+
 static double cpu_ti_get_speed(void *cpu, double load)
 {
   return load * ((cpu_ti_t)surf_cpu_resource_priv(cpu))->power_peak;
@@ -729,12 +747,15 @@ static double cpu_ti_get_available_speed(void *cpu)
   return CPU->power_scale;
 }
 
-static void cpu_ti_finalize(void)
+static void cpu_ti_finalize(surf_model_t cpu_model)
 {
   void **cpu;
   xbt_lib_cursor_t cursor;
   char *key;
 
+  /* FIXME: we should update this code for VM support */
+  xbt_abort();
+
   xbt_lib_foreach(host_lib, cursor, key, cpu){
     if(cpu[SURF_CPU_LEVEL])
     {
@@ -744,8 +765,8 @@ static void cpu_ti_finalize(void)
     }
   }
 
-  surf_model_exit(surf_cpu_model);
-  surf_cpu_model = NULL;
+  surf_model_exit(cpu_model);
+  cpu_model = NULL;
 
   xbt_swag_free
       (cpu_ti_running_action_set_that_does_not_need_being_checked);
@@ -754,12 +775,12 @@ static void cpu_ti_finalize(void)
   xbt_heap_free(cpu_ti_action_heap);
 }
 
-static void surf_cpu_ti_model_init_internal(void)
+static surf_model_t surf_cpu_ti_model_init_internal(void)
 {
   s_surf_action_t action;
   s_cpu_ti_t cpu;
 
-  surf_cpu_model = surf_model_init();
+  surf_model_t cpu_model = surf_model_init();
 
   cpu_ti_running_action_set_that_does_not_need_being_checked =
       xbt_swag_new(xbt_swag_offset(action, state_hookup));
@@ -767,48 +788,52 @@ static void surf_cpu_ti_model_init_internal(void)
   cpu_ti_modified_cpu =
       xbt_swag_new(xbt_swag_offset(cpu, modified_cpu_hookup));
 
-  surf_cpu_model->name = "cpu_ti";
+  cpu_model->name = "cpu_ti";
+  cpu_model->type = SURF_MODEL_TYPE_CPU;
 
-  surf_cpu_model->action_unref = cpu_ti_action_unref;
-  surf_cpu_model->action_cancel = cpu_ti_action_cancel;
-  surf_cpu_model->action_state_set = cpu_ti_action_state_set;
+  cpu_model->action_unref = cpu_ti_action_unref;
+  cpu_model->action_cancel = cpu_ti_action_cancel;
+  cpu_model->action_state_set = cpu_ti_action_state_set;
 
-  surf_cpu_model->model_private->resource_used = cpu_ti_resource_used;
-  surf_cpu_model->model_private->share_resources = cpu_ti_share_resources;
-  surf_cpu_model->model_private->update_actions_state =
+  cpu_model->model_private->resource_used = cpu_ti_resource_used;
+  cpu_model->model_private->share_resources = cpu_ti_share_resources;
+  cpu_model->model_private->update_actions_state =
       cpu_ti_update_actions_state;
-  surf_cpu_model->model_private->update_resource_state =
+  cpu_model->model_private->update_resource_state =
       cpu_ti_update_resource_state;
-  surf_cpu_model->model_private->finalize = cpu_ti_finalize;
-
-  surf_cpu_model->suspend = cpu_ti_action_suspend;
-  surf_cpu_model->resume = cpu_ti_action_resume;
-  surf_cpu_model->is_suspended = cpu_ti_action_is_suspended;
-  surf_cpu_model->set_max_duration = cpu_ti_action_set_max_duration;
-  surf_cpu_model->set_priority = cpu_ti_action_set_priority;
-  surf_cpu_model->get_remains = cpu_ti_action_get_remains;
-
-  surf_cpu_model->extension.cpu.execute = cpu_ti_execute;
-  surf_cpu_model->extension.cpu.sleep = cpu_ti_action_sleep;
-
-  surf_cpu_model->extension.cpu.get_state = cpu_ti_get_state;
-  surf_cpu_model->extension.cpu.get_speed = cpu_ti_get_speed;
-  surf_cpu_model->extension.cpu.get_available_speed =
+  cpu_model->model_private->finalize = cpu_ti_finalize;
+
+  cpu_model->suspend = cpu_ti_action_suspend;
+  cpu_model->resume = cpu_ti_action_resume;
+  cpu_model->is_suspended = cpu_ti_action_is_suspended;
+  cpu_model->set_max_duration = cpu_ti_action_set_max_duration;
+  cpu_model->set_priority = cpu_ti_action_set_priority;
+  cpu_model->get_remains = cpu_ti_action_get_remains;
+
+  cpu_model->extension.cpu.execute = cpu_ti_execute;
+  cpu_model->extension.cpu.sleep = cpu_ti_action_sleep;
+
+  cpu_model->extension.cpu.get_state = cpu_ti_get_state;
+  cpu_model->extension.cpu.set_state = cpu_ti_set_state;
+  cpu_model->extension.cpu.get_speed = cpu_ti_get_speed;
+  cpu_model->extension.cpu.get_available_speed =
       cpu_ti_get_available_speed;
-  surf_cpu_model->extension.cpu.add_traces = add_traces_cpu_ti;
+  cpu_model->extension.cpu.add_traces = add_traces_cpu_ti;
 
   cpu_ti_action_heap = xbt_heap_new(8, NULL);
   xbt_heap_set_update_callback(cpu_ti_action_heap,
                                cpu_ti_action_update_index_heap);
 
+  return cpu_model;
 }
 
-void surf_cpu_model_init_ti()
+surf_model_t surf_cpu_model_init_ti(void)
 {
-  xbt_assert(!surf_cpu_model,"CPU model already initialized. This should not happen.");
-  surf_cpu_ti_model_init_internal();
+  surf_model_t cpu_model = surf_cpu_ti_model_init_internal();
   cpu_ti_define_callbacks();
-  xbt_dynar_push(model_list, &surf_cpu_model);
+  xbt_dynar_push(model_list, &cpu_model);
+
+  return cpu_model;
 }
 
 
index 04c5763..1646c58 100644 (file)
@@ -325,18 +325,18 @@ int net_get_link_latency_limited(surf_action_t action)
 }
 #endif
 
-static double net_share_resources_full(double now)
+static double net_share_resources_full(surf_model_t network_model, double now)
 {
   s_surf_action_lmm_t s_action;
   surf_action_network_CM02_t action = NULL;
   xbt_swag_t running_actions =
-      surf_network_model->states.running_action_set;
+      network_model->states.running_action_set;
   double min;
 
   min = generic_maxmin_share_resources(running_actions,
                                        xbt_swag_offset(s_action,
                                                        variable),
-                                                       surf_network_model->model_private->maxmin_system,
+                                                       network_model->model_private->maxmin_system,
                                        network_solve);
 
 #define VARIABLE(action) (*((lmm_variable_t*)(((char *) (action)) + xbt_swag_offset(s_action, variable)  )))
@@ -359,19 +359,19 @@ static double net_share_resources_full(double now)
   return min;
 }
 
-static double net_share_resources_lazy(double now)
+static double net_share_resources_lazy(surf_model_t network_model, double now)
 {
-  return generic_share_resources_lazy(now, surf_network_model);
+  return generic_share_resources_lazy(now, network_model);
 }
 
-static void net_update_actions_state_full(double now, double delta)
+static void net_update_actions_state_full(surf_model_t network_model, double now, double delta)
 {
-  generic_update_actions_state_full(now, delta, surf_network_model);
+  generic_update_actions_state_full(now, delta, network_model);
 }
 
-static void net_update_actions_state_lazy(double now, double delta)
+static void net_update_actions_state_lazy(surf_model_t network_model, double now, double delta)
 {
-  generic_update_actions_state_lazy(now, delta, surf_network_model);
+  generic_update_actions_state_lazy(now, delta, network_model);
 }
 
 static void net_update_resource_state(void *id,
@@ -652,18 +652,18 @@ static int net_link_shared(const void *link)
       lmm_constraint_is_shared(((surf_resource_lmm_t) link)->constraint);
 }
 
-static void net_finalize(void)
+static void net_finalize(surf_model_t network_model)
 {
-  lmm_system_free(surf_network_model->model_private->maxmin_system);
-  surf_network_model->model_private->maxmin_system = NULL;
+  lmm_system_free(network_model->model_private->maxmin_system);
+  network_model->model_private->maxmin_system = NULL;
 
-  if (surf_network_model->model_private->update_mechanism == UM_LAZY) {
-    xbt_heap_free(surf_network_model->model_private->action_heap);
-    xbt_swag_free(surf_network_model->model_private->modified_set);
+  if (network_model->model_private->update_mechanism == UM_LAZY) {
+    xbt_heap_free(network_model->model_private->action_heap);
+    xbt_swag_free(network_model->model_private->modified_set);
   }
 
-  surf_model_exit(surf_network_model);
-  surf_network_model = NULL;
+  surf_model_exit(network_model);
+  network_model = NULL;
 
   xbt_dict_free(&gap_lookup);
   xbt_dynar_free(&smpi_bw_factor);
@@ -762,6 +762,7 @@ static void surf_network_model_init_internal(void)
   set_update_mechanism();
 
   surf_network_model->name = "network";
+  surf_network_model->type = SURF_MODEL_TYPE_NETWORK;
   surf_network_model->action_unref = surf_action_unref;
   surf_network_model->action_cancel = surf_action_cancel;
   surf_network_model->action_recycle = net_action_recycle;
@@ -795,7 +796,11 @@ static void surf_network_model_init_internal(void)
   surf_network_model->suspend = surf_action_suspend;
   surf_network_model->resume = surf_action_resume;
   surf_network_model->is_suspended = surf_action_is_suspended;
-  surf_cpu_model->set_max_duration = surf_action_set_max_duration;
+
+  xbt_assert(surf_cpu_model_pm);
+  xbt_assert(surf_cpu_model_vm);
+  surf_cpu_model_pm->set_max_duration = surf_action_set_max_duration;
+  surf_cpu_model_vm->set_max_duration = surf_action_set_max_duration;
 
   surf_network_model->extension.network.communicate = net_communicate;
   surf_network_model->extension.network.get_route = net_get_route;
index 5dcff1b..6227ea2 100644 (file)
@@ -50,11 +50,11 @@ static void netcste_action_cancel(surf_action_t action)
   return;
 }
 
-static double netcste_share_resources(double now)
+static double netcste_share_resources(surf_model_t network_model, double now)
 {
   surf_action_network_Constant_t action = NULL;
   xbt_swag_t running_actions =
-      surf_network_model->states.running_action_set;
+      network_model->states.running_action_set;
   double min = -1.0;
 
   xbt_swag_foreach(action, running_actions) {
@@ -69,12 +69,12 @@ static double netcste_share_resources(double now)
   return min;
 }
 
-static void netcste_update_actions_state(double now, double delta)
+static void netcste_update_actions_state(surf_model_t network_model, double now, double delta)
 {
   surf_action_network_Constant_t action = NULL;
   surf_action_network_Constant_t next_action = NULL;
   xbt_swag_t running_actions =
-      surf_network_model->states.running_action_set;
+      network_model->states.running_action_set;
 
   xbt_swag_foreach_safe(action, next_action, running_actions) {
     if (action->latency > 0) {
@@ -91,12 +91,12 @@ static void netcste_update_actions_state(double now, double delta)
 
     if (action->generic_action.remains <= 0) {
       action->generic_action.finish = surf_get_clock();
-      surf_network_model->action_state_set((surf_action_t) action,
+      network_model->action_state_set((surf_action_t) action,
                                            SURF_ACTION_DONE);
     } else if ((action->generic_action.max_duration != NO_MAX_DURATION)
                && (action->generic_action.max_duration <= 0)) {
       action->generic_action.finish = surf_get_clock();
-      surf_network_model->action_state_set((surf_action_t) action,
+      network_model->action_state_set((surf_action_t) action,
                                            SURF_ACTION_DONE);
     }
   }
@@ -181,10 +181,10 @@ static int netcste_action_is_suspended(surf_action_t action)
   return ((surf_action_network_Constant_t) action)->suspended;
 }
 
-static void netcste_finalize(void)
+static void netcste_finalize(surf_model_t network_model)
 {
-  surf_model_exit(surf_network_model);
-  surf_network_model = NULL;
+  surf_model_exit(network_model);
+  network_model = NULL;
 }
 
 
@@ -217,7 +217,11 @@ void surf_network_model_init_Constant()
   surf_network_model->suspend = netcste_action_suspend;
   surf_network_model->resume = netcste_action_resume;
   surf_network_model->is_suspended = netcste_action_is_suspended;
-  surf_cpu_model->set_max_duration = surf_action_set_max_duration;
+
+  xbt_assert(surf_cpu_model_pm);
+  xbt_assert(surf_cpu_model_vm);
+  surf_cpu_model_pm->set_max_duration = surf_action_set_max_duration;
+  surf_cpu_model_vm->set_max_duration = surf_action_set_max_duration;
 
   surf_network_model->extension.network.communicate = netcste_communicate;
   surf_network_model->extension.network.get_link_bandwidth =
index 8207982..0de24aa 100644 (file)
@@ -196,7 +196,7 @@ static void action_state_set(surf_action_t action,
   surf_action_state_set(action, state);
 }
 
-static double share_resources(double now)
+static double share_resources(surf_model_t network_model, double now)
 {
   xbt_swag_t running_actions =
       surf_network_model->states.running_action_set;
@@ -216,11 +216,11 @@ static double share_resources(double now)
   return time_to_next_flow_completion;
 }
 
-static void update_actions_state(double now, double delta)
+static void update_actions_state(surf_model_t network_model, double now, double delta)
 {
   surf_action_network_GTNETS_t action = NULL;
   xbt_swag_t running_actions =
-      surf_network_model->states.running_action_set;
+      network_model->states.running_action_set;
 
   /* If there are no running flows, just return */
   if (time_to_next_flow_completion < 0.0) {
@@ -400,7 +400,7 @@ static void gtnets_action_set_category(surf_action_t action, const char *categor
 }
 #endif
 
-static void finalize(void)
+static void finalize(surf_model_t network_model)
 {
   gtnets_finalize();
 }
@@ -410,6 +410,7 @@ static void surf_network_model_init_internal(void)
   surf_network_model = surf_model_init();
 
   surf_network_model->name = "network GTNetS";
+  surf_network_model->type = SURF_MODEL_TYPE_NETWORK;
   surf_network_model->action_unref = action_unref;
   surf_network_model->action_cancel = action_cancel;
   surf_network_model->action_recycle = action_recycle;
index e180da0..8ec660d 100644 (file)
@@ -23,9 +23,9 @@ extern xbt_dict_t dict_socket;
 
 static double time_to_next_flow_completion = -1;
 
-static double ns3_share_resources(double min);
-static void ns3_update_actions_state(double now, double delta);
-static void finalize(void);
+static double ns3_share_resources(surf_model_t network_model, double min);
+static void ns3_update_actions_state(surf_model_t network_model, double now, double delta);
+static void finalize(surf_model_t network_model);
 static surf_action_t ns3_communicate(sg_routing_edge_t src_elm,
                                      sg_routing_edge_t dst_elm,
                                      double size, double rate);
@@ -342,6 +342,7 @@ void surf_network_model_init_NS3()
 
   surf_network_model = surf_model_init();
   surf_network_model->name = "network NS3";
+  surf_network_model->type = SURF_MODEL_TYPE_NETWORK;
   surf_network_model->extension.network.get_link_latency = ns3_get_link_latency;
   surf_network_model->extension.network.get_link_bandwidth = ns3_get_link_bandwidth;
   surf_network_model->extension.network.get_route = ns3_get_route;
@@ -380,19 +381,19 @@ void surf_network_model_init_NS3()
 #endif
 }
 
-static void finalize(void)
+static void finalize(surf_model_t network_model)
 {
   ns3_finalize();
   xbt_dynar_free_container(&IPV4addr);
   xbt_dict_free(&dict_socket);
 }
 
-static double ns3_share_resources(double min)
+static double ns3_share_resources(surf_model_t network_model, double min)
 {
   XBT_DEBUG("ns3_share_resources");
 
   xbt_swag_t running_actions =
-    surf_network_model->states.running_action_set;
+    network_model->states.running_action_set;
 
   //get the first relevant value from the running_actions list
   if (!xbt_swag_size(running_actions) || min == 0.0)
@@ -411,7 +412,7 @@ static double ns3_share_resources(double min)
   return time_to_next_flow_completion;
 }
 
-static void ns3_update_actions_state(double now, double delta)
+static void ns3_update_actions_state(surf_model_t network_model, double now, double delta)
 {
   xbt_dict_cursor_t cursor = NULL;
   char *key;
@@ -422,7 +423,7 @@ static void ns3_update_actions_state(double now, double delta)
 
   surf_action_network_ns3_t action = NULL;
   xbt_swag_t running_actions =
-    surf_network_model->states.running_action_set;
+    network_model->states.running_action_set;
 
   /* If there are no running flows, just return */
   if (!xbt_swag_size(running_actions)) {
index 35e725e..f5a91f9 100644 (file)
@@ -47,25 +47,25 @@ static void* new_model_create_resource(const char* id, const char* model,const c
   return NULL;
 }
 
-static void new_model_finalize(void)
+static void new_model_finalize(surf_model_t new_model)
 {
   lmm_system_free(new_model_maxmin_system);
   new_model_maxmin_system = NULL;
 
-  surf_model_exit(surf_new_model);
-  surf_new_model = NULL;
+  surf_model_exit(new_model);
+  new_model = NULL;
 
   xbt_swag_free
       (new_model_running_action_set_that_does_not_need_being_checked);
   new_model_running_action_set_that_does_not_need_being_checked = NULL;
 }
 
-static void new_model_update_actions_state(double now, double delta)
+static void new_model_update_actions_state(surf_model_t new_model, double now, double delta)
 {
   return;
 }
 
-static double new_model_share_resources(double NOW)
+static double new_model_share_resources(surf_model_t new_model, double NOW)
 {
   return -1;
 }
@@ -147,6 +147,7 @@ static void surf_new_model_init_internal(void)
       xbt_swag_new(xbt_swag_offset(action, state_hookup));
 
   surf_new_model->name = "New Model";
+  surf_new_model->type = SURF_MODEL_TYPE_NEW_MODEL;
   surf_new_model->action_unref = new_model_action_unref;
   surf_new_model->action_cancel = new_model_action_cancel;
   surf_new_model->action_state_set = new_model_action_state_set;
index df2d0d4..9db9c85 100644 (file)
@@ -233,13 +233,13 @@ static void* storage_create_resource(const char* id, const char* model,const cha
   return storage;
 }
 
-static void storage_finalize(void)
+static void storage_finalize(surf_model_t storage_model)
 {
   lmm_system_free(storage_maxmin_system);
   storage_maxmin_system = NULL;
 
-  surf_model_exit(surf_storage_model);
-  surf_storage_model = NULL;
+  surf_model_exit(storage_model);
+  storage_model = NULL;
 
   xbt_dynar_free(&storage_list);
 
@@ -248,11 +248,11 @@ static void storage_finalize(void)
   storage_running_action_set_that_does_not_need_being_checked = NULL;
 }
 
-static void storage_update_actions_state(double now, double delta)
+static void storage_update_actions_state(surf_model_t storage_model, double now, double delta)
 {
   surf_action_storage_t action = NULL;
   surf_action_storage_t next_action = NULL;
-  xbt_swag_t running_actions = surf_storage_model->states.running_action_set;
+  xbt_swag_t running_actions = storage_model->states.running_action_set;
 
   // Update the disk usage
   // Update the file size
@@ -299,7 +299,7 @@ static void storage_update_actions_state(double now, double delta)
   return;
 }
 
-static double storage_share_resources(double NOW)
+static double storage_share_resources(surf_model_t storage_model, double NOW)
 {
   XBT_DEBUG("storage_share_resources %f",NOW);
   s_surf_action_storage_t action;
@@ -307,7 +307,7 @@ static double storage_share_resources(double NOW)
   storage_t storage;
   surf_action_storage_t write_action;
 
-  double min_completion = generic_maxmin_share_resources(surf_storage_model->states.running_action_set,
+  double min_completion = generic_maxmin_share_resources(storage_model->states.running_action_set,
       xbt_swag_offset(action, generic_lmm_action.variable),
       storage_maxmin_system, lmm_solve);
 
@@ -461,6 +461,7 @@ static void surf_storage_model_init_internal(void)
       xbt_swag_new(xbt_swag_offset(action, state_hookup));
 
   surf_storage_model->name = "Storage";
+  surf_storage_model->type = SURF_MODEL_TYPE_STORAGE;
   surf_storage_model->action_unref = storage_action_unref;
   surf_storage_model->action_cancel = storage_action_cancel;
   surf_storage_model->action_state_set = storage_action_state_set;
index 3463fad..2cc050d 100644 (file)
@@ -110,7 +110,11 @@ int __surf_is_absolute_file_path(const char *file_path)
 
 double NOW = 0;
 
-xbt_dynar_t model_list = NULL;
+/* model_list_invoke contains only surf_workstation and surf_vm_workstation.
+ * The callback functions of cpu_model and network_model will be called from
+ * those of these workstation models. */
+xbt_dynar_t model_list = NULL; /* for destroying all models correctly */
+xbt_dynar_t model_list_invoke = NULL;  /* for invoking callbacks */
 tmgr_history_t history = NULL;
 lmm_system_t maxmin_system = NULL;
 xbt_dynar_t surf_path = NULL;
@@ -414,6 +418,8 @@ void surf_init(int *argc, char **argv)
   xbt_init(argc, argv);
   if (!model_list)
     model_list = xbt_dynar_new(sizeof(surf_model_private_t), NULL);
+  if (!model_list_invoke)
+    model_list_invoke = xbt_dynar_new(sizeof(surf_model_private_t), NULL);
   if (!history)
     history = tmgr_history_new();
 
@@ -467,8 +473,11 @@ void surf_exit(void)
   sg_config_finalize();
 
   xbt_dynar_foreach(model_list, iter, model)
-      model->model_private->finalize();
+      model->model_private->finalize(model);
   xbt_dynar_free(&model_list);
+
+  xbt_dynar_free(&model_list_invoke);
+
   routing_exit();
 
   if (maxmin_system) {
@@ -529,8 +538,10 @@ void surf_presolve(void)
       }
     }
   }
+
+  /* FIXME: see what is check_update_action_state(). if necessary, use model_list_invoke. */
   xbt_dynar_foreach(model_list, iter, model)
-      model->model_private->update_actions_state(NOW, 0.0);
+      model->model_private->update_actions_state(model, NOW, 0.0);
 }
 
 double surf_solve(double max_date)
@@ -551,17 +562,17 @@ double surf_solve(double max_date)
   XBT_DEBUG("Looking for next action end for all models except NS3");
 
   if (surf_mins == NULL) {
-    surf_mins = xbt_new(double, xbt_dynar_length(model_list));
+    surf_mins = xbt_new(double, xbt_dynar_length(model_list_invoke));
   }
   surf_min_index = 0;
 
   /* sequential version */
-  xbt_dynar_foreach(model_list, iter, model) {
+  xbt_dynar_foreach(model_list_invoke, iter, model) {
     surf_share_resources(model);
   }
 
   unsigned i;
-  for (i = 0; i < xbt_dynar_length(model_list); i++) {
+  for (i = 0; i < xbt_dynar_length(model_list_invoke); i++) {
     if ((min < 0.0 || surf_mins[i] < min)
         && surf_mins[i] >= 0.0) {
       min = surf_mins[i];
@@ -586,7 +597,7 @@ double surf_solve(double max_date)
 
       XBT_DEBUG("Run for network at most %f", min);
       // run until min or next flow
-      model_next_action_end = surf_network_model->model_private->share_resources(min);
+      model_next_action_end = surf_network_model->model_private->share_resources(surf_network_model, min);
 
       XBT_DEBUG("Min for network : %f", model_next_action_end);
       if(model_next_action_end>=0.0)
@@ -632,7 +643,7 @@ double surf_solve(double max_date)
   XBT_DEBUG("Duration set to %f", min);
 
   NOW = NOW + min;
-
+  /* FIXME: model_list or model_list_invoke? revisit here later */
   /* sequential version */
   xbt_dynar_foreach(model_list, iter, model) {
     surf_update_actions_state(model);
@@ -656,7 +667,7 @@ static void surf_share_resources(surf_model_t model)
   int i = __sync_fetch_and_add(&surf_min_index, 1);
   if (strcmp(model->name,"network NS3")) {
     XBT_DEBUG("Running for Resource [%s]", model->name);
-    next_action_end = model->model_private->share_resources(NOW);
+    next_action_end = model->model_private->share_resources(model, NOW);
     XBT_DEBUG("Resource [%s] : next action end = %f",
         model->name, next_action_end);
   }
@@ -665,10 +676,9 @@ static void surf_share_resources(surf_model_t model)
 
 static void surf_update_actions_state(surf_model_t model)
 {
-  model->model_private->update_actions_state(NOW, min);
+  model->model_private->update_actions_state(model, NOW, min);
 }
 
-
 /* This function is a pimple that we ought to fix. But it won't be easy.
  *
  * The surf_solve() function does properly return the set of actions that changed.
index 59e775f..bb3006f 100644 (file)
@@ -74,7 +74,7 @@ void *surf_action_new(size_t size, double cost, surf_model_t model,
   action->max_duration = NO_MAX_DURATION;
   action->start = surf_get_clock();
   action->finish = -1.0;
-  action->model_type = model;
+  action->model_obj = model;
 #ifdef HAVE_TRACING
   action->category = NULL;
 #endif
@@ -91,7 +91,7 @@ void *surf_action_new(size_t size, double cost, surf_model_t model,
 
 e_surf_action_state_t surf_action_state_get(surf_action_t action)
 {
-  surf_action_state_t action_state = &(action->model_type->states);
+  surf_action_state_t action_state = &(action->model_obj->states);
 
   if (action->state_set == action_state->ready_action_set)
     return SURF_ACTION_READY;
@@ -124,7 +124,7 @@ XBT_INLINE void surf_action_free(surf_action_t * action)
 void surf_action_state_set(surf_action_t action,
                            e_surf_action_state_t state)
 {
-  surf_action_state_t action_state = &(action->model_type->states);
+  surf_action_state_t action_state = &(action->model_obj->states);
   XBT_IN("(%p,%s)", action, surf_action_state_names[state]);
   xbt_swag_remove(action, action->state_set);
 
@@ -187,7 +187,7 @@ void surf_action_lmm_heap_remove(xbt_heap_t heap, surf_action_lmm_t action)
 
 void surf_action_cancel(surf_action_t action)
 {
-  surf_model_t model = action->model_type;
+  surf_model_t model = action->model_obj;
   surf_action_state_set(action, SURF_ACTION_FAILED);
   if (model->model_private->update_mechanism == UM_LAZY) {
     xbt_swag_remove(action, model->model_private->modified_set);
@@ -198,7 +198,7 @@ void surf_action_cancel(surf_action_t action)
 
 int surf_action_unref(surf_action_t action)
 {
-  surf_model_t model = action->model_type;
+  surf_model_t model = action->model_obj;
   action->refcount--;
   if (!action->refcount) {
     xbt_swag_remove(action, action->state_set);
@@ -221,7 +221,7 @@ int surf_action_unref(surf_action_t action)
 
 void surf_action_suspend(surf_action_t action)
 {
-  surf_model_t model = action->model_type;
+  surf_model_t model = action->model_obj;
   XBT_IN("(%p)", action);
   if (((surf_action_lmm_t) action)->suspended != 2) {
     lmm_update_variable_weight(model->model_private->maxmin_system,
@@ -236,7 +236,7 @@ void surf_action_suspend(surf_action_t action)
 
 void surf_action_resume(surf_action_t action)
 {
-  surf_model_t model = action->model_type;
+  surf_model_t model = action->model_obj;
   XBT_IN("(%p)", action);
   if (((surf_action_lmm_t) action)->suspended != 2) {
     lmm_update_variable_weight(model->model_private->maxmin_system,
@@ -256,7 +256,7 @@ int surf_action_is_suspended(surf_action_t action)
 
 void surf_action_set_max_duration(surf_action_t action, double duration)
 {
-  surf_model_t model = action->model_type;
+  surf_model_t model = action->model_obj;
   XBT_IN("(%p,%g)", action, duration);
   action->max_duration = duration;
   if (model->model_private->update_mechanism == UM_LAZY)      // remove action from the heap
@@ -266,7 +266,7 @@ void surf_action_set_max_duration(surf_action_t action, double duration)
 
 void surf_action_set_priority(surf_action_t action, double priority)
 {
-  surf_model_t model = action->model_type;
+  surf_model_t model = action->model_obj;
   XBT_IN("(%p,%g)", action, priority);
   action->priority = priority;
   lmm_update_variable_weight(model->model_private->maxmin_system,
@@ -278,6 +278,18 @@ void surf_action_set_priority(surf_action_t action, double priority)
   XBT_OUT();
 }
 
+void surf_action_set_bound(surf_action_t action, double bound)
+{
+  surf_model_t model = action->model_obj;
+  XBT_IN("(%p,%g)", action, bound);
+  action->bound = bound;
+  lmm_update_variable_bound(model->model_private->maxmin_system, ((surf_action_lmm_t) action)->variable, bound);
+
+  if (model->model_private->update_mechanism == UM_LAZY)
+    surf_action_lmm_heap_remove(model->model_private->action_heap, (surf_action_lmm_t) action);
+  XBT_OUT();
+}
+
 #ifdef HAVE_TRACING
 void surf_action_set_category(surf_action_t action,
                                     const char *category)
@@ -291,7 +303,7 @@ void surf_action_set_category(surf_action_t action,
 void generic_update_action_remaining_lazy( surf_action_lmm_t action, double now)
 {
   double delta = 0.0;
-  surf_model_t model = action->generic_action.model_type;
+  surf_model_t model = action->generic_action.model_obj;
 
   if(model == surf_network_model)
   {
@@ -316,7 +328,7 @@ void generic_update_action_remaining_lazy( surf_action_lmm_t action, double now)
         action->last_value * delta);
 
 #ifdef HAVE_TRACING
-    if (model == surf_cpu_model && TRACE_is_enabled()) {
+    if (model->type == SURF_MODEL_TYPE_CPU && TRACE_is_enabled()) {
       surf_resource_t cpu =
           lmm_constraint_id(lmm_get_cnst_from_var
               (model->model_private->maxmin_system,
@@ -360,7 +372,7 @@ void generic_update_action_remaining_lazy( surf_action_lmm_t action, double now)
 double surf_action_get_remains(surf_action_t action)
 {
   XBT_IN("(%p)", action);
-  surf_model_t model = action->model_type;
+  surf_model_t model = action->model_obj;
   /* update remains before return it */
   if (model->model_private->update_mechanism == UM_LAZY)      /* update remains before return it */
     generic_update_action_remaining_lazy((surf_action_lmm_t)action, surf_get_clock());
@@ -377,7 +389,7 @@ void generic_update_actions_state_lazy(double now, double delta, surf_model_t mo
     XBT_DEBUG("Something happened to action %p", action);
 #ifdef HAVE_TRACING
     if (TRACE_is_enabled()) {
-      if(model == surf_cpu_model){
+      if(model->type == SURF_MODEL_TYPE_CPU){
       surf_resource_t cpu =
           lmm_constraint_id(lmm_get_cnst_from_var
                             (model->model_private->maxmin_system,
@@ -409,7 +421,7 @@ void generic_update_actions_state_lazy(double now, double delta, surf_model_t mo
     }
 #endif
 
-    if(model == surf_cpu_model){
+    if(model->type == SURF_MODEL_TYPE_CPU){
       action->generic_action.finish = surf_get_clock();
       XBT_DEBUG("Action %p finished", action);
 
@@ -446,7 +458,7 @@ void generic_update_actions_state_lazy(double now, double delta, surf_model_t mo
     }
   }
 #ifdef HAVE_TRACING
-  if (TRACE_is_enabled() && model == surf_cpu_model) {
+  if (TRACE_is_enabled() && model->type == SURF_MODEL_TYPE_CPU) {
     //defining the last timestamp that we can safely dump to trace file
     //without losing the event ascending order (considering all CPU's)
     double smaller = -1;
index dd54c47..2fb09bf 100644 (file)
@@ -31,12 +31,12 @@ typedef struct surf_model_private {
   int (*resource_used) (void *resource_id);
   /* Share the resources to the actions and return in how much time
      the next action may terminate */
-  double (*share_resources) (double now);
+  double (*share_resources) (surf_model_t model, double now);
   /* Update the actions' state */
-  void (*update_actions_state) (double now, double delta);
-  void (*update_resource_state) (void *id, tmgr_trace_event_t event_type,
+  void (*update_actions_state) (surf_model_t model, double now, double delta);
+  void (*update_resource_state) (void *resource, tmgr_trace_event_t event_type,
                                  double value, double time);
-  void (*finalize) (void);
+  void (*finalize) (surf_model_t model);
 
   lmm_system_t maxmin_system;
   e_UM_t update_mechanism;
@@ -75,6 +75,7 @@ void surf_action_resume(surf_action_t action);
 int surf_action_is_suspended(surf_action_t action);
 void surf_action_set_max_duration(surf_action_t action, double duration);
 void surf_action_set_priority(surf_action_t action, double priority);
+void surf_action_set_bound(surf_action_t action, double bound);
 #ifdef HAVE_TRACING
 void surf_action_set_category(surf_action_t action,
                                     const char *category);
diff --git a/src/surf/vm_workstation.c b/src/surf/vm_workstation.c
new file mode 100644 (file)
index 0000000..2310a77
--- /dev/null
@@ -0,0 +1,553 @@
+/* Copyright (c) 2004, 2005, 2006, 2007, 2008, 2009, 2010. 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 "xbt/ex.h"
+#include "xbt/dict.h"
+#include "portable.h"
+#include "surf_private.h"
+#include "surf/surf_resource.h"
+#include "simgrid/sg_config.h"
+#include "vm_workstation_private.h"
+#include "cpu_cas01_private.h"
+#include "maxmin_private.h"
+
+XBT_LOG_NEW_DEFAULT_SUBCATEGORY(surf_vm_workstation, surf,
+                                "Logging specific to the SURF VM workstation module");
+
+
+surf_model_t surf_vm_workstation_model = NULL;
+
+/* ind means ''indirect'' that this is a reference on the whole dict_elm
+ * structure (i.e not on the surf_resource_private infos) */
+
+static void vm_ws_create(const char *name, void *ind_phys_workstation)
+{
+  workstation_CLM03_t sub_ws = surf_workstation_resource_priv(ind_phys_workstation);
+  const char *sub_ws_name = sub_ws->generic_resource.name;
+
+  /* The workstation_VM2013 struct inherits the workstation_CLM03 struct. We
+   * create a physical workstation resource, but specifying the size of
+   * s_workstation_VM2013_t and the vm workstation model object. */
+  workstation_CLM03_t ws = (workstation_CLM03_t) surf_resource_new(sizeof(s_workstation_VM2013_t),
+      surf_vm_workstation_model, name, NULL);
+
+  /* Currently, we assume a VM has no storage. */
+  ws->storage = NULL;
+
+  /* Currently, a VM uses the network resource of its physical host. In
+   * host_lib, this network resource object is refered from two different keys.
+   * When deregistering the reference that points the network resource object
+   * from the VM name, we have to make sure that the system does not call the
+   * free callback for the network resource object. The network resource object
+   * is still used by the physical machine. */
+  ws->net_elm = xbt_lib_get_or_null(host_lib, sub_ws_name, ROUTING_HOST_LEVEL);
+  xbt_lib_set(host_lib, name, ROUTING_HOST_LEVEL, ws->net_elm);
+
+  /* The SURF_WKS_LEVEL at host_lib saves workstation_CLM03 objects. Please
+   * note workstation_VM2013 objects, inheriting the workstation_CLM03
+   * structure, are also saved there. 
+   *
+   * If you want to get a workstation_VM2013 object from host_lib, see
+   * ws->generic_resouce.model->type first. If it is
+   * SURF_MODEL_TYPE_VM_WORKSTATION, you can cast ws to vm_ws. */
+  XBT_INFO("Create VM(%s)@PM(%s) with %ld mounted disks", name, sub_ws_name, xbt_dynar_length(ws->storage));
+  xbt_lib_set(host_lib, name, SURF_WKS_LEVEL, ws);
+
+
+  /* We initialize the VM-specific members. */
+  workstation_VM2013_t vm_ws = (workstation_VM2013_t) ws;
+  vm_ws->sub_ws = sub_ws;
+  vm_ws->current_state = SURF_VM_STATE_CREATED;
+
+
+
+  // //// CPU  RELATED STUFF ////
+  // Roughly, create a vcpu resource by using the values of the sub_cpu one.
+  cpu_Cas01_t sub_cpu = surf_cpu_resource_priv(ind_phys_workstation);
+
+  /* We can assume one core and cas01 cpu for the first step.
+   * Do xbt_lib_set(host_lib, name, SURF_CPU_LEVEL, cpu) if you get the resource. */
+  cpu_cas01_create_resource(name, // name
+      sub_cpu->power_peak,        // host->power_peak,
+      1,                          // host->power_scale,
+      NULL,                       // host->power_trace,
+      1,                          // host->core_amount,
+      SURF_RESOURCE_ON,           // host->initial_state,
+      NULL,                       // host->state_trace,
+      NULL,                       // host->properties,
+      surf_cpu_model_vm);
+
+
+
+  /* We create cpu_action corresponding to a VM process on the host operating system. */
+  /* FIXME: TODO: we have to peridocally input GUESTOS_NOISE to the system? how ? */
+  // vm_ws->cpu_action = surf_cpu_model_pm->extension.cpu.execute(ind_phys_workstation, GUESTOS_NOISE);
+  vm_ws->cpu_action = surf_cpu_model_pm->extension.cpu.execute(ind_phys_workstation, 0);
+
+
+  /* TODO:
+   * - check how network requests are scheduled between distinct processes competing for the same card.
+   */
+}
+
+/*
+ * Update the physical host of the given VM
+ */
+static void vm_ws_migrate(void *ind_vm, void *ind_dst_pm)
+{ 
+   /* ind_phys_workstation equals to smx_host_t */
+   workstation_VM2013_t ws_vm2013 = surf_workstation_resource_priv(ind_vm);
+   workstation_CLM03_t ws_clm03_dst = surf_workstation_resource_priv(ind_dst_pm);
+   const char *vm_name = ws_vm2013->ws.generic_resource.name;
+   const char *pm_name_src = ws_vm2013->sub_ws->generic_resource.name;
+   const char *pm_name_dst = ws_clm03_dst->generic_resource.name;
+
+   xbt_assert(ws_vm2013);
+   xbt_assert(ws_clm03_dst);
+
+   /* do something */
+
+   /* update net_elm with that of the destination physical host */
+   void *old_net_elm = ws_vm2013->ws.net_elm;
+   void *new_net_elm = xbt_lib_get_or_null(host_lib, pm_name_dst, ROUTING_HOST_LEVEL);
+   xbt_assert(new_net_elm);
+
+   /* Unregister the current net_elm from host_lib. Do not call the free callback. */
+   xbt_lib_unset(host_lib, vm_name, ROUTING_HOST_LEVEL, 0);
+
+   /* Then, resister the new one. */
+   ws_vm2013->ws.net_elm = new_net_elm;
+   xbt_lib_set(host_lib, vm_name, ROUTING_HOST_LEVEL, ws_vm2013->ws.net_elm);
+
+   ws_vm2013->sub_ws = ws_clm03_dst;
+
+   /* Update vcpu's action for the new pm */
+   {
+#if 0
+     XBT_INFO("cpu_action->remains %g", ws_vm2013->cpu_action->remains);
+     XBT_INFO("cost %f remains %f start %f finish %f", ws_vm2013->cpu_action->cost,
+         ws_vm2013->cpu_action->remains,
+         ws_vm2013->cpu_action->start,
+         ws_vm2013->cpu_action->finish
+         );
+     XBT_INFO("cpu_action state %d", surf_action_state_get(ws_vm2013->cpu_action));
+#endif
+
+     /* create a cpu action bound to the pm model at the destination. */
+     surf_action_t new_cpu_action = surf_cpu_model_pm->extension.cpu.execute(ind_dst_pm, 0);
+
+     e_surf_action_state_t state = surf_action_state_get(ws_vm2013->cpu_action);
+     if (state != SURF_ACTION_DONE)
+       XBT_CRITICAL("FIXME: may need a proper handling, %d", state);
+     if (ws_vm2013->cpu_action->remains > 0)
+       XBT_CRITICAL("FIXME: need copy the state(?), %f", ws_vm2013->cpu_action->remains);
+
+     int ret = surf_cpu_model_pm->action_unref(ws_vm2013->cpu_action);
+     xbt_assert(ret == 1, "Bug: some resource still remains");
+
+     ws_vm2013->cpu_action = new_cpu_action;
+   }
+
+   XBT_DEBUG("migrate VM(%s): change net_elm (%p to %p)", vm_name, old_net_elm, new_net_elm);
+   XBT_DEBUG("migrate VM(%s): change PM (%s to %s)", vm_name, pm_name_src, pm_name_dst);
+}
+
+/*
+ * A physical host does not disapper in the current SimGrid code, but a VM may
+ * disapper during a simulation.
+ */
+static void vm_ws_destroy(void *ind_vm_workstation)
+{ 
+       /* ind_phys_workstation equals to smx_host_t */
+
+  /* Before clearing the entries in host_lib, we have to pick up resources. */
+       workstation_VM2013_t vm_ws = surf_workstation_resource_priv(ind_vm_workstation);
+  cpu_Cas01_t cpu = surf_cpu_resource_priv(ind_vm_workstation);
+       const char *name = vm_ws->ws.generic_resource.name;
+
+       xbt_assert(vm_ws);
+       xbt_assert(vm_ws->ws.generic_resource.model == surf_vm_workstation_model);
+
+
+  /* We deregister objects from host_lib, without invoking the freeing callback
+   * of each level.
+   *
+   * Do not call xbt_lib_remove() here. It deletes all levels of the key,
+   * including MSG_HOST_LEVEL and others. We should unregister only what we know.
+   */
+  xbt_lib_unset(host_lib, name, SURF_CPU_LEVEL, 0);
+  xbt_lib_unset(host_lib, name, ROUTING_HOST_LEVEL, 0);
+  xbt_lib_unset(host_lib, name, SURF_WKS_LEVEL, 0);
+
+  /* TODO: comment out when VM stroage is implemented. */
+  // xbt_lib_unset(host_lib, name, SURF_STORAGE_LEVEL, 0);
+
+
+  /* Free the cpu_action of the VM. */
+  int ret = surf_cpu_model_pm->action_unref(vm_ws->cpu_action);
+  xbt_assert(ret == 1, "Bug: some resource still remains");
+
+  /* Free the cpu resource of the VM. If using power_trace, we will have to
+   * free other objects than lmm_constraint. */
+  surf_model_t cpu_model = cpu->generic_resource.model;
+  lmm_constraint_free(cpu_model->model_private->maxmin_system, cpu->constraint);
+  surf_resource_free(cpu);
+
+  /* Free the network resource of the VM. */
+       // Nothing has to be done, because net_elmts is just a pointer on the physical one
+
+  /* Free the storage resource of the VM. */
+  // Not relevant yet
+
+       /* Free the workstation resource of the VM. */
+  surf_resource_free(vm_ws);
+}
+
+static int vm_ws_get_state(void *ind_vm_ws)
+{
+       return ((workstation_VM2013_t) surf_workstation_resource_priv(ind_vm_ws))->current_state;
+}
+
+static void vm_ws_set_state(void *ind_vm_ws, int state)
+{
+        ((workstation_VM2013_t) surf_workstation_resource_priv(ind_vm_ws))->current_state = state;
+}
+
+static void vm_ws_suspend(void *ind_vm_ws)
+{
+  workstation_VM2013_t vm_ws = surf_workstation_resource_priv(ind_vm_ws);
+
+  surf_action_suspend(vm_ws->cpu_action);
+
+  vm_ws->current_state = SURF_VM_STATE_SUSPENDED;
+}
+
+static void vm_ws_resume(void *ind_vm_ws)
+{
+  workstation_VM2013_t vm_ws = surf_workstation_resource_priv(ind_vm_ws);
+
+  surf_action_resume(vm_ws->cpu_action);
+
+  vm_ws->current_state = SURF_VM_STATE_RUNNING;
+}
+
+static void vm_ws_save(void *ind_vm_ws)
+{
+  workstation_VM2013_t vm_ws = surf_workstation_resource_priv(ind_vm_ws);
+
+  vm_ws->current_state = SURF_VM_STATE_SAVING;
+
+  /* FIXME: do something here */
+  surf_action_suspend(vm_ws->cpu_action);
+
+  vm_ws->current_state = SURF_VM_STATE_SAVED;
+}
+
+static void vm_ws_restore(void *ind_vm_ws)
+{
+  workstation_VM2013_t vm_ws = surf_workstation_resource_priv(ind_vm_ws);
+
+  vm_ws->current_state = SURF_VM_STATE_RESTORING;
+
+  /* FIXME: do something here */
+  surf_action_resume(vm_ws->cpu_action);
+
+  vm_ws->current_state = SURF_VM_STATE_RUNNING;
+}
+
+
+static double get_solved_value(surf_action_t cpu_action)
+{
+  int found = 0;
+  /* NOTE: Do not use surf_workstation_model's maxmin_system. It is not used. */
+  lmm_system_t pm_system = surf_cpu_model_pm->model_private->maxmin_system;
+  lmm_variable_t var = NULL;
+
+  xbt_swag_foreach(var, &pm_system->variable_set) {
+    XBT_DEBUG("var id %p id_int %d double %f", var->id, var->id_int, var->value);
+    if (var->id == cpu_action) {
+      found = 1;
+      break;
+    }
+  }
+
+  if (found)
+    return var->value;
+
+  XBT_CRITICAL("bug: cannot found the solved variable of the action %p", cpu_action);
+  DIE_IMPOSSIBLE;
+  return -1; /* NOT REACHED */
+}
+
+
+
+/* In the real world, processes on the guest operating system will be somewhat
+ * degraded due to virtualization overhead. The total CPU share that these
+ * processes get is smaller than that of the VM process gets on a host
+ * operating system. */
+// const double virt_overhead = 0.95;
+const double virt_overhead = 1;
+
+static double vm_ws_share_resources(surf_model_t workstation_model, double now)
+{
+  /* TODO: udpate action's cost with the total cost of processes on the VM. */
+
+
+  /* 0. Make sure that we already calculated the resource share at the physical
+   * machine layer. */
+  {
+    unsigned int index_of_pm_ws_model = xbt_dynar_search(model_list_invoke, &surf_workstation_model);
+    unsigned int index_of_vm_ws_model = xbt_dynar_search(model_list_invoke, &surf_vm_workstation_model);
+    xbt_assert((index_of_pm_ws_model < index_of_vm_ws_model), "Cannot assume surf_workstation_model comes before");
+    /* Another option is that we call sub_ws->share_resource() here. The
+     * share_resource() function has no side-effect. We can call it here to
+     * ensure that. */
+  }
+
+
+  /* 1. Now we know how many resource should be assigned to each virtual
+   * machine. We update constraints of the virtual machine layer.
+   *
+   *
+   * If we have two virtual machine (VM1 and VM2) on a physical machine (PM1).
+   *     X1 + X2 = C       (Equation 1)
+   * where
+   *    the resource share of VM1: X1
+   *    the resource share of VM2: X2
+   *    the capacity of PM1: C
+   *
+   * Then, if we have two process (P1 and P2) on VM1.
+   *     X1_1 + X1_2 = X1  (Equation 2)
+   * where
+   *    the resource share of P1: X1_1
+   *    the resource share of P2: X1_2
+   *    the capacity of VM1: X1
+   *
+   * Equation 1 was solved in the physical machine layer.
+   * Equation 2 is solved in the virtual machine layer (here).
+   * X1 must be passed to the virtual machine laye as a constraint value.
+   *
+   **/
+
+  /* iterate for all hosts including virtual machines */
+  xbt_lib_cursor_t cursor;
+  char *key;
+  void **ind_host;
+  xbt_lib_foreach(host_lib, cursor, key, ind_host) {
+    workstation_CLM03_t ws_clm03 = ind_host[SURF_WKS_LEVEL];
+    cpu_Cas01_t cpu_cas01 = ind_host[SURF_CPU_LEVEL];
+
+    if (!ws_clm03)
+      continue;
+    /* skip if it is not a virtual machine */
+    if (ws_clm03->generic_resource.model != surf_vm_workstation_model)
+      continue;
+    xbt_assert(cpu_cas01, "cpu-less workstation");
+
+    /* It is a virtual machine, so we can cast it to workstation_VM2013_t */
+    workstation_VM2013_t ws_vm2013 = (workstation_VM2013_t) ws_clm03;
+
+    double solved_value = get_solved_value(ws_vm2013->cpu_action);
+    XBT_DEBUG("assign %f to vm %s @ pm %s", solved_value,
+        ws_clm03->generic_resource.name, ws_vm2013->sub_ws->generic_resource.name);
+
+    // TODO: check lmm_update_constraint_bound() works fine instead of the below manual substitution.
+    // cpu_cas01->constraint->bound = solved_value;
+    surf_model_t cpu_model = cpu_cas01->generic_resource.model;
+    xbt_assert(cpu_model == surf_cpu_model_vm);
+    lmm_system_t vcpu_system = cpu_model->model_private->maxmin_system;
+    lmm_update_constraint_bound(vcpu_system, cpu_cas01->constraint, virt_overhead * solved_value);
+  }
+
+
+  /* 2. Calculate resource share at the virtual machine layer. */
+  double ret = ws_share_resources(workstation_model, now);
+
+
+  /* FIXME: 3. do we have to re-initialize our cpu_action object? */
+#if 1
+  /* iterate for all hosts including virtual machines */
+  xbt_lib_foreach(host_lib, cursor, key, ind_host) {
+    workstation_CLM03_t ws_clm03 = ind_host[SURF_WKS_LEVEL];
+
+    /* skip if it is not a virtual machine */
+    if (!ws_clm03)
+      continue;
+    if (ws_clm03->generic_resource.model != surf_vm_workstation_model)
+      continue;
+
+    /* It is a virtual machine, so we can cast it to workstation_VM2013_t */
+    {
+#if 0
+      workstation_VM2013_t ws_vm2013 = (workstation_VM2013_t) ws_clm03;            
+      XBT_INFO("cost %f remains %f start %f finish %f", ws_vm2013->cpu_action->cost,
+          ws_vm2013->cpu_action->remains,
+          ws_vm2013->cpu_action->start,
+          ws_vm2013->cpu_action->finish
+          );
+#endif
+#if 0
+      void *ind_sub_host = xbt_lib_get_elm_or_null(host_lib, ws_vm2013->sub_ws->generic_resource.name);      
+      surf_cpu_model_pm->action_unref(ws_vm2013->cpu_action);
+      /* FIXME: this means busy loop? */
+      // ws_vm2013->cpu_action = surf_cpu_model_pm->extension.cpu.execute(ind_sub_host, GUESTOS_NOISE);
+      ws_vm2013->cpu_action = surf_cpu_model_pm->extension.cpu.execute(ind_sub_host, 0);
+#endif
+
+    }
+  }
+#endif
+
+
+  return ret;
+}
+
+
+/*
+ * A surf level object will be useless in the upper layer. Returing the
+ * dict_elm of the host.
+ **/
+static void *vm_ws_get_pm(void *ind_vm_ws)
+{
+       workstation_VM2013_t vm_ws = surf_workstation_resource_priv(ind_vm_ws);
+  const char *sub_ws_name = vm_ws->sub_ws->generic_resource.name;
+
+  return xbt_lib_get_elm_or_null(host_lib, sub_ws_name);
+}
+
+
+/* Adding a task to a VM updates the VCPU task on its physical machine. */
+static surf_action_t vm_ws_execute(void *workstation, double size)
+{
+  surf_resource_t ws = ((surf_resource_t) surf_workstation_resource_priv(workstation));
+
+  xbt_assert(ws->model->type == SURF_MODEL_TYPE_VM_WORKSTATION);
+  workstation_VM2013_t vm_ws = (workstation_VM2013_t) ws;
+
+  double old_cost = vm_ws->cpu_action->cost;
+  double new_cost = old_cost + size;
+
+  XBT_DEBUG("VM(%s)@PM(%s): update dummy action's cost (%f -> %f)",
+      ws->name, vm_ws->sub_ws->generic_resource.name,
+      old_cost, new_cost);
+
+  vm_ws->cpu_action->cost = new_cost;
+
+  return ws_execute(workstation, size);
+}
+
+static void vm_ws_action_cancel(surf_action_t action)
+{
+  XBT_CRITICAL("FIXME: Not yet implemented. Reduce dummy action's cost by %f", action->cost);
+
+  ws_action_cancel(action);
+}
+
+
+/* Now we can set bound for each task by using MSG_task_set_bound. But, it does
+ * not work for the dummy CPU action of a VM. Here, we add the set_bound
+ * function for the dummy CPU action. */
+static void vm_ws_set_vm_bound(void *workstation, double bound)
+{
+  surf_resource_t ws = ((surf_resource_t) surf_workstation_resource_priv(workstation));
+  xbt_assert(ws->model->type == SURF_MODEL_TYPE_VM_WORKSTATION);
+  workstation_VM2013_t vm_ws = (workstation_VM2013_t) ws;
+
+  surf_action_set_bound(vm_ws->cpu_action, bound);
+}
+
+
+static void surf_vm_workstation_model_init_internal(void)
+{
+  surf_model_t model = surf_model_init();
+
+  model->name = "Virtual Workstation";
+  model->type = SURF_MODEL_TYPE_VM_WORKSTATION;
+
+  model->action_unref     = ws_action_unref;
+  model->action_cancel    = vm_ws_action_cancel;
+  // model->action_state_set = ws_action_state_set;
+
+
+  model->model_private->share_resources       = vm_ws_share_resources;
+  model->model_private->resource_used         = ws_resource_used;
+  model->model_private->update_actions_state  = ws_update_actions_state;
+  model->model_private->update_resource_state = ws_update_resource_state;
+  model->model_private->finalize              = ws_finalize;
+
+
+  /* operation for an action, not for VM it self */
+  model->suspend          = ws_action_suspend;
+  model->resume           = ws_action_resume;
+//   model->is_suspended     = ws_action_is_suspended;
+//   model->set_max_duration = ws_action_set_max_duration;
+  model->set_priority     = ws_action_set_priority;
+  model->set_bound        = ws_action_set_bound;
+// #ifdef HAVE_TRACING
+//   model->set_category     = ws_action_set_category;
+// #endif
+  model->get_remains      = ws_action_get_remains;
+// #ifdef HAVE_LATENCY_BOUND_TRACKING
+//   model->get_latency_limited = ws_get_latency_limited;
+// #endif
+
+
+
+
+
+
+
+  xbt_assert(surf_cpu_model_vm);
+  model->extension.workstation.cpu_model = surf_cpu_model_vm;
+
+  model->extension.workstation.execute   = vm_ws_execute;
+  model->extension.workstation.sleep     = ws_action_sleep;
+  model->extension.workstation.get_state = ws_get_state;
+  model->extension.workstation.get_speed = ws_get_speed;
+  // model->extension.workstation.get_available_speed = ws_get_available_speed;
+
+  // model->extension.workstation.communicate           = ws_communicate;
+  // model->extension.workstation.get_route             = ws_get_route;
+  // model->extension.workstation.execute_parallel_task = ws_execute_parallel_task;
+  // model->extension.workstation.get_link_bandwidth    = ws_get_link_bandwidth;
+  // model->extension.workstation.get_link_latency      = ws_get_link_latency;
+  // model->extension.workstation.link_shared           = ws_link_shared;
+  // model->extension.workstation.get_properties        = ws_get_properties;
+
+  // model->extension.workstation.open   = ws_action_open;
+  // model->extension.workstation.close  = ws_action_close;
+  // model->extension.workstation.read   = ws_action_read;
+  // model->extension.workstation.write  = ws_action_write;
+  // model->extension.workstation.stat   = ws_action_stat;
+  // model->extension.workstation.unlink = ws_action_unlink;
+  // model->extension.workstation.ls     = ws_action_ls;
+
+
+  model->extension.vm_workstation.create        = vm_ws_create;
+  model->extension.vm_workstation.set_state     = vm_ws_set_state;
+  model->extension.vm_workstation.get_state     = vm_ws_get_state;
+  model->extension.vm_workstation.migrate       = vm_ws_migrate;
+  model->extension.vm_workstation.destroy       = vm_ws_destroy;
+  model->extension.vm_workstation.suspend       = vm_ws_suspend;
+  model->extension.vm_workstation.resume        = vm_ws_resume;
+  model->extension.vm_workstation.save          = vm_ws_save;
+  model->extension.vm_workstation.restore       = vm_ws_restore;
+  model->extension.vm_workstation.get_pm        = vm_ws_get_pm;
+  model->extension.vm_workstation.set_vm_bound  = vm_ws_set_vm_bound;
+
+  model->extension.workstation.set_params    = ws_set_params;
+  model->extension.workstation.get_params    = ws_get_params;
+
+  surf_vm_workstation_model = model;
+}
+
+void surf_vm_workstation_model_init(void)
+{
+  surf_vm_workstation_model_init_internal();
+  xbt_dynar_push(model_list, &surf_vm_workstation_model);
+  xbt_dynar_push(model_list_invoke, &surf_vm_workstation_model);
+}
diff --git a/src/surf/vm_workstation_private.h b/src/surf/vm_workstation_private.h
new file mode 100644 (file)
index 0000000..9524f9b
--- /dev/null
@@ -0,0 +1,37 @@
+/* Copyright (c) 2009, 2013. 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. */
+
+#ifndef VM_WS_PRIVATE_H_
+#define VM_WS_PRIVATE_H_
+
+#define GUESTOS_NOISE 100 // This value corresponds to the cost of the global action associated to the VM
+                          // It corresponds to the cost of a VM running no tasks.
+
+#include "workstation_private.h"
+
+/* NOTE:
+ * The workstation_VM2013 struct includes the workstation_CLM03 struct in
+ * its first member. The workstation_VM2013_t struct inherites all
+ * characteristics of the workstation_CLM03 struct. So, we can treat a
+ * workstation_VM2013 object as a workstation_CLM03 if necessary.
+ **/
+typedef struct workstation_VM2013 {
+  s_workstation_CLM03_t ws;    /* a VM is a ''v''host */
+
+  /* The workstation object of the lower layer */
+  workstation_CLM03_t sub_ws;  // Pointer to the ''host'' OS
+
+  e_surf_vm_state_t current_state;
+
+
+  surf_action_t cpu_action;
+
+} s_workstation_VM2013_t, *workstation_VM2013_t;
+
+
+void surf_vm_workstation_model_init(void);
+
+#endif /* VM_WS_PRIVATE_H_ */
index aec832a..dbaf9ae 100644 (file)
 #include "storage_private.h"
 #include "surf/surf_resource.h"
 #include "simgrid/sg_config.h"
-
-typedef struct workstation_CLM03 {
-  s_surf_resource_t generic_resource;   /* Must remain first to add this to a trace */
-  void *net_elm;
-  xbt_dynar_t storage;
-} s_workstation_CLM03_t, *workstation_CLM03_t;
+#include "workstation_private.h"
+#include "vm_workstation_private.h"
+#include "cpu_cas01_private.h"
+#include "maxmin_private.h"
 
 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(surf_workstation, surf,
                                 "Logging specific to the SURF workstation module");
 
 surf_model_t surf_workstation_model = NULL;
 
+
 static void workstation_new(sg_platf_host_cbarg_t host)
 {
-  workstation_CLM03_t workstation = xbt_new0(s_workstation_CLM03_t, 1);
+  const char *name = host->id;
 
-  workstation->generic_resource.model = surf_workstation_model;
-  workstation->generic_resource.name = xbt_strdup(host->id);
-  workstation->storage = xbt_lib_get_or_null(storage_lib,host->id,ROUTING_STORAGE_HOST_LEVEL);
-  workstation->net_elm = xbt_lib_get_or_null(host_lib,host->id,ROUTING_HOST_LEVEL);
-  XBT_DEBUG("Create workstation %s with %ld mounted disks",host->id,xbt_dynar_length(workstation->storage));
-  xbt_lib_set(host_lib, host->id, SURF_WKS_LEVEL, workstation);
-}
+  /* NOTE: The properties object is NULL, because the current code uses that of
+   * that of a cpu resource. */
+  workstation_CLM03_t ws = (workstation_CLM03_t) surf_resource_new(sizeof(s_workstation_CLM03_t), surf_workstation_model, name, NULL);
 
-static int ws_resource_used(void *resource_id)
-{
-  THROW_IMPOSSIBLE;             /* This model does not implement parallel tasks */
-  return -1;
+  ws->storage = xbt_lib_get_or_null(storage_lib, name, ROUTING_STORAGE_HOST_LEVEL);
+  ws->net_elm = xbt_lib_get_or_null(host_lib, name, ROUTING_HOST_LEVEL);
+
+  XBT_DEBUG("Create ws %s with %ld mounted disks", name, xbt_dynar_length(ws->storage));
+  xbt_lib_set(host_lib, name, SURF_WKS_LEVEL, ws);
 }
 
 static void ws_parallel_action_cancel(surf_action_t action)
@@ -52,26 +48,28 @@ static int ws_parallel_action_free(surf_action_t action)
   return -1;
 }
 
-static int ws_action_unref(surf_action_t action)
+int ws_action_unref(surf_action_t action)
 {
-  if (action->model_type == surf_network_model)
+  if (action->model_obj->type == SURF_MODEL_TYPE_NETWORK)
     return surf_network_model->action_unref(action);
-  else if (action->model_type == surf_cpu_model)
-    return surf_cpu_model->action_unref(action);
-  else if (action->model_type == surf_workstation_model)
+  else if (action->model_obj->type == SURF_MODEL_TYPE_CPU)
+    return action->model_obj->action_unref(action);
+      // previously was: Adrien/Arnaud 6 feb
+         // surf_cpu_model->action_unref(action);
+  else if (action->model_obj->type == SURF_MODEL_TYPE_WORKSTATION)
     return ws_parallel_action_free(action);
   else
     DIE_IMPOSSIBLE;
   return 0;
 }
 
-static void ws_action_cancel(surf_action_t action)
+void ws_action_cancel(surf_action_t action)
 {
-  if (action->model_type == surf_network_model)
+  if (action->model_obj->type == SURF_MODEL_TYPE_NETWORK)
     surf_network_model->action_cancel(action);
-  else if (action->model_type == surf_cpu_model)
-    surf_cpu_model->action_cancel(action);
-  else if (action->model_type == surf_workstation_model)
+  else if (action->model_obj->type == SURF_MODEL_TYPE_CPU)
+    action->model_obj->action_cancel(action);
+  else if (action->model_obj->type == SURF_MODEL_TYPE_WORKSTATION)
     ws_parallel_action_cancel(action);
   else
     DIE_IMPOSSIBLE;
@@ -81,72 +79,173 @@ static void ws_action_cancel(surf_action_t action)
 static void ws_action_state_set(surf_action_t action,
                                 e_surf_action_state_t state)
 {
-  if (action->model_type == surf_network_model)
+  if (action->model_obj->type == SURF_MODEL_TYPE_NETWORK)
     surf_network_model->action_state_set(action, state);
-  else if (action->model_type == surf_cpu_model)
-    surf_cpu_model->action_state_set(action, state);
-  else if (action->model_type == surf_workstation_model)
+  else if (action->model_obj->type == SURF_MODEL_TYPE_CPU)
+    action->model_obj->action_state_set(action, state);
+  else if (action->model_obj->type == SURF_MODEL_TYPE_WORKSTATION)
     surf_action_state_set(action, state);
   else
     DIE_IMPOSSIBLE;
   return;
 }
 
-static double ws_share_resources(double now)
+
+/* -- The callback functions at model_private -- */
+/* These callbacks are also used for the vm workstation model. */
+int ws_resource_used(void *resource_id)
 {
-  return -1.0;
+  /* This model does not implement parallel tasks */
+  THROW_IMPOSSIBLE;
+  return -1;
+}
+
+
+/* TODO: The current code would be slow due to the iteration. Later, we can
+ * make it faster. */
+static int constraint_is_active(cpu_Cas01_t cpu_cas01)
+{
+  surf_model_t cpu_model = cpu_cas01->generic_resource.model;
+  lmm_system_t sys = cpu_model->model_private->maxmin_system;
+  int found = 0;
+  lmm_constraint_t cnst_tmp;
+
+  xbt_swag_foreach(cnst_tmp, &sys->active_constraint_set) {
+    if (cnst_tmp == cpu_cas01->constraint) {
+      found = 1;
+      break;
+    }
+  }
+
+  return found;
+}
+
+/* Each VM has a dummy CPU action on the PM layer. This CPU action works as the
+ * constraint (capacity) of the VM in the PM layer. If the VM does not have any
+ * active task, the dummy CPU action must be deactivated, so that the VM does
+ * not get any CPU share in the PM layer. */
+static void adjust_weight_of_dummy_cpu_actions(void)
+{
+  /* iterate for all hosts including virtual machines */
+  xbt_lib_cursor_t cursor;
+  char *key;
+  void **ind_host;
+
+  xbt_lib_foreach(host_lib, cursor, key, ind_host) {
+    workstation_CLM03_t ws_clm03 = ind_host[SURF_WKS_LEVEL];
+    cpu_Cas01_t cpu_cas01 = ind_host[SURF_CPU_LEVEL];
+
+    if (!ws_clm03)
+      continue;
+    /* skip if it is not a virtual machine */
+    if (ws_clm03->generic_resource.model != surf_vm_workstation_model)
+      continue;
+    xbt_assert(cpu_cas01, "cpu-less workstation");
+
+    /* It is a virtual machine, so we can cast it to workstation_VM2013_t */
+    workstation_VM2013_t ws_vm2013 = (workstation_VM2013_t) ws_clm03;
+
+    if (constraint_is_active(cpu_cas01)) {
+      /* some tasks exist on this VM */
+      XBT_DEBUG("set the weight of the dummy CPU action on PM to 1");
+
+      /* FIXME: we shoud use lmm_update_variable_weight() ? */
+      /* FIXME: If we assgign 1.05 and 0.05, the system makes apparently wrong values. */
+      surf_action_set_priority(ws_vm2013->cpu_action, 1);
+
+    } else {
+      /* no task exits on this VM */
+      XBT_DEBUG("set the weight of the dummy CPU action on PM to 0");
+
+      surf_action_set_priority(ws_vm2013->cpu_action, 0);
+    }
+  }
 }
 
-static void ws_update_actions_state(double now, double delta)
+
+double ws_share_resources(surf_model_t workstation_model, double now)
+{
+  if (workstation_model->type == SURF_MODEL_TYPE_WORKSTATION)
+    adjust_weight_of_dummy_cpu_actions();
+
+  /* Invoke the share_resources() callback of the physical cpu model object and
+   * the network model objects. */
+  surf_model_t cpu_model = workstation_model->extension.workstation.cpu_model;
+  surf_model_t net_model = surf_network_model;
+
+  double min_by_cpu = cpu_model->model_private->share_resources(cpu_model, now);
+  double min_by_net = net_model->model_private->share_resources(net_model, now);
+
+  XBT_DEBUG("model %p, %s min_by_cpu %f, %s min_by_net %f",
+      workstation_model, cpu_model->name, min_by_cpu, net_model->name, min_by_net);
+
+  if (min_by_cpu >= 0.0 && min_by_net >= 0.0)
+    return min(min_by_cpu, min_by_net);
+  else if (min_by_cpu >= 0.0)
+    return min_by_cpu;
+  else if (min_by_net >= 0.0)
+    return min_by_net;
+  else
+    return min_by_cpu;  /* probably min_by_cpu == min_by_net == -1 */
+}
+
+void ws_update_actions_state(surf_model_t workstation_model, double now, double delta)
 {
   return;
 }
 
-static void ws_update_resource_state(void *id,
-                                     tmgr_trace_event_t event_type,
-                                     double value, double date)
+void ws_update_resource_state(void *id, tmgr_trace_event_t event_type, double value, double date)
 {
-  THROW_IMPOSSIBLE;             /* This model does not implement parallel tasks */
+  /* This model does not implement parallel tasks */
+  THROW_IMPOSSIBLE;
 }
 
-static surf_action_t ws_execute(void *workstation, double size)
+void ws_finalize(surf_model_t workstation_model)
+{
+  surf_model_exit(workstation_model);
+  workstation_model = NULL;
+}
+
+
+
+surf_action_t ws_execute(void *workstation, double size)
 {
   surf_resource_t cpu = ((surf_resource_t) surf_cpu_resource_priv(workstation));
   return cpu->model->extension.cpu.execute(workstation, size);
 }
 
-static surf_action_t ws_action_sleep(void *workstation, double duration)
+surf_action_t ws_action_sleep(void *workstation, double duration)
 {
-  return surf_cpu_model->extension.cpu.
-      sleep(workstation, duration);
+  surf_resource_t cpu = ((surf_resource_t) surf_cpu_resource_priv(workstation));
+  return cpu->model->extension.cpu.sleep(workstation, duration);
 }
 
-static void ws_action_suspend(surf_action_t action)
+void ws_action_suspend(surf_action_t action)
 {
-  if (action->model_type == surf_network_model)
+  if (action->model_obj->type == SURF_MODEL_TYPE_NETWORK)
     surf_network_model->suspend(action);
-  else if (action->model_type == surf_cpu_model)
-    surf_cpu_model->suspend(action);
+  else if (action->model_obj->type == SURF_MODEL_TYPE_CPU)
+    action->model_obj->suspend(action);
   else
     DIE_IMPOSSIBLE;
 }
 
-static void ws_action_resume(surf_action_t action)
+void ws_action_resume(surf_action_t action)
 {
-  if (action->model_type == surf_network_model)
+  if (action->model_obj->type == SURF_MODEL_TYPE_NETWORK)
     surf_network_model->resume(action);
-  else if (action->model_type == surf_cpu_model)
-    surf_cpu_model->resume(action);
+  else if (action->model_obj->type == SURF_MODEL_TYPE_CPU)
+    action->model_obj->resume(action);
   else
     DIE_IMPOSSIBLE;
 }
 
 static int ws_action_is_suspended(surf_action_t action)
 {
-  if (action->model_type == surf_network_model)
+  if (action->model_obj->type == SURF_MODEL_TYPE_NETWORK)
     return surf_network_model->is_suspended(action);
-  if (action->model_type == surf_cpu_model)
-    return surf_cpu_model->is_suspended(action);
+  if (action->model_obj->type == SURF_MODEL_TYPE_CPU)
+    return action->model_obj->is_suspended(action);
   DIE_IMPOSSIBLE;
   return -1;
 }
@@ -154,20 +253,31 @@ static int ws_action_is_suspended(surf_action_t action)
 static void ws_action_set_max_duration(surf_action_t action,
                                        double duration)
 {
-  if (action->model_type == surf_network_model)
+  if (action->model_obj->type == SURF_MODEL_TYPE_NETWORK)
     surf_network_model->set_max_duration(action, duration);
-  else if (action->model_type == surf_cpu_model)
-    surf_cpu_model->set_max_duration(action, duration);
+  else if (action->model_obj->type == SURF_MODEL_TYPE_CPU)
+    action->model_obj->set_max_duration(action, duration);
   else
     DIE_IMPOSSIBLE;
 }
 
-static void ws_action_set_priority(surf_action_t action, double priority)
+void ws_action_set_priority(surf_action_t action, double priority)
 {
-  if (action->model_type == surf_network_model)
+  if (action->model_obj->type == SURF_MODEL_TYPE_NETWORK)
     surf_network_model->set_priority(action, priority);
-  else if (action->model_type == surf_cpu_model)
-    surf_cpu_model->set_priority(action, priority);
+  else if (action->model_obj->type == SURF_MODEL_TYPE_CPU)
+    action->model_obj->set_priority(action, priority);
+  else
+    DIE_IMPOSSIBLE;
+}
+
+void ws_action_set_bound(surf_action_t action, double bound)
+{
+  /* FIXME: only for CPU model object? */
+  if (action->model_obj->type == SURF_MODEL_TYPE_NETWORK)
+    surf_network_model->set_bound(action, bound);
+  else if (action->model_obj->type == SURF_MODEL_TYPE_CPU)
+    action->model_obj->set_bound(action, bound);
   else
     DIE_IMPOSSIBLE;
 }
@@ -175,10 +285,10 @@ static void ws_action_set_priority(surf_action_t action, double priority)
 #ifdef HAVE_TRACING
 static void ws_action_set_category(surf_action_t action, const char *category)
 {
-  if (action->model_type == surf_network_model)
+  if (action->model_obj->type == SURF_MODEL_TYPE_NETWORK)
     surf_network_model->set_category(action, category);
-  else if (action->model_type == surf_cpu_model)
-    surf_cpu_model->set_category(action, category);
+  else if (action->model_obj->type == SURF_MODEL_TYPE_CPU)
+    action->model_obj->set_category(action, category);
   else
     DIE_IMPOSSIBLE;
 }
@@ -187,19 +297,19 @@ static void ws_action_set_category(surf_action_t action, const char *category)
 #ifdef HAVE_LATENCY_BOUND_TRACKING
 static int ws_get_latency_limited(surf_action_t action)
 {
-  if (action->model_type == surf_network_model)
+  if (action->model_obj->type == SURF_MODEL_TYPE_NETWORK)
     return surf_network_model->get_latency_limited(action);
   else
     return 0;
 }
 #endif
 
-static double ws_action_get_remains(surf_action_t action)
+double ws_action_get_remains(surf_action_t action)
 {
-  if (action->model_type == surf_network_model)
+  if (action->model_obj->type == SURF_MODEL_TYPE_NETWORK)
     return surf_network_model->get_remains(action);
-  if (action->model_type == surf_cpu_model)
-    return surf_cpu_model->get_remains(action);
+  if (action->model_obj->type == SURF_MODEL_TYPE_CPU)
+    return action->model_obj->get_remains(action);
   DIE_IMPOSSIBLE;
   return -1.0;
 }
@@ -215,30 +325,33 @@ static surf_action_t ws_communicate(void *workstation_src,
                   dst->net_elm, size, rate);
 }
 
-static e_surf_resource_state_t ws_get_state(void *workstation)
+e_surf_resource_state_t ws_get_state(void *workstation)
 {
-  return surf_cpu_model->extension.cpu.
-      get_state(workstation);
+  surf_resource_t cpu = ((surf_resource_t) surf_cpu_resource_priv(workstation));
+  return cpu->model->extension.cpu.get_state(workstation);
 }
 
-static double ws_get_speed(void *workstation, double load)
+static void ws_set_state(void *workstation, e_surf_resource_state_t state)
 {
-  return surf_cpu_model->extension.cpu.
-      get_speed(workstation, load);
+  surf_resource_t cpu = ((surf_resource_t) surf_cpu_resource_priv(workstation));
+  cpu->model->extension.cpu.set_state(workstation, state);
 }
 
-static int ws_get_core(void *workstation)
+double ws_get_speed(void *workstation, double load)
 {
-  return surf_cpu_model->extension.cpu.
-      get_core(workstation);
+  surf_resource_t cpu = ((surf_resource_t) surf_cpu_resource_priv(workstation));
+  return cpu->model->extension.cpu.get_speed(workstation, load);
 }
 
-
-
+static int ws_get_core(void *workstation)
+{
+  surf_resource_t cpu = ((surf_resource_t) surf_cpu_resource_priv(workstation));
+  return cpu->model->extension.cpu.get_core(workstation);
+}
 static double ws_get_available_speed(void *workstation)
 {
-  return surf_cpu_model->extension.cpu.
-      get_available_speed(workstation);
+  surf_resource_t cpu = ((surf_resource_t) surf_cpu_resource_priv(workstation));
+  return cpu->model->extension.cpu.get_available_speed(workstation);
 }
 
 static surf_action_t ws_execute_parallel_task(int workstation_nb,
@@ -302,12 +415,6 @@ static int ws_link_shared(const void *link)
   return surf_network_model->extension.network.link_shared(link);
 }
 
-static void ws_finalize(void)
-{
-  surf_model_exit(surf_workstation_model);
-  surf_workstation_model = NULL;
-}
-
 static xbt_dict_t ws_get_properties(const void *ws)
 {
   return surf_resource_properties(surf_cpu_resource_priv(ws));
@@ -412,85 +519,135 @@ static size_t ws_file_get_size(void *workstation, surf_file_t fd)
   return fd->size;
 }
 
-static void surf_workstation_model_init_internal(void)
+void ws_get_params(void *ws, ws_params_t params)
 {
-  surf_workstation_model = surf_model_init();
-
-  surf_workstation_model->name = "Workstation";
-  surf_workstation_model->action_unref = ws_action_unref;
-  surf_workstation_model->action_cancel = ws_action_cancel;
-  surf_workstation_model->action_state_set = ws_action_state_set;
-
-  surf_workstation_model->model_private->resource_used = ws_resource_used;
-  surf_workstation_model->model_private->share_resources =
-      ws_share_resources;
-  surf_workstation_model->model_private->update_actions_state =
-      ws_update_actions_state;
-  surf_workstation_model->model_private->update_resource_state =
-      ws_update_resource_state;
-  surf_workstation_model->model_private->finalize = ws_finalize;
-
-  surf_workstation_model->suspend = ws_action_suspend;
-  surf_workstation_model->resume = ws_action_resume;
-  surf_workstation_model->is_suspended = ws_action_is_suspended;
-  surf_workstation_model->set_max_duration = ws_action_set_max_duration;
-  surf_workstation_model->set_priority = ws_action_set_priority;
-#ifdef HAVE_TRACING
-  surf_workstation_model->set_category = ws_action_set_category;
-#endif
-  surf_workstation_model->get_remains = ws_action_get_remains;
-#ifdef HAVE_LATENCY_BOUND_TRACKING
-  surf_workstation_model->get_latency_limited = ws_get_latency_limited;
-#endif
+  workstation_CLM03_t ws_clm03 = surf_workstation_resource_priv(ws);
+  memcpy(params, &ws_clm03->params, sizeof(s_ws_params_t));
+}
+
+void ws_set_params(void *ws, ws_params_t params)
+{
+  workstation_CLM03_t ws_clm03 = surf_workstation_resource_priv(ws);
+  /* may check something here. */
+  memcpy(&ws_clm03->params, params, sizeof(s_ws_params_t));
+}
+
+static xbt_dynar_t ws_get_vms(void *pm)
+{
+  xbt_dynar_t dyn = xbt_dynar_new(sizeof(smx_host_t), NULL);
+
+  /* iterate for all hosts including virtual machines */
+  xbt_lib_cursor_t cursor;
+  char *key;
+  void **ind_host;
+  xbt_lib_foreach(host_lib, cursor, key, ind_host) {
+    workstation_CLM03_t ws_clm03 = ind_host[SURF_WKS_LEVEL];
+    if (!ws_clm03)
+      continue;
+    /* skip if it is not a virtual machine */
+    if (ws_clm03->generic_resource.model != surf_vm_workstation_model)
+      continue;
+
+    /* It is a virtual machine, so we can cast it to workstation_VM2013_t */
+    workstation_VM2013_t ws_vm2013 = (workstation_VM2013_t) ws_clm03;
+    if (pm == ws_vm2013->sub_ws)
+      xbt_dynar_push(dyn, &ws_vm2013->sub_ws);
+  }
+
+  return dyn;
+}
 
-  surf_workstation_model->extension.workstation.execute = ws_execute;
-  surf_workstation_model->extension.workstation.sleep = ws_action_sleep;
-  surf_workstation_model->extension.workstation.get_state = ws_get_state;
-  surf_workstation_model->extension.workstation.get_core = ws_get_core;
-  surf_workstation_model->extension.workstation.get_speed = ws_get_speed;
-  surf_workstation_model->extension.workstation.get_available_speed =
+
+static void surf_workstation_model_init_internal(void)
+{
+  surf_model_t model = surf_model_init();
+
+  model->name = "Workstation";
+  model->type = SURF_MODEL_TYPE_WORKSTATION;
+  model->action_unref     = ws_action_unref;
+  model->action_cancel    = ws_action_cancel;
+  model->action_state_set = ws_action_state_set;
+
+  model->model_private->resource_used         = ws_resource_used;
+  model->model_private->share_resources       = ws_share_resources;
+  model->model_private->update_actions_state  = ws_update_actions_state;
+  model->model_private->update_resource_state = ws_update_resource_state;
+  model->model_private->finalize              = ws_finalize;
+
+  model->suspend          = ws_action_suspend;
+  model->resume           = ws_action_resume;
+  model->is_suspended     = ws_action_is_suspended;
+  model->set_max_duration = ws_action_set_max_duration;
+  model->set_priority     = ws_action_set_priority;
+  model->set_bound        = ws_action_set_bound;
+  #ifdef HAVE_TRACING
+  model->set_category     = ws_action_set_category;
+  #endif
+  model->get_remains      = ws_action_get_remains;
+  #ifdef HAVE_LATENCY_BOUND_TRACKING
+  model->get_latency_limited = ws_get_latency_limited;
+  #endif
+
+  /* For VM support, we have a surf cpu model object for each workstation model
+   * object. The physical workstation model object has the cpu model object of
+   * the physical machine layer. */
+  xbt_assert(surf_cpu_model_pm);
+  model->extension.workstation.cpu_model = surf_cpu_model_pm;
+
+  model->extension.workstation.execute   = ws_execute;
+  model->extension.workstation.sleep     = ws_action_sleep;
+  model->extension.workstation.get_state = ws_get_state;
+  model->extension.workstation.set_state = ws_set_state;
+  model->extension.workstation.get_core  = ws_get_core;
+  model->extension.workstation.get_speed = ws_get_speed;
+  model->extension.workstation.get_available_speed =
       ws_get_available_speed;
 
-  surf_workstation_model->extension.workstation.communicate =
-      ws_communicate;
-  surf_workstation_model->extension.workstation.get_route = ws_get_route;
-  surf_workstation_model->extension.workstation.execute_parallel_task =
-      ws_execute_parallel_task;
-  surf_workstation_model->extension.workstation.get_link_bandwidth =
-      ws_get_link_bandwidth;
-  surf_workstation_model->extension.workstation.get_link_latency =
-      ws_get_link_latency;
-  surf_workstation_model->extension.workstation.link_shared =
-      ws_link_shared;
-  surf_workstation_model->extension.workstation.get_properties =
-      ws_get_properties;
-
-  surf_workstation_model->extension.workstation.open = ws_action_open;
-  surf_workstation_model->extension.workstation.close = ws_action_close;
-  surf_workstation_model->extension.workstation.read = ws_action_read;
-  surf_workstation_model->extension.workstation.write = ws_action_write;
-  surf_workstation_model->extension.workstation.unlink = ws_file_unlink;
-  surf_workstation_model->extension.workstation.ls = ws_action_ls;
-  surf_workstation_model->extension.workstation.get_size = ws_file_get_size;
+  model->extension.workstation.communicate           = ws_communicate;
+  model->extension.workstation.get_route             = ws_get_route;
+  model->extension.workstation.execute_parallel_task = ws_execute_parallel_task;
+  model->extension.workstation.get_link_bandwidth    = ws_get_link_bandwidth;
+  model->extension.workstation.get_link_latency      = ws_get_link_latency;
+  model->extension.workstation.link_shared           = ws_link_shared;
+  model->extension.workstation.get_properties        = ws_get_properties;
+
+  model->extension.workstation.open   = ws_action_open;
+  model->extension.workstation.close  = ws_action_close;
+  model->extension.workstation.read   = ws_action_read;
+  model->extension.workstation.write  = ws_action_write;
+  model->extension.workstation.unlink = ws_file_unlink;
+  model->extension.workstation.ls     = ws_action_ls;
+
+  model->extension.workstation.get_params = ws_get_params;
+  model->extension.workstation.set_params = ws_set_params;
+  model->extension.workstation.get_vms    = ws_get_vms;
+
+  surf_workstation_model = model;
 }
 
 void surf_workstation_model_init_current_default(void)
 {
-  surf_workstation_model_init_internal();
   xbt_cfg_setdefault_boolean(_sg_cfg_set, "network/crosstraffic", xbt_strdup("yes"));
   surf_cpu_model_init_Cas01();
   surf_network_model_init_LegrandVelho();
 
+  /* surf_cpu_mode_pm and surf_network_model must be initialized in advance. */
+  xbt_assert(surf_cpu_model_pm);
+  xbt_assert(surf_network_model);
+  surf_workstation_model_init_internal();
+
   xbt_dynar_push(model_list, &surf_workstation_model);
+  xbt_dynar_push(model_list_invoke, &surf_workstation_model);
   sg_platf_host_add_cb(workstation_new);
 }
 
 void surf_workstation_model_init_compound()
 {
-
-  xbt_assert(surf_cpu_model, "No CPU model defined yet!");
+  xbt_assert(surf_cpu_model_pm, "No CPU model defined yet!");
   xbt_assert(surf_network_model, "No network model defined yet!");
+
   surf_workstation_model_init_internal();
   xbt_dynar_push(model_list, &surf_workstation_model);
+  xbt_dynar_push(model_list_invoke, &surf_workstation_model);
   sg_platf_host_add_cb(workstation_new);
 }
diff --git a/src/surf/workstation_private.h b/src/surf/workstation_private.h
new file mode 100644 (file)
index 0000000..171d9b7
--- /dev/null
@@ -0,0 +1,41 @@
+/* Copyright (c) 2009, 2013. 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. */
+
+#ifndef WS_PRIVATE_H_
+#define WS_PRIVATE_H_
+typedef struct workstation_CLM03 {
+  s_surf_resource_t generic_resource;   /* Must remain first to add this to a trace */
+  void *net_elm;
+  xbt_dynar_t storage;
+
+  /* common with vm */
+  s_ws_params_t params;
+
+} s_workstation_CLM03_t, *workstation_CLM03_t;
+
+int ws_action_unref(surf_action_t action);
+
+int ws_resource_used(void *resource_id);
+double ws_share_resources(surf_model_t workstation_model, double now);
+void ws_update_actions_state(surf_model_t workstation_model, double now, double delta);
+void ws_update_resource_state(void *id, tmgr_trace_event_t event_type, double value, double date);
+void ws_finalize(surf_model_t workstation_model);
+
+void ws_action_set_priority(surf_action_t action, double priority);
+void ws_action_set_bound(surf_action_t action, double bound);
+
+surf_action_t ws_execute(void *workstation, double size);
+surf_action_t ws_action_sleep(void *workstation, double duration);
+void ws_action_suspend(surf_action_t action);
+void ws_action_resume(surf_action_t action);
+void ws_action_cancel(surf_action_t action);
+e_surf_resource_state_t ws_get_state(void *workstation);
+double ws_get_speed(void *workstation, double load);
+double ws_action_get_remains(surf_action_t action);
+
+void ws_get_params(void *ws, ws_params_t params);
+void ws_set_params(void *ws, ws_params_t params);
+#endif /* WS_PRIVATE_H_ */
index 3a63505..795ef05 100644 (file)
@@ -219,13 +219,13 @@ static int ptask_resource_used(void *resource_id)
 
 }
 
-static double ptask_share_resources(double now)
+static double ptask_share_resources(surf_model_t workstation_model, double now)
 {
   s_surf_action_workstation_L07_t s_action;
   surf_action_workstation_L07_t action = NULL;
 
   xbt_swag_t running_actions =
-      surf_workstation_model->states.running_action_set;
+      workstation_model->states.running_action_set;
   double min = generic_maxmin_share_resources(running_actions,
                                               xbt_swag_offset(s_action,
                                                               variable),
@@ -251,13 +251,13 @@ static double ptask_share_resources(double now)
   return min;
 }
 
-static void ptask_update_actions_state(double now, double delta)
+static void ptask_update_actions_state(surf_model_t workstation_model, double now, double delta)
 {
   double deltap = 0.0;
   surf_action_workstation_L07_t action = NULL;
   surf_action_workstation_L07_t next_action = NULL;
   xbt_swag_t running_actions =
-      surf_workstation_model->states.running_action_set;
+      workstation_model->states.running_action_set;
 
   xbt_swag_foreach_safe(action, next_action, running_actions) {
     deltap = delta;
@@ -410,12 +410,12 @@ static void ptask_update_resource_state(void *id,
   return;
 }
 
-static void ptask_finalize(void)
+static void ptask_finalize(surf_model_t workstation_model)
 {
   xbt_dict_free(&ptask_parallel_task_link_set);
 
-  surf_model_exit(surf_workstation_model);
-  surf_workstation_model = NULL;
+  surf_model_exit(workstation_model);
+  workstation_model = NULL;
   surf_model_exit(surf_network_model);
   surf_network_model = NULL;
 
@@ -859,6 +859,7 @@ static void ptask_model_init_internal(void)
   surf_workstation_model->set_priority = ptask_action_set_priority;
   surf_workstation_model->get_remains = ptask_action_get_remains;
   surf_workstation_model->name = "Workstation ptask_L07";
+  surf_workstation_model->type = SURF_MODEL_TYPE_WORKSTATION;
 
   surf_workstation_model->model_private->resource_used =
       ptask_resource_used;
@@ -921,7 +922,7 @@ static void ptask_model_init_internal(void)
 void surf_workstation_model_init_ptask_L07(void)
 {
   XBT_INFO("surf_workstation_model_init_ptask_L07");
-  xbt_assert(!surf_cpu_model, "CPU model type already defined");
+  xbt_assert(!surf_cpu_model_pm, "CPU model type already defined");
   xbt_assert(!surf_network_model, "network model type already defined");
   ptask_define_callbacks();
   ptask_model_init_internal();
index f383208..bba15a6 100644 (file)
@@ -223,6 +223,9 @@ const char *xbt_ex_catname(xbt_errcat_t cat)
     return "tracing error";
   case io_error:
     return "io error";
+  case vm_error:
+    return "vm error";
+
   }
   return "INVALID ERROR";
 }
index ccb1e0e..9929a07 100644 (file)
@@ -70,6 +70,37 @@ void xbt_lib_set(xbt_lib_t lib, const char *key, int level, void *obj)
   elts[level] = obj;
 }
 
+/* for vm */
+void xbt_lib_unset(xbt_lib_t lib, const char *key, int level, int invoke_callback)
+{
+  void **elts = xbt_dict_get_or_null(lib->dict, key);
+  if (!elts) {
+     XBT_WARN("no key %s", key);
+     return;
+  }
+
+  void *obj = elts[level];
+
+  if (!obj) {
+     XBT_WARN("no key %s at level %d", key, level);
+  } else {
+     XBT_DEBUG("Remove %p of key %s at level %d", obj, key, level);
+     if (invoke_callback)
+       lib->free_f[level](obj);
+     elts[level] = NULL;
+  }
+
+  /* check if there still remains any elements of this key */
+  int i;
+  for (i = 0; i < lib->levels; i++) {
+     if (elts[i] != NULL)
+       return;
+  }
+
+  /* there is no element at any level, so delete the key */
+  xbt_dict_remove(lib->dict, key);
+}
+
 void *xbt_lib_get_or_null(xbt_lib_t lib, const char *key, int level)
 {
   void **elts = xbt_dict_get_or_null(lib->dict, key);
@@ -85,3 +116,7 @@ void *xbt_lib_get_level(xbt_dictelm_t elm, int level){
   void **elts = elm->content;
   return elts ? elts[level] : NULL;
 }
+
+void xbt_lib_remove(xbt_lib_t lib, const char *key){
+  xbt_dict_remove(lib->dict, key);
+}
index 1224959..851043d 100644 (file)
@@ -58,7 +58,7 @@ void test(char *platform)
   parse_platform_file(platform);
 
   /*********************** CPU ***********************************/
-  XBT_DEBUG("%p", surf_cpu_model);
+  XBT_DEBUG("%p", surf_cpu_model_pm);
   cpuA = surf_cpu_resource_by_name("Cpu A");
   cpuB = surf_cpu_resource_by_name("Cpu B");
 
@@ -67,14 +67,14 @@ void test(char *platform)
   XBT_DEBUG("%s : %p", surf_resource_name(cpuB), cpuB);
 
   /* Let's do something on it */
-  actionA = surf_cpu_model->extension.cpu.execute(cpuA, 1000.0);
-  actionB = surf_cpu_model->extension.cpu.execute(cpuB, 1000.0);
-  actionC = surf_cpu_model->extension.cpu.sleep(cpuB, 7.32);
+  actionA = surf_cpu_model_pm->extension.cpu.execute(cpuA, 1000.0);
+  actionB = surf_cpu_model_pm->extension.cpu.execute(cpuB, 1000.0);
+  actionC = surf_cpu_model_pm->extension.cpu.sleep(cpuB, 7.32);
 
   /* Use whatever calling style you want... */
-  stateActionA = surf_cpu_model->action_state_get(actionA);     /* When you know actionA model type */
-  stateActionB = actionB->model_type->action_state_get(actionB);        /* If you're unsure about it's model type */
-  stateActionC = surf_cpu_model->action_state_get(actionC);     /* When you know actionA model type */
+  stateActionA = surf_cpu_model_pm->action_state_get(actionA);     /* When you know actionA model type */
+  stateActionB = actionB->model_obj->action_state_get(actionB);        /* If you're unsure about it's model type */
+  stateActionC = surf_cpu_model_pm->action_state_get(actionC);     /* When you know actionA model type */
 
   /* And just look at the state of these tasks */
   XBT_DEBUG("actionA : %p (%s)", actionA, string_action(stateActionA));
@@ -101,31 +101,31 @@ void test(char *platform)
     XBT_DEBUG("Next Event : %g", now);
     XBT_DEBUG("\t CPU actions");
     while ((action =
-            xbt_swag_extract(surf_cpu_model->states.failed_action_set))) {
+            xbt_swag_extract(surf_cpu_model_pm->states.failed_action_set))) {
       XBT_DEBUG("\t * Failed : %p", action);
-      action->model_type->action_unref(action);
+      action->model_obj->action_unref(action);
     }
     while ((action =
-            xbt_swag_extract(surf_cpu_model->states.done_action_set))) {
+            xbt_swag_extract(surf_cpu_model_pm->states.done_action_set))) {
       XBT_DEBUG("\t * Done : %p", action);
-      action->model_type->action_unref(action);
+      action->model_obj->action_unref(action);
     }
     XBT_DEBUG("\t Network actions");
     while ((action =
             xbt_swag_extract(surf_network_model->states.
                              failed_action_set))) {
       XBT_DEBUG("\t * Failed : %p", action);
-      action->model_type->action_unref(action);
+      action->model_obj->action_unref(action);
     }
     while ((action =
             xbt_swag_extract(surf_network_model->states.
                              done_action_set))) {
       XBT_DEBUG("\t * Done : %p", action);
-      action->model_type->action_unref(action);
+      action->model_obj->action_unref(action);
     }
 
   } while ((xbt_swag_size(surf_network_model->states.running_action_set) ||
-            xbt_swag_size(surf_cpu_model->states.running_action_set)) &&
+            xbt_swag_size(surf_cpu_model_pm->states.running_action_set)) &&
            surf_solve(-1.0) >= 0.0);
 
   XBT_DEBUG("Simulation Terminated");