Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
add a missing file and add MSG_vm_set_bound
authorTakahiro Hirofuchi <t.hirofuchi+sg@aist.go.jp>
Thu, 6 Jun 2013 12:59:53 +0000 (14:59 +0200)
committerTakahiro Hirofuchi <t.hirofuchi+sg@aist.go.jp>
Thu, 6 Jun 2013 12:59:53 +0000 (14:59 +0200)
12 files changed:
examples/msg/cloud/bound.c [new file with mode: 0644]
include/msg/msg.h
include/simgrid/simix.h
src/include/surf/surf.h
src/msg/msg_task.c
src/msg/msg_vm.c
src/simix/smx_host_private.h
src/simix/smx_smurf_private.h
src/simix/smx_user.c
src/simix/smx_vm.c
src/surf/vm_workstation.c
src/surf/workstation.c

diff --git a/examples/msg/cloud/bound.c b/examples/msg/cloud/bound.c
new file mode 100644 (file)
index 0000000..475c535
--- /dev/null
@@ -0,0 +1,348 @@
+/* Copyright (c) 2007-2013. The SimGrid Team. All rights reserved. */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#include <stdio.h>
+#include "msg/msg.h"            /* Yeah! If you want to use msg, you need to include msg/msg.h */
+#include "xbt/sysdep.h"         /* calloc, printf */
+
+/* Create a log channel to have nice outputs. */
+#include "xbt/log.h"
+#include "xbt/asserts.h"
+XBT_LOG_NEW_DEFAULT_CATEGORY(msg_test,
+                             "Messages specific for this msg example");
+
+/** @addtogroup MSG_examples
+ *
+ * - <b>priority/priority.c</b>: Demonstrates the use of @ref
+ *   MSG_task_set_bound to change the computation priority of a
+ *   given task.
+ *
+ */
+
+static int worker_main(int argc, char *argv[])
+{
+  double computation_amount = atof(argv[1]);
+  int use_bound = atoi(argv[2]);
+  double bound = atof(argv[3]);
+
+  {
+    double clock_sta = MSG_get_clock();
+
+    msg_task_t task = MSG_task_create("Task", computation_amount, 0, NULL);
+    if (use_bound)
+      MSG_task_set_bound(task, bound);
+    MSG_task_execute(task);
+    MSG_task_destroy(task);
+
+    double clock_end = MSG_get_clock();
+    double duration = clock_end - clock_sta;
+    double flops_per_sec = computation_amount / duration;
+
+    if (use_bound)
+      XBT_INFO("bound to %f => duration %f (%f flops/s)", bound, duration, flops_per_sec);
+    else
+      XBT_INFO("not bound => duration %f (%f flops/s)", duration, flops_per_sec);
+  }
+
+  return 0;
+}
+
+static void launch_worker(msg_host_t host, const char *pr_name, double computation_amount, int use_bound, double bound)
+{
+  char **argv = xbt_new(char *, 5);
+  argv[0] = xbt_strdup(pr_name);
+  argv[1] = bprintf("%lf", computation_amount);
+  argv[2] = bprintf("%d", use_bound);
+  argv[3] = bprintf("%lf", bound);
+  argv[4] = NULL;
+
+  MSG_process_create_with_arguments(pr_name, worker_main, NULL, host, 4, argv);
+}
+
+#if 0
+static int worker_busy_loop_main(int argc, char *argv[])
+{
+  double clock_sta = MSG_get_clock();
+
+  msg_task_t task = MSG_task_create("Task", 100, 0, NULL);
+  MSG_task_execute(task);
+  MSG_task_destroy(task);
+
+  double clock_sta = MSG_get_clock();
+
+  return 0;
+}
+
+
+static msg_process_t launch_busy_loop_worker(msg_host_t host, const char *pr_name)
+{
+  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, worker_busy_loop_main, NULL, host, 1, argv);
+  return pr;
+}
+
+static void test_dynamic_change(void)
+{
+  xbt_dynar_t hosts_dynar = MSG_hosts_as_dynar();
+  msg_host_t pm0 = xbt_dynar_get_as(hosts_dynar, 0, msg_host_t);
+
+  msg_host_t vm0 = MSG_vm_create_core(pm0, "VM0");
+  msg_host_t vm1 = MSG_vm_create_core(pm0, "VM1");
+  MSG_vm_start(vm0);
+  MSG_vm_start(vm1);
+#endif
+
+  
+
+
+
+static void test_one_task(msg_host_t hostA)
+{
+  const double cpu_speed = MSG_get_host_speed(hostA);
+  const double computation_amount = cpu_speed * 10;
+  const char *hostA_name = MSG_host_get_name(hostA);
+
+  XBT_INFO("### Test: with/without MSG_task_set_bound");
+
+#if 0
+  /* Easy-to-understand code (without calling MSG_task_set_bound) */
+  {
+    double clock_sta = MSG_get_clock();
+
+    msg_task_t task = MSG_task_create("Task", computation_amount, 0, NULL);
+    MSG_task_execute(task);
+    MSG_task_destroy(task);
+
+    double clock_end = MSG_get_clock();
+    double duration = clock_end - clock_sta;
+    double flops_per_sec = computation_amount / duration;
+
+    XBT_INFO("not bound => duration %f (%f flops/s)", duration, flops_per_sec);
+  }
+
+  /* Easy-to-understand code (with calling MSG_task_set_bound) */
+  {
+    double clock_sta = MSG_get_clock();
+
+    msg_task_t task = MSG_task_create("Task", computation_amount, 0, NULL);
+    MSG_task_set_bound(task, cpu_speed / 2);
+    MSG_task_execute(task);
+    MSG_task_destroy(task);
+
+    double clock_end = MSG_get_clock();
+    double duration = clock_end - clock_sta;
+    double flops_per_sec = computation_amount / duration;
+
+    XBT_INFO("bound to 0.5 => duration %f (%f flops/s)", duration, flops_per_sec);
+  }
+#endif
+
+  {
+    XBT_INFO("### Test: no bound for Task1@%s", hostA_name);
+    launch_worker(hostA, "worker0", computation_amount, 0, 0);
+  }
+
+  MSG_process_sleep(1000);
+
+  {
+    XBT_INFO("### Test: 50%% for Task1@%s", hostA_name);
+    launch_worker(hostA, "worker0", computation_amount, 1, cpu_speed / 2);
+  }
+
+  MSG_process_sleep(1000);
+
+  {
+    XBT_INFO("### Test: 33%% for Task1@%s", hostA_name);
+    launch_worker(hostA, "worker0", computation_amount, 1, cpu_speed / 3);
+  }
+
+  MSG_process_sleep(1000);
+
+  {
+    XBT_INFO("### Test: zero for Task1@%s (i.e., unlimited)", hostA_name);
+    launch_worker(hostA, "worker0", computation_amount, 1, 0);
+  }
+
+  MSG_process_sleep(1000);
+
+  {
+    XBT_INFO("### Test: 200%% for Task1@%s (i.e., meaningless)", hostA_name);
+    launch_worker(hostA, "worker0", computation_amount, 1, cpu_speed * 2);
+  }
+
+  MSG_process_sleep(1000);
+}
+
+
+static void test_two_tasks(msg_host_t hostA, msg_host_t hostB)
+{
+  const double cpu_speed = MSG_get_host_speed(hostA);
+  xbt_assert(cpu_speed == MSG_get_host_speed(hostB));
+  const double computation_amount = cpu_speed * 10;
+  const char *hostA_name = MSG_host_get_name(hostA);
+  const char *hostB_name = MSG_host_get_name(hostB);
+
+  {
+    XBT_INFO("### Test: no bound for Task1@%s, no bound for Task2@%s", hostA_name, hostB_name);
+    launch_worker(hostA, "worker0", computation_amount, 0, 0);
+    launch_worker(hostB, "worker1", computation_amount, 0, 0);
+  }
+
+  MSG_process_sleep(1000);
+
+  {
+    XBT_INFO("### Test: 0 for Task1@%s, 0 for Task2@%s (i.e., unlimited)", hostA_name, hostB_name);
+    launch_worker(hostA, "worker0", computation_amount, 1, 0);
+    launch_worker(hostB, "worker1", computation_amount, 1, 0);
+  }
+
+  MSG_process_sleep(1000);
+
+  {
+    XBT_INFO("### Test: 50%% for Task1@%s, 50%% for Task2@%s", hostA_name, hostB_name);
+    launch_worker(hostA, "worker0", computation_amount, 1, cpu_speed / 2);
+    launch_worker(hostB, "worker1", computation_amount, 1, cpu_speed / 2);
+  }
+
+  MSG_process_sleep(1000);
+
+  {
+    XBT_INFO("### Test: 25%% for Task1@%s, 25%% for Task2@%s", hostA_name, hostB_name);
+    launch_worker(hostA, "worker0", computation_amount, 1, cpu_speed / 4);
+    launch_worker(hostB, "worker1", computation_amount, 1, cpu_speed / 4);
+  }
+
+  MSG_process_sleep(1000);
+
+  {
+    XBT_INFO("### Test: 75%% for Task1@%s, 100%% for Task2@%s", hostA_name, hostB_name);
+    launch_worker(hostA, "worker0", computation_amount, 1, cpu_speed * 0.75);
+    launch_worker(hostB, "worker1", computation_amount, 1, cpu_speed);
+  }
+
+  MSG_process_sleep(1000);
+
+  {
+    XBT_INFO("### Test: no bound for Task1@%s, 25%% for Task2@%s", hostA_name, hostB_name);
+    launch_worker(hostA, "worker0", computation_amount, 0, 0);
+    launch_worker(hostB, "worker1", computation_amount, 1, cpu_speed / 4);
+  }
+
+  MSG_process_sleep(1000);
+
+  {
+    XBT_INFO("### Test: 75%% for Task1@%s, 25%% for Task2@%s", hostA_name, hostB_name);
+    launch_worker(hostA, "worker0", computation_amount, 1, cpu_speed * 0.75);
+    launch_worker(hostB, "worker1", computation_amount, 1, cpu_speed / 4);
+  }
+
+  MSG_process_sleep(1000);
+}
+
+static int master_main(int argc, char *argv[])
+{
+  xbt_dynar_t hosts_dynar = MSG_hosts_as_dynar();
+  msg_host_t pm0 = xbt_dynar_get_as(hosts_dynar, 0, msg_host_t);
+
+
+  {
+    XBT_INFO("# 1. Put a single task on a PM. ");
+    test_one_task(pm0);
+    XBT_INFO(" ");
+
+
+    XBT_INFO("# 2. Put two tasks on a PM.");
+    test_two_tasks(pm0, pm0);
+    XBT_INFO(" ");
+  }
+
+
+  {
+    msg_host_t vm0 = MSG_vm_create_core(pm0, "VM0");
+    MSG_vm_start(vm0);
+
+    XBT_INFO("# 3. Put a single task on a VM. ");
+    test_one_task(vm0);
+    XBT_INFO(" ");
+
+    XBT_INFO("# 4. Put two tasks on a VM.");
+    test_two_tasks(vm0, vm0);
+    XBT_INFO(" ");
+
+
+    MSG_vm_destroy(vm0);
+  }
+
+
+  {
+    msg_host_t vm0 = MSG_vm_create_core(pm0, "VM0");
+    MSG_vm_start(vm0);
+
+    XBT_INFO("# 6. Put a task on a PM and a task on a VM.");
+    test_two_tasks(pm0, vm0);
+    XBT_INFO(" ");
+
+
+    MSG_vm_destroy(vm0);
+  }
+
+
+  {
+    msg_host_t vm0 = MSG_vm_create_core(pm0, "VM0");
+    const double cpu_speed = MSG_get_host_speed(pm0);
+    MSG_vm_set_bound(vm0, cpu_speed / 10);
+    MSG_vm_start(vm0);
+
+    XBT_INFO("# 7. Put a single task on the VM capped by 10%%.");
+    test_one_task(vm0);
+    XBT_INFO(" ");
+
+    XBT_INFO("# 8. Put two tasks on the VM capped by 10%%.");
+    test_two_tasks(vm0, vm0);
+    XBT_INFO(" ");
+
+    XBT_INFO("# 9. Put a task on a PM and a task on the VM capped by 10%%.");
+    test_two_tasks(pm0, vm0);
+    XBT_INFO(" ");
+
+    MSG_vm_destroy(vm0);
+  }
+
+
+  return 0;
+}
+
+static void launch_master(msg_host_t host)
+{
+  const char *pr_name = "master_";
+  char **argv = xbt_new(char *, 2);
+  argv[0] = xbt_strdup(pr_name);
+  argv[1] = NULL;
+
+  MSG_process_create_with_arguments(pr_name, master_main, NULL, host, 1, argv);
+}
+
+int main(int argc, char *argv[])
+{
+  /* Get the arguments */
+  MSG_init(&argc, argv);
+
+  /* load the platform file */
+  xbt_assert(argc == 2);
+  MSG_create_environment(argv[1]);
+
+  xbt_dynar_t hosts_dynar = MSG_hosts_as_dynar();
+  msg_host_t pm0 = xbt_dynar_get_as(hosts_dynar, 0, msg_host_t);
+  launch_master(pm0);
+
+  int res = MSG_main();
+  XBT_INFO("Bye (simulation time %g)", MSG_get_clock());
+
+
+  return !(res == MSG_OK);
+}
index e042ab7..8c9c4db 100644 (file)
@@ -401,7 +401,8 @@ XBT_PUBLIC(void) MSG_vm_resume(msg_vm_t vm);
 XBT_PUBLIC(void) MSG_vm_save(msg_vm_t vm);
 XBT_PUBLIC(void) MSG_vm_restore(msg_vm_t vm);
 
-msg_host_t MSG_vm_get_pm(msg_vm_t vm);
+XBT_PUBLIC(msg_host_t) MSG_vm_get_pm(msg_vm_t vm);
+XBT_PUBLIC(void) MSG_vm_set_bound(msg_vm_t vm, double bound);
 
 /* TODO: do we need this? */
 // XBT_PUBLIC(xbt_dynar_t) MSG_vms_as_dynar(void);
index 171e4a9..fe2a5c5 100644 (file)
@@ -332,6 +332,7 @@ XBT_PUBLIC(int) simcall_vm_get_state(smx_host_t vm);
 XBT_PUBLIC(void) simcall_vm_start(smx_host_t vm);
 XBT_PUBLIC(void) simcall_vm_migrate(smx_host_t vm, smx_host_t dst_pm);
 XBT_PUBLIC(void *) simcall_vm_get_pm(smx_host_t vm);
+XBT_PUBLIC(void) simcall_vm_set_bound(smx_host_t vm, double bound);
 XBT_PUBLIC(void) simcall_vm_resume(smx_host_t vm);
 XBT_PUBLIC(void) simcall_vm_save(smx_host_t vm);
 XBT_PUBLIC(void) simcall_vm_restore(smx_host_t vm);
index 07b15b3..74133ae 100644 (file)
@@ -323,6 +323,8 @@ typedef struct surf_vm_workstation_model_extension_public {
 
   void * (*get_pm) (void *ind_vm_ws); // will be vm_ws_get_pm()
 
+  void   (*set_vm_bound) (void *ind_vm_ws, double bound); // will be vm_ws_set_vm_bound()
+
 } s_surf_model_extension_vm_workstation_t;
 
 /** \ingroup SURF_models
index 03f5810..d95b180 100644 (file)
@@ -445,6 +445,7 @@ void MSG_task_set_priority(msg_task_t task, double priority)
  * \brief Changes the maximum CPU utilization of a computation task.
  *        Unit is flops/s.
  *
+ * For VMs, there is a pitfall. Please see MSG_vm_set_bound().
  */
 void MSG_task_set_bound(msg_task_t task, double bound)
 {
@@ -452,7 +453,7 @@ void MSG_task_set_bound(msg_task_t task, double bound)
   xbt_assert(task->simdata, "Invalid parameter");
 
   if (bound == 0)
-    XBT_INFO("bound == 0 means no capping");
+    XBT_INFO("bound == 0 means no capping (i.e., unlimited).");
 
   task->simdata->bound = bound;
   if (task->simdata->compute)
index 717cb22..6cbe343 100644 (file)
@@ -1172,8 +1172,6 @@ void MSG_vm_restore(msg_vm_t vm)
 }
 
 
-
-
 /** @brief Get the physical host of a given VM.
  *  @ingroup msg_VMs
  */
@@ -1181,3 +1179,36 @@ msg_host_t MSG_vm_get_pm(msg_vm_t vm)
 {
   return simcall_vm_get_pm(vm);
 }
+
+
+/** @brief Set a CPU bound for a given VM.
+ *  @ingroup msg_VMs
+ *
+ * Note that in some cases MSG_task_set_bound() may not intuitively work for VMs.
+ *
+ * For example,
+ *  On PM0, there are Task1 and VM0.
+ *  On VM0, there is Task2.
+ * Now we bound 75% to Task1@PM0 and bound 25% to Task2@VM0.
+ * Then, 
+ *  Task1@PM0 gets 50%.
+ *  Task2@VM0 gets 25%.
+ * This is NOT 75% for Task1@PM0 and 25% for Task2@VM0, respectively.
+ *
+ * This is because a VM has the dummy CPU action in the PM layer. Putting a
+ * task on the VM does not affect the bound of the dummy CPU action. The bound
+ * of the dummy CPU action is unlimited.
+ *
+ * There are some solutions for this problem. One option is to update the bound
+ * of the dummy CPU action automatically. It should be the sum of all tasks on
+ * the VM. But, this solution might be costy, because we have to scan all tasks
+ * on the VM in share_resource() or we have to trap both the start and end of
+ * task execution.
+ *
+ * The current solution is to use MSG_vm_set_bound(), which allows us to
+ * directly set the bound of the dummy CPU action.
+ */
+void MSG_vm_set_bound(msg_vm_t vm, double bound)
+{
+  return simcall_vm_set_bound(vm, bound);
+}
index c7b487d..2c5e157 100644 (file)
@@ -126,6 +126,9 @@ void SIMIX_pre_vm_migrate(smx_simcall_t simcall, smx_host_t ind_vm, smx_host_t i
 void *SIMIX_vm_get_pm(smx_host_t ind_vm);
 void *SIMIX_pre_vm_get_pm(smx_simcall_t simcall, smx_host_t ind_vm);
 
+void SIMIX_vm_set_bound(smx_host_t ind_vm, double bound);
+void SIMIX_pre_vm_set_bound(smx_simcall_t simcall, smx_host_t ind_vm, double bound);
+
 void SIMIX_host_get_params(smx_host_t ind_vm, ws_params_t params);
 void SIMIX_pre_host_get_params(smx_simcall_t simcall, smx_host_t ind_vm, ws_params_t params);
 
index 8740e10..6e075a9 100644 (file)
@@ -284,6 +284,7 @@ ACTION(SIMCALL_VM_SET_STATE, vm_set_state, WITHOUT_ANSWER, TVOID(result), TSPEC(
 ACTION(SIMCALL_VM_GET_STATE, vm_get_state, WITH_ANSWER,    TINT(result),  TSPEC(ind_vm, smx_host_t)) sep \
 ACTION(SIMCALL_VM_MIGRATE,   vm_migrate,   WITHOUT_ANSWER, TVOID(result), TSPEC(ind_vm, smx_host_t), TSPEC(ind_dst_pm, smx_host_t)) sep \
 ACTION(SIMCALL_VM_GET_PM,    vm_get_pm,    WITH_ANSWER,    TPTR(result),  TSPEC(ind_vm, smx_host_t)) sep \
+ACTION(SIMCALL_VM_SET_BOUND, vm_set_bound, WITHOUT_ANSWER, TVOID(result), TSPEC(ind_vm, smx_host_t), TDOUBLE(bound)) sep \
 ACTION(SIMCALL_VM_DESTROY,   vm_destroy,   WITHOUT_ANSWER, TVOID(result), TSPEC(ind_vm, smx_host_t)) sep \
 ACTION(SIMCALL_VM_SUSPEND,   vm_suspend,   WITHOUT_ANSWER, TVOID(result), TSPEC(ind_vm, smx_host_t)) sep \
 ACTION(SIMCALL_VM_RESUME,    vm_resume,    WITHOUT_ANSWER, TVOID(result), TSPEC(ind_vm, smx_host_t)) sep \
index 303a378..2b09caa 100644 (file)
@@ -340,6 +340,12 @@ void *simcall_vm_get_pm(smx_host_t vm)
   return simcall_BODY_vm_get_pm(vm);
 }
 
+void simcall_vm_set_bound(smx_host_t vm, double bound)
+{
+  /* will jump to SIMIX_pre_vm_set_bound in src/simix/smx_smurf_private.h */
+  simcall_BODY_vm_set_bound(vm, bound);
+}
+
 void simcall_host_get_params(smx_host_t vm, ws_params_t params)
 {
   /* will jump to SIMIX_pre_host_get_params in src/simix/smx_smurf_private.h */
index ce340c2..f53c188 100644 (file)
@@ -155,7 +155,7 @@ void SIMIX_pre_vm_migrate(smx_simcall_t simcall, smx_host_t ind_vm, smx_host_t i
 
 
 /**
- * \brief Function to get the physical host of the given the SIMIX VM host.
+ * \brief Function to get the physical host of the given SIMIX VM host.
  *
  * \param host the vm host to get_phys_host (a smx_host_t)
  */
@@ -171,6 +171,25 @@ void *SIMIX_pre_vm_get_pm(smx_simcall_t simcall, smx_host_t ind_vm)
 }
 
 
+/**
+ * \brief Function to set the CPU bound of the given SIMIX VM host.
+ *
+ * \param host the vm host (a smx_host_t)
+ * \param bound bound (a double)
+ */
+void SIMIX_vm_set_bound(smx_host_t ind_vm, double bound)
+{
+  /* jump to vm_ws_set_vm_bound(). */
+  surf_vm_workstation_model->extension.vm_workstation.set_vm_bound(ind_vm, bound);
+}
+
+void SIMIX_pre_vm_set_bound(smx_simcall_t simcall, smx_host_t ind_vm, double bound)
+{
+  SIMIX_vm_set_bound(ind_vm, bound);
+  SIMIX_simcall_answer(simcall);
+}
+
+
 /**
  * \brief Function to suspend a SIMIX VM host. This function stops the exection of the
  * VM. All the processes on this VM will pause. The state of the VM is
index 1ad14a7..dab20dc 100644 (file)
@@ -288,7 +288,8 @@ static double get_solved_value(surf_action_t cpu_action)
  * degraded due to virtualization overhead. The total CPU share that these
  * processes get is smaller than that of the VM process gets on a host
  * operating system. */
-const double virt_overhead = 0.95;
+// const double virt_overhead = 0.95;
+const double virt_overhead = 1;
 
 static double vm_ws_share_resources(surf_model_t workstation_model, double now)
 {
@@ -447,6 +448,21 @@ static void vm_ws_action_cancel(surf_action_t action)
 }
 
 
+/* Now we can set bound for each task by using MSG_task_set_bound. But, it does
+ * not work for the dummy CPU action of a VM. Here, we add the set_bound
+ * function for the dummy CPU action. */
+static void vm_ws_set_vm_bound(void *workstation, double bound)
+{
+  surf_resource_t ws = ((surf_resource_t) surf_workstation_resource_priv(workstation));
+  xbt_assert(ws->model->type == SURF_MODEL_TYPE_VM_WORKSTATION);
+  workstation_VM2013_t vm_ws = (workstation_VM2013_t) ws;
+
+  XBT_INFO("%p bound %f", vm_ws->cpu_action, bound);
+  surf_action_set_bound(vm_ws->cpu_action, bound);
+  get_bound(vm_ws->cpu_action);
+}
+
+
 static void surf_vm_workstation_model_init_internal(void)
 {
   surf_model_t model = surf_model_init();
@@ -523,6 +539,7 @@ static void surf_vm_workstation_model_init_internal(void)
   model->extension.vm_workstation.save          = vm_ws_save;
   model->extension.vm_workstation.restore       = vm_ws_restore;
   model->extension.vm_workstation.get_pm        = vm_ws_get_pm;
+  model->extension.vm_workstation.set_vm_bound  = vm_ws_set_vm_bound;
 
   model->extension.workstation.set_params    = ws_set_params;
   model->extension.workstation.get_params    = ws_get_params;
index 22e7953..1748f2b 100644 (file)
@@ -121,6 +121,10 @@ static int constraint_is_active(cpu_Cas01_t cpu_cas01)
   return found;
 }
 
+/* Each VM has a dummy CPU action on the PM layer. This CPU action works as the
+ * constraint (capacity) of the VM in the PM layer. If the VM does not have any
+ * active task, the dummy CPU action must be deactivated, so that the VM does
+ * not get any CPU share in the PM layer. */
 static void adjust_weight_of_dummy_cpu_actions(void)
 {
   /* iterate for all hosts including virtual machines */