Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Update of scheduling infrastructure and newest version of EDF scheduler
[palacios.git] / palacios / src / extensions / ext_sched_edf.c
index 953fa4e..b09b463 100644 (file)
@@ -8,6 +8,7 @@
  * http://www.v3vee.org\r
  *\r
  * Copyright (c) 2013, Oscar Mondragon <omondrag@cs.unm.edu>\r
+ * Copyright (c) 2013, Patrick G. Bridges <bridges@cs.unm.edu>\r
  * Copyright (c) 2013, The V3VEE Project <http://www.v3vee.org> \r
  * All rights reserved.\r
  *\r
@@ -25,8 +26,7 @@
 #include <palacios/vmm_hashtable.h>\r
 #include <palacios/vmm_config.h>\r
 #include <palacios/vmm_extensions.h>\r
-#include <palacios/vmm_edf_sched.h>\r
-\r
+#include <palacios/vmm_rbtree.h>\r
 \r
 \r
 #ifndef V3_CONFIG_DEBUG_EDF_SCHED\r
 #define MAX_SLICE 1000000000\r
 #define MIN_SLICE 10000\r
 #define CPU_PERCENT 100\r
+typedef uint64_t time_us;\r
+\r
+/* \r
+ * Per-core EDF Scheduling information \r
+ */\r
+\r
+struct vm_core_edf_sched {\r
+    struct guest_info *info;   // Core struct\r
+    struct rb_node node;      // red-black tree node\r
+    time_us period;           // Amount of time (us) during which the core may received a CPU allocation\r
+    time_us slice;            // Minimum amount of time (us) received for the core during each period \r
+    time_us current_deadline; // Time (us) at which current core period ends\r
+    time_us used_time;        // Amount of time (us) of the slice used whiting the current period\r
+    time_us last_wakeup_time; // Time at which the last wakeup started for this core   \r
+    time_us remaining_time;   // Remaining time (us) before current core period ends (before current deadline) \r
+    bool extra_time;          // Specifies if the virtual core is eligible to receive extra CPU time\r
+    int miss_deadline;        // Number of times the core has missed its deadline\r
+    time_us total_time;       // Total scheduled time for this core. For now used for debugging purposes \r
+    int slice_overuse;        // Statistical purposes\r
+    time_us extra_time_given;     // Statistical\r
+};\r
+\r
+/* \r
+ * Scheduler configuration\r
+ */\r
+\r
+struct vm_edf_sched_config {\r
+    time_us min_slice;       // Minimum allowed slice\r
+    time_us max_slice;       // Maximum allowed slice\r
+    time_us min_period;      // Minimum allowed period\r
+    time_us max_period;      // Maximum allowed period\r
+    int cpu_percent;       // Percentange of CPU utilization for the scheduler in each physical CPU (100 or less)\r
+   \r
+};\r
+\r
+/* \r
+ * Run queue structure. Per-logical core data structure  used to keep the runnable virtual cores (threads) allocated to that logical core \r
+ * Contains a pointer to the red black tree, the structure of configuration options and other info\r
+ */\r
+\r
+struct vm_edf_rq{\r
+    \r
+    //int cpu_id; // Physical CPU id\r
+    int cpu_u; // CPU utilization (must be less or equal to the cpu_percent in vm_edf_sched_config)     \r
+    struct rb_root vCPUs_tree; // Red-Black Tree\r
+    struct vm_edf_sched_config edf_config;     // Scheduling configuration structure\r
+    int nr_vCPU;       // Number of cores in the runqueue\r
+    struct vm_core_edf_sched *curr_vCPU;       // Current running CPU          \r
+    struct rb_node *rb_leftmost;     // vCPU with the earliest deadline (leftmost in the tree)\r
+    time_us last_sched_time;  // statistical purposes\r
+};\r
+\r
+/* \r
+ * Basic functions for scheduling \r
+ */\r
+\r
+int v3_init_edf_scheduling();\r
+\r
+\r
 \r
 \r
 /*\r
@@ -77,31 +136,30 @@ init_edf_config(struct vm_edf_sched_config *edf_config){
 \r
 \r
 /*\r
- * edf_sched_init: Initialize the run queue\r
+ * priv_data_init: Initialize the run queue\r
  */\r
 \r
 int \r
-edf_sched_init(struct v3_vm_info *vm){\r
+priv_data_init(struct v3_vm_info *vm){\r
 \r
-    PrintDebug(vm, VCORE_NONE,"EDF Sched. Initializing vm %s\n", vm->name);\r
+    PrintDebug(vm, VCORE_NONE,"EDF Sched. Initializing EDF Scheduling \n");\r
 \r
-    struct vm_sched_state *sched_state = &vm->sched; \r
-    sched_state->priv_data = V3_Malloc( vm->avail_cores * sizeof(struct vm_edf_rq));\r
+    vm->sched_priv_data = V3_Malloc( vm->avail_cores * sizeof(struct vm_edf_rq));\r
 \r
-    if (!sched_state->priv_data) {\r
-       PrintError(vm, VCORE_NONE,"Cannot allocate in priv_data in edf_sched_init\n");\r
+    if (!vm->sched_priv_data) {\r
+       PrintError(vm, VCORE_NONE,"Cannot allocate in priv_data in priv_data_init\n");\r
        return -1;\r
     }\r
 \r
     int lcore = 0;\r
   \r
-    PrintDebug(vm, VCORE_NONE,"EDF Sched. edf_sched_init. Available cores %d\n", vm->avail_cores);\r
+    PrintDebug(vm, VCORE_NONE,"EDF Sched. priv_data_init. Available cores %d\n", vm->avail_cores);\r
 \r
     for(lcore = 0; lcore < vm->avail_cores ; lcore++){\r
 \r
-        PrintDebug(vm, VCORE_NONE,"EDF Sched. edf_sched_init. Initializing logical core %d\n", lcore);\r
+        PrintDebug(vm, VCORE_NONE,"EDF Sched. priv_data_init. Initializing logical core %d\n", lcore);\r
 \r
-        struct vm_edf_rq * edf_rq_list =   (struct vm_edf_rq *) sched_state->priv_data;\r
+        struct vm_edf_rq * edf_rq_list =   (struct vm_edf_rq *)vm->sched_priv_data;\r
         struct vm_edf_rq * edf_rq = &edf_rq_list[lcore];\r
     \r
         edf_rq->vCPUs_tree = RB_ROOT;\r
@@ -118,7 +176,6 @@ edf_sched_init(struct v3_vm_info *vm){
    \r
 }\r
 \r
-\r
 /*\r
  * is_admissible_core: Decides if a core is admited to the red black tree according with \r
  * the admisibility formula.\r
@@ -136,6 +193,7 @@ is_admissible_core(struct vm_core_edf_sched * new_sched_core, struct vm_edf_rq *
     else\r
        return false;    \r
 \r
+return true;\r
 }\r
 \r
 \r
@@ -235,7 +293,7 @@ next_start_period(uint64_t curr_time_us, uint64_t period_us){
 \r
 struct vm_edf_rq * get_runqueue(struct guest_info *info){\r
 \r
-    struct vm_edf_rq *runqueue_list = (struct vm_edf_rq *) info->vm_info->sched.priv_data;\r
+    struct vm_edf_rq *runqueue_list = (struct vm_edf_rq *) info->vm_info->sched_priv_data;\r
     struct vm_edf_rq *runqueue = &runqueue_list[info->pcpu_id]; \r
     return runqueue;\r
 }\r
@@ -248,7 +306,7 @@ struct vm_edf_rq * get_runqueue(struct guest_info *info){
 static void \r
 wakeup_core(struct guest_info *info){\r
 \r
-    struct vm_core_edf_sched *core = info->core_sched.priv_data;\r
+    struct vm_core_edf_sched *core = info->sched_priv_data;\r
     struct vm_edf_rq *runqueue = get_runqueue(info);\r
 \r
     if (!info->core_thread) {\r
@@ -350,7 +408,7 @@ edf_sched_core_init(struct guest_info * info){
        PrintError(info->vm_info, info,"Cannot allocate private_data in edf_sched_core_init\n");\r
        return -1;\r
     }\r
-    info->core_sched.priv_data = core_edf;\r
+    info->sched_priv_data = core_edf;\r
     \r
     // Default configuration if not specified in configuration file  \r
   \r
@@ -509,7 +567,7 @@ pick_next_core(struct vm_edf_rq *runqueue){
 static void \r
 adjust_slice(struct guest_info * info, int used_time, int extra_time)\r
 {\r
-    struct vm_core_edf_sched *core = info->core_sched.priv_data;\r
+    struct vm_core_edf_sched *core = info->sched_priv_data;\r
     struct vm_edf_rq *runqueue = get_runqueue(info);\r
 \r
     core->used_time = used_time;\r
@@ -532,7 +590,7 @@ adjust_slice(struct guest_info * info, int used_time, int extra_time)
 static void \r
 run_next_core(struct guest_info *info, int used_time, int usec)\r
 {\r
-    struct vm_core_edf_sched *core = info->core_sched.priv_data;\r
+    struct vm_core_edf_sched *core = info->sched_priv_data;\r
     struct vm_core_edf_sched *next_core;\r
     struct vm_edf_rq *runqueue = get_runqueue(info);\r
    \r
@@ -571,7 +629,7 @@ edf_schedule(struct guest_info * info, int usec){
 \r
     uint64_t host_time = get_curr_host_time(&info->time_state);\r
     struct vm_edf_rq *runqueue = get_runqueue(info);  \r
-    struct vm_core_edf_sched *core = (struct vm_core_edf_sched *) info->core_sched.priv_data;\r
+    struct vm_core_edf_sched *core = (struct vm_core_edf_sched *) info->sched_priv_data;\r
 \r
     uint64_t used_time = 0;\r
     if(core->last_wakeup_time != 0) \r
@@ -625,13 +683,8 @@ edf_sched_yield(struct guest_info * info, int usec){
 int \r
 edf_sched_deinit(struct v3_vm_info *vm)\r
 {\r
-\r
-    struct vm_scheduler  * sched = vm->sched.sched;\r
-    void *priv_data = vm->sched.priv_data;\r
+    void *priv_data = vm->sched_priv_data;\r
     \r
-    if (sched) \r
-        V3_Free(sched); \r
-\r
     if (priv_data) \r
         V3_Free(priv_data);\r
 \r
@@ -646,32 +699,53 @@ edf_sched_deinit(struct v3_vm_info *vm)
 int \r
 edf_sched_core_deinit(struct guest_info *core)\r
 {\r
-\r
-    struct vm_scheduler  * sched = core->core_sched.sched;\r
-    void *priv_data = core->core_sched.priv_data;\r
+    void *priv_data = core->sched_priv_data;\r
     \r
-    if (sched) \r
-        V3_Free(sched); \r
-\r
     if (priv_data) \r
         V3_Free(priv_data);\r
 \r
     return 0;\r
 }\r
 \r
+int edf_sched_vm_init(struct v3_vm_info *vm){\r
+    return 0;\r
+}\r
+\r
+int edf_sched_admit(struct v3_vm_info *vm){\r
+\r
+    /*\r
+     * Initialize priv_data for the vm: \r
+     * For EDF this is done here because we need the parameter\r
+     * avail_core which is set in v3_start_vm before the\r
+     * v3_scheduler_admit_vm function is called.\r
+     */\r
+   \r
+    priv_data_init(vm);\r
+\r
+    // TODO Admission\r
+     \r
+    return 0;\r
+}\r
+\r
+\r
 static struct vm_scheduler_impl edf_sched = {\r
-       .name = "edf",\r
-       .init = edf_sched_init,\r
-       .deinit = edf_sched_deinit,\r
-       .core_init = edf_sched_core_init,\r
-       .core_deinit = edf_sched_core_deinit,\r
-       .schedule = edf_sched_schedule,\r
-       .yield = edf_sched_yield\r
+\r
+    .name = "edf",\r
+    .init = NULL,\r
+    .deinit = NULL,\r
+    .vm_init = edf_sched_vm_init,\r
+    .vm_deinit = NULL,\r
+    .core_init = edf_sched_core_init,\r
+    .core_deinit = edf_sched_core_deinit,\r
+    .schedule = edf_sched_schedule,\r
+    .yield = edf_sched_yield,\r
+    .admit = edf_sched_admit,\r
+    .remap = NULL,\r
+    .dvfs=NULL\r
 };\r
 \r
 static int \r
 ext_sched_edf_init() {\r
-       \r
     PrintDebug(VM_NONE, VCORE_NONE,"Sched. Creating (%s) scheduler\n",edf_sched.name);\r
     return v3_register_scheduler(&edf_sched);\r
 }\r