Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Merge branch 'master' into hypervisor
authoralebre <adrien.lebre@inria.fr>
Tue, 2 Apr 2013 13:26:47 +0000 (15:26 +0200)
committeralebre <adrien.lebre@inria.fr>
Tue, 2 Apr 2013 13:26:47 +0000 (15:26 +0200)
54 files changed:
buildtools/Cmake/DefinePackages.cmake
examples/msg/cloud/CMakeLists.txt
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/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_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 28ca9d7..84cb6cc 100644 (file)
@@ -285,6 +285,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
   )
 
@@ -302,6 +303,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 534992d..a19ba8b 100644 (file)
@@ -3,13 +3,13 @@ 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 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)
 
 set(tesh_files
   ${tesh_files}
@@ -19,11 +19,14 @@ 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
   PARENT_SCOPE
   )
 set(bin_files
index e1527eb..e0d4374 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,239 @@ 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 */
+  /* Retrive 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 %ld 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);
+    MSG_vm_start(vm);
+    xbt_dynar_push(vms, &vm);
 
-  /* 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("put %s on %s", pr_name, vm_name);
+    MSG_process_create_with_arguments(pr_name, worker_fun, NULL, vm, 2, wrk_argv);
+  }
 
-  XBT_INFO("Now suspend all VMs, just for fun");
 
-  xbt_dynar_foreach(vms,i,vm) {
+  /* Send a bunch of work to every one */
+  XBT_INFO("Send a task to %d worker process", workers_count);
+  work_batch(workers_count);
+
+  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_INFO("Reboot all the VMs");
-  xbt_dynar_foreach(vms,i,vm) {
-    MSG_vm_reboot(vm);
+  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);
   }
 
-  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;
+  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;
   }
-  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);
+
+
+  MSG_process_create_with_arguments("master", master_fun, NULL, master_pm, nb_hosts + 1, master_argv);
+
+  msg_error_t res = MSG_main();
+  XBT_INFO("Bye (simulation time %g)", MSG_get_clock());
+
   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..0ada43f
--- /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");
+
+
+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);
+}
+
+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;
+}
+
+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);
+}
+
+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;
+}
+
+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..548cf70
--- /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");
+
+
+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;
+}
+
+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;
+};
+
+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;
+}
+
+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;
+}
+
+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;
+  char *pr_name = NULL;
+
+  pr_name = "comm_tx";
+  argv = xbt_new(char *, 3);
+  argv[0] = xbt_strdup(pr_name);
+  argv[1] = xbt_strdup(mbox);
+  argv[2] = NULL;
+
+  MSG_process_create_with_arguments(pr_name, communication_tx_fun, NULL, tx_host, 2, argv);
+
+  pr_name = "comm_rx";
+  argv = xbt_new(char *, 3);
+  argv[0] = xbt_strdup(pr_name);
+  argv[1] = xbt_strdup(mbox);
+  argv[2] = NULL;
+
+  MSG_process_create_with_arguments(pr_name, communication_rx_fun, NULL, rx_host, 2, argv);
+
+  xbt_free(mbox);
+}
+
+
+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;
+}
+
+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_t pr = 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);
+}
index 46281fe..78af98e 100644 (file)
@@ -46,7 +46,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
@@ -81,22 +84,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 0826da7..b3311ff 100644 (file)
@@ -95,7 +95,8 @@ 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_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);
@@ -112,6 +113,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,
@@ -362,29 +366,38 @@ XBT_PUBLIC(int) MSG_get_channel_number(void);
  *
  */
 /* 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);
+
+// 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, int mem_cap, int net_cap, char *disk_path, int disk_size);
+
+XBT_PUBLIC(void) MSG_vm_start(msg_vm_t);
 
 XBT_PUBLIC(int) MSG_vm_is_suspended(msg_vm_t);
 XBT_PUBLIC(int) MSG_vm_is_running(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(const char*) MSG_vm_get_name(msg_vm_t);
 
 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);
-  // \forall p in VM, MSG_process_suspend(p) // Freeze the processes
+XBT_PUBLIC(void) MSG_vm_resume(msg_vm_t vm);
 
-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
+/* 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(void) MSG_vm_shutdown(msg_vm_t vm); // killall
-
-XBT_PUBLIC(void) MSG_vm_reboot(msg_vm_t vm);
+/* Shutdown the guest operating system. */
+XBT_PUBLIC(void) MSG_vm_shutdown(msg_vm_t vm);
 
 XBT_PUBLIC(void) MSG_vm_destroy(msg_vm_t vm);
 
-XBT_PUBLIC(xbt_dynar_t) MSG_vms_as_dynar(void);
+msg_host_t MSG_vm_get_pm(msg_vm_t vm);
+
+/* 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 652b8bc..50dac1c 100644 (file)
@@ -41,6 +41,39 @@ 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_stage2;
+  double max_downtime;
+
+  double dp_rate;
+  double dp_cap;
+} 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 bd69b19..36bce8d 100644 (file)
@@ -15,6 +15,8 @@
 #include "xbt/parmap.h"
 #include "xbt/swag.h"
 
+#include "simgrid/platf.h" // ws_params_t
+
 SG_BEGIN_DECL()
 
 /**************************** Scalar Values **********************************/
@@ -319,7 +321,22 @@ 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(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_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 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 1483505..c5b183c 100644 (file)
@@ -80,6 +80,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
  *
@@ -106,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
@@ -236,12 +248,15 @@ 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 */
@@ -273,10 +288,58 @@ 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()
 
+} 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
@@ -288,7 +351,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);
@@ -322,6 +387,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;
@@ -352,11 +419,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
@@ -381,9 +451,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
@@ -402,7 +477,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).
@@ -574,6 +649,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
  *
@@ -622,6 +707,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 Globals **************************/
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..e6bd45a 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
index a767553..4cced2c 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);
 }
@@ -115,19 +117,35 @@ msg_host_t MSG_host_self(void)
 }
 
 /*
- * \brief Destroys a host (internal call only)
+ * \brief Frees private data of a host (internal call only)
  */
-void __MSG_host_destroy(msg_host_priv_t host) {
+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
@@ -252,3 +270,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..e708105 100644 (file)
@@ -68,8 +68,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 +87,8 @@ 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;
-*/
+
 /************************** Global variables ********************************/
 typedef struct MSG_Global {
   xbt_fifo_t host;
@@ -114,7 +99,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 +120,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 +134,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 +168,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 097cfaa..471e2a6 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 1143525..ee2b580 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);
+}
 
-  xbt_swag_insert(res,msg_global->vms);
-  xbt_swag_insert(res, MSG_host_priv(location)->vms);
+/** \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)");
 
-  #ifdef HAVE_TRACING
-  TRACE_msg_vm_create(name, location);
-  #endif
+  return (simcall_host_get_properties(vm));
+}
 
+/** \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
  *
- * Don't forget to free the dynar after use.
+ * \brief Return the name of the #msg_host_t.
+ *
+ * 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);
 }
 
-/** @brief Returns whether the given VM is currently suspended
+
+/* **** 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 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.
+
+#if 0
+/** @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.
+ */
+int MSG_vm_is_migrating(msg_vm_t vm)
+{
+  return __MSG_vm_is_state(vm, SURF_VM_STATE_MIGRATING);
+}
+#endif
+
+/** @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);
+}
+
+/** @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 Returns whether the given VM has been saved, not running.
+ *  @ingroup msg_VMs
+ */
+int MSG_vm_is_saved(msg_vm_t vm)
+{
+  return __MSG_vm_is_state(vm, SURF_VM_STATE_SAVED);
+}
+
+/** @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*
  *
  */
-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);
+msg_vm_t MSG_vm_create(msg_host_t ind_pm, const char *name,
+                                            int ncpus, int ramsize, int net_cap, char *disk_path, int 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);
   }
-  /* check if the host is in the right host */
-  if (simdata->m_host != vm->location) {
-    MSG_process_migrate(process,vm->location);
+
+  /* TODO: We will revisit the disk support later. */
+
+  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;
+    }
   }
-  simdata->vm = vm;
 
-  XBT_DEBUG("binding Process %s to %p",MSG_process_get_name(process),vm);
+  /* 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);
 
-  xbt_dynar_push_as(vm->processes,msg_process_t,process);
+  #ifdef HAVE_TRACING
+  TRACE_msg_vm_create(name, ind_pm);
+  #endif
+
+  return ind_vm;
 }
-/** @brief Removes the given process from the given VM, and kill it
+
+
+/** @brief Start a vm (i.e., boot the guest operating system)
  *  @ingroup msg_VMs
  *
- *  Will raise a not_found exception if the process were not bound to that VM
+ *  If the VM cannot be started, an exception is generated.
+ *
  */
-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);
+void MSG_vm_start(msg_vm_t vm)
+{
+  simcall_vm_start(vm);
+
+  #ifdef HAVE_TRACING
+  TRACE_msg_vm_start(vm);
+  #endif
 }
 
-/** @brief Immediately change the host on which all processes are running.
+
+
+/** @brief Immediately kills all processes within the given VM. Any memory that they allocated will be leaked.
  *  @ingroup msg_VMs
  *
- * No migration cost occurs. If you want to simulate this too, you want to use a
+ * 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_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 int migration_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_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);
+
+  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);
+
+    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;
+}
+
+
+typedef struct dirty_page {
+  double prev_clock;
+  double prev_remaining;
+  msg_task_t task;
+} s_dirty_page, *dirty_page_t;
+
+
+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
+
+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 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-stage2.%d: computed %f flop_counts (including %f by deleted tasks)",
+      stage2_round_for_fancy_debug,
+      total, priv->dp_updated_by_deleted_tasks);
+
+
+
+  priv->dp_updated_by_deleted_tasks = 0;
+
+
+  return total;
+}
+
+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 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)
+{
+  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);
+  msg_error_t ret = MSG_task_send(task, mbox);
+  xbt_assert(ret == MSG_OK);
+
+  if (stage == 2)
+    XBT_INFO("mig-stage%d.%d: sent %f", stage, stage2_round, size);
+  else
+    XBT_INFO("mig-stage%d: sent %f", stage, size);
+
+  xbt_free(task_name);
+}
+
+
+static int migration_tx_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_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_stage2     = params.skip_stage2;
+  const double max_downtime = params.max_downtime;
+  const double dp_rate      = params.dp_rate;
+  const double dp_cap       = params.dp_cap;
+  double remaining_size = ramsize + devsize;
+  double threshold = max_downtime * 125 * 1000 * 1000;
+
+
+  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);
+
+  send_migration_data(vm_name, src_pm_name, dst_pm_name, ramsize, mbox, 1, 0);
+
+  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 (;;) {
+    // long updated_size = lookup_dirty_pages(vm);
+    double updated_size = lookup_computed_flop_counts(vm, stage2_round) * 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;
+    }
+
+    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);
+
+    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);
+
+  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_t pr = 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_t pr = 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 destination) {
-  unsigned int cpt;
-  msg_process_t process;
-  xbt_dynar_foreach(vm->processes,cpt,process) {
-    MSG_process_migrate(process,destination);
-  }
-  xbt_swag_remove(vm, MSG_host_priv(vm->location)->vms);
-  xbt_swag_insert_at_tail(vm, MSG_host_priv(destination)->vms);
-  
+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_change_host(vm,vm->location,destination);
+  TRACE_msg_vm_change_host(vm, old_pm, new_pm);
   #endif
-
-  vm->location = destination;
 }
 
+
 /** @brief Immediately suspend the execution of all processes within the given VM.
  *  @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);
-  }
+ * 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
 }
 
-/** @brief Immediately resumes the execution of all processes within the given VM.
+
+/** @brief Resume the execution of the VM. All processes on the VM run again.
  *  @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.
- */
-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);
-  }
+ * No resume cost occurs.
+ */
+void MSG_vm_resume(msg_vm_t vm)
+{
+  simcall_vm_resume(vm);
 
   #ifdef HAVE_TRACING
   TRACE_msg_vm_resume(vm);
   #endif
 }
 
-/** @brief Immediately kills all processes within the given VM. Any memory that they allocated will be leaked.
+
+/** @brief Immediately save the execution of all processes within the given VM.
  *  @ingroup msg_VMs
  *
- * 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.
+ * 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_shutdown(msg_vm_t vm)
+void MSG_vm_save(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);
-  }
-
+  simcall_vm_save(vm);
   #ifdef HAVE_TRACING
-  TRACE_msg_vm_kill(vm);
+  TRACE_msg_vm_save(vm);
   #endif
-
 }
 
-/**
- * \ingroup msg_VMs
- * \brief Reboot the VM, restarting all the processes in it.
+/** @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_reboot(msg_vm_t vm)
+void MSG_vm_restore(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_restore(vm);
 
-  xbt_dynar_foreach(vm->processes, cpt, process) {
-    xbt_dynar_push_as(process_list, msg_process_t, process);
-  }
-
-  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);
+  #ifdef HAVE_TRACING
+  TRACE_msg_vm_restore(vm);
+  #endif
 }
 
-/** @brief Destroy a msg_vm_t.
+
+/** @brief Destroy a VM. Destroy the VM object from the simulation.
  *  @ingroup msg_VMs
  */
-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_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_end(vm);
   #endif
+}
 
-  xbt_free(vm->name);
-  xbt_dynar_free(&vm->processes);
-  xbt_free(vm);
+
+/** @brief Get the physical host of a givne VM.
+ *  @ingroup msg_VMs
+ */
+msg_host_t MSG_vm_get_pm(msg_vm_t vm)
+{
+  return simcall_vm_get_pm(vm);
 }
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 dea71e1..a8f51c2 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");
@@ -875,6 +876,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 3799230..3b227d7 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 5bd6088..9624e63 100644 (file)
@@ -135,7 +135,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 +145,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);
 }
 
 double SIMIX_pre_host_get_available_speed(smx_simcall_t simcall, smx_host_t host){
@@ -154,8 +155,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){
@@ -164,8 +165,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){
@@ -321,13 +322,12 @@ 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);
   }
 
   XBT_DEBUG("Create execute action %p", action);
@@ -366,28 +366,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);
@@ -400,8 +426,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){
@@ -409,9 +437,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;
 }
@@ -428,8 +457,10 @@ void SIMIX_pre_host_execution_set_priority(smx_simcall_t simcall, smx_action_t a
   return 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)
-    surf_workstation_model->set_priority(action->execution.surf_exec, priority);
+    ws_model->set_priority(action->execution.surf_exec, priority);
 }
 
 void SIMIX_pre_host_execution_wait(smx_simcall_t simcall, smx_action_t action){
@@ -454,20 +485,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) {
 
@@ -494,8 +530,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;
     }
 
@@ -508,15 +543,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;
@@ -525,7 +563,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;
   }
 
@@ -543,12 +581,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 6b03c17..b91a91e 100644 (file)
@@ -85,5 +85,50 @@ 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_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 f261620..dfb8554 100644 (file)
@@ -356,7 +356,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 d399b46..ccce24a 100644 (file)
@@ -337,17 +337,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..d3fd685 100644 (file)
@@ -689,9 +689,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 +707,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 +720,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 +741,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 +756,32 @@ 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);
+  smx_host_t host = action->sleep.host;
+  surf_model_t ws_model = surf_resource_model(host, SURF_WKS_LEVEL);
+
   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 c55fa36..3c6b698 100644 (file)
@@ -275,6 +275,20 @@ ACTION(SIMCALL_HOST_EXECUTION_GET_REMAINS, host_execution_get_remains, WITH_ANSW
 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_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_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 414b927..58e0b85 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 a23e346..06c52c9 100644 (file)
@@ -274,6 +274,157 @@ 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_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..4afe111
--- /dev/null
@@ -0,0 +1,378 @@
+/* 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);
+  {
+    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)
+{
+  const char *name = SIMIX_host_get_name(ind_vm);
+
+  /* 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 the 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 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);
+
+  smx_host_priv_t host_priv = SIMIX_host_priv(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 b492ee1..9b7d5c4 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();
@@ -304,23 +305,23 @@ static double cpu_get_available_speed(void *cpu)
   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;
@@ -329,14 +330,14 @@ static void surf_cpu_model_init_internal()
   int select =
       xbt_cfg_get_int(_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
@@ -349,61 +350,64 @@ 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;
+  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->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;
 #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_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.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;
 }
 
 /*********************************************************************/
@@ -422,19 +426,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..91d66ea 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;
@@ -729,12 +742,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 +760,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 +770,12 @@ static void cpu_ti_finalize(void)
   xbt_heap_free(cpu_ti_action_heap);
 }
 
-static void surf_cpu_ti_model_init_internal(void)
+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 +783,51 @@ 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;
+  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;
+  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;
 
-  surf_cpu_model->extension.cpu.execute = cpu_ti_execute;
-  surf_cpu_model->extension.cpu.sleep = cpu_ti_action_sleep;
+  cpu_model->extension.cpu.execute = cpu_ti_execute;
+  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->extension.cpu.get_state = cpu_ti_get_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 2eee39c..0d7f5ba 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 ea2b572..dce13e2 100644 (file)
@@ -48,25 +48,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;
 }
@@ -148,6 +148,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 9de73f7..2e35c45 100644 (file)
@@ -267,13 +267,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);
 
@@ -282,11 +282,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
@@ -330,7 +330,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;
@@ -338,7 +338,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);
 
@@ -492,6 +492,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 4103529..d2ded06 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;
@@ -415,6 +419,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();
 
@@ -468,8 +474,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) {
@@ -530,8 +539,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)
@@ -552,7 +563,7 @@ 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;
 
@@ -560,20 +571,20 @@ double surf_solve(double max_date)
   if (surf_get_nthreads() > 1) {
     /* parallel version */
 #ifdef CONTEXT_THREADS
-    xbt_parmap_apply(surf_parmap, (void_f_pvoid_t) surf_share_resources, model_list);
+    xbt_parmap_apply(surf_parmap, (void_f_pvoid_t) surf_share_resources, model_list_invoke);
 #else
     xbt_die("Asked to run in parallel, but no thread at hand...");
 #endif
   }
   else {
     /* 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];
@@ -598,7 +609,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)
@@ -652,6 +663,7 @@ double surf_solve(double max_date)
 #endif
   }
   else {
+    /* FIXME: model_list or model_list_invoke? revisit here later */
     /* sequential version */
     xbt_dynar_foreach(model_list, iter, model) {
       surf_update_actions_state(model);
@@ -676,7 +688,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);
   }
@@ -685,7 +697,7 @@ 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);
 }
 
 /**
index 59e775f..0e582d2 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,
@@ -291,7 +291,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 +316,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 +360,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 +377,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 +409,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 +446,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 8358de6..bb40853 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;
diff --git a/src/surf/vm_workstation.c b/src/surf/vm_workstation.c
new file mode 100644 (file)
index 0000000..445ea13
--- /dev/null
@@ -0,0 +1,536 @@
+/* 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(?), %d", 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;
+
+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 */
+    workstation_VM2013_t ws_vm2013 = (workstation_VM2013_t) ws_clm03;
+    {
+      void *ind_sub_host = xbt_lib_get_elm_or_null(host_lib, ws_vm2013->sub_ws->generic_resource.name);
+      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
+          );
+
+#if 0
+      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. */
+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);
+}
+
+
+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;
+// #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.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 b938ed0..33bfedf 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)
 {
   THROW_UNIMPLEMENTED;          /* This model does not implement parallel tasks */
@@ -52,26 +49,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 +80,169 @@ 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;
+}
+
+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);
+    }
+  }
+}
+
+
+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 */
 }
 
-static void ws_update_actions_state(double now, double delta)
+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)
+{
+  /* This model does not implement parallel tasks */
+  THROW_IMPOSSIBLE;
+}
+
+void ws_finalize(surf_model_t workstation_model)
 {
-  THROW_IMPOSSIBLE;             /* This model does not implement parallel tasks */
+  surf_model_exit(workstation_model);
+  workstation_model = NULL;
 }
 
-static surf_action_t ws_execute(void *workstation, double size)
+
+
+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 +250,20 @@ 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;
 }
@@ -175,10 +271,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 +283,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,22 +311,22 @@ 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)
 {
-  return surf_cpu_model->extension.cpu.
-      get_speed(workstation, load);
+  surf_resource_t cpu = ((surf_resource_t) surf_cpu_resource_priv(workstation));
+  return cpu->model->extension.cpu.get_speed(workstation, load);
 }
 
 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,
@@ -294,12 +390,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));
@@ -382,84 +472,132 @@ static surf_action_t ws_action_ls(void *workstation, const char* mount, const ch
   return model->extension.storage.ls(st, path);
 }
 
-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;
 
-  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_speed = ws_get_speed;
-  surf_workstation_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.stat = ws_action_stat;
-  surf_workstation_model->extension.workstation.unlink = ws_action_unlink;
-  surf_workstation_model->extension.workstation.ls = ws_action_ls;
+    /* 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;
+}
+
+
+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;
+  #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.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.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_int(_sg_cfg_set, "network/crosstraffic", 1);
   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..22866eb
--- /dev/null
@@ -0,0 +1,38 @@
+/* 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);
+
+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);
+e_surf_resource_state_t ws_get_state(void *workstation);
+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");