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.


Add CPU mapper extension and fix to scheduler for time dilation
[palacios.git] / palacios / src / extensions / ext_sched_edf.c
1 /* 
2  * This file is part of the Palacios Virtual Machine Monitor developed
3  * by the V3VEE Project with funding from the United States National 
4  * Science Foundation and the Department of Energy.  
5  *
6  * The V3VEE Project is a joint project between Northwestern University
7  * and the University of New Mexico.  You can find out more at 
8  * http://www.v3vee.org
9  *
10  * Copyright (c) 2013, Oscar Mondragon <omondrag@cs.unm.edu>
11  * Copyright (c) 2013, Patrick G. Bridges <bridges@cs.unm.edu>
12  * Copyright (c) 2013, The V3VEE Project <http://www.v3vee.org> 
13  * All rights reserved.
14  *
15  * Author: Oscar Mondragon <omondrag@cs.unm.edu>
16  *         Patrick G. Bridges <bridges@cs.unm.edu>
17  *
18  * This is free software.  You are permitted to use,
19  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
20  */
21
22
23 #include <palacios/vmm.h>
24 #include <palacios/vmm_time.h>
25 #include <palacios/vm_guest.h>
26 #include <palacios/vmm_hashtable.h>
27 #include <palacios/vmm_config.h>
28 #include <palacios/vmm_extensions.h>
29 #include <palacios/vmm_rbtree.h>
30
31
32 #ifndef V3_CONFIG_DEBUG_EXT_SCHED_EDF
33 #undef PrintDebug
34 #define PrintDebug(fmt, args...)
35 #endif
36
37 /* Overview 
38  *
39  * EDF Scheduling
40  *
41  * The EDF scheduler uses a dynamic calculated priority as scheduling criteria to choose
42  * what thread will be scheduled.That priority is calculated according with the relative 
43  * deadline of the threads that are ready to run in the runqueue. This runqueue is a per-logical
44  * core data structure used to keep the runnable virtual cores (threads) allocated to that 
45  * logical core.The threads with less time before its deadline will receive better priorities. 
46  * The runqueue is sorted each time that a vCPU becomes runnable. At that time the vCPU is 
47  * enqueue and a new scheduling decision is taken. Each time a vCPU is scheduled, the parameter
48  * slice used time is set to zero and the current deadline is calculated using its period. Once
49  * the vCPU uses the logical core for slice seconds, that vCPU sleeps until its next scheduling 
50  * period (when is re-inserted in the runqueue) and  yields the CPU to allow the scheduling 
51  * of the vCPU with best priority in the runqueue. 
52  */
53
54 // Default configuration values for the EDF Scheduler
55 // time parameters in microseconds 
56
57 #define MAX_PERIOD 1000000000
58 #define MIN_PERIOD 50000
59 #define MAX_SLICE 1000000000
60 #define MIN_SLICE 10000
61 #define CPU_PERCENT 100
62 typedef uint64_t time_us;
63
64 /* 
65  * Per-core EDF Scheduling information 
66  */
67
68 struct vm_core_edf_sched {
69     struct guest_info *info;   // Core struct
70     struct rb_node node;      // red-black tree node
71     time_us period;           // Amount of time (us) during which the core may received a CPU allocation
72     time_us slice;            // Minimum amount of time (us) received for the core during each period 
73     time_us current_deadline; // Time (us) at which current core period ends
74     time_us used_time;        // Amount of time (us) of the slice used whiting the current period
75     time_us last_wakeup_time; // Time at which the last wakeup started for this core   
76     time_us remaining_time;   // Remaining time (us) before current core period ends (before current deadline) 
77     bool extra_time;          // Specifies if the virtual core is eligible to receive extra CPU time
78     int miss_deadline;        // Number of times the core has missed its deadline
79     time_us total_time;       // Total scheduled time for this core. For now used for debugging purposes 
80     int slice_overuse;        // Statistical purposes
81     time_us extra_time_given;     // Statistical
82 };
83
84 /* 
85  * Scheduler configuration
86  */
87
88 struct vm_edf_sched_config {
89     time_us min_slice;       // Minimum allowed slice
90     time_us max_slice;       // Maximum allowed slice
91     time_us min_period;      // Minimum allowed period
92     time_us max_period;      // Maximum allowed period
93     int cpu_percent;       // Percentange of CPU utilization for the scheduler in each physical CPU (100 or less)
94    
95 };
96
97 /* 
98  * Run queue structure. Per-logical core data structure  used to keep the runnable virtual cores (threads) allocated to that logical core 
99  * Contains a pointer to the red black tree, the structure of configuration options and other info
100  */
101
102 struct vm_edf_rq{
103     
104     //int cpu_id; // Physical CPU id
105     int cpu_u;  // CPU utilization (must be less or equal to the cpu_percent in vm_edf_sched_config)     
106     struct rb_root vCPUs_tree;  // Red-Black Tree
107     struct vm_edf_sched_config edf_config;      // Scheduling configuration structure
108     int nr_vCPU;        // Number of cores in the runqueue
109     struct vm_core_edf_sched *curr_vCPU;        // Current running CPU          
110     struct rb_node *rb_leftmost;     // vCPU with the earliest deadline (leftmost in the tree)
111     time_us last_sched_time;  // statistical purposes
112 };
113
114 /* 
115  * Basic functions for scheduling 
116  */
117
118 int v3_init_edf_scheduling();
119
120
121
122
123 /*
124  * init_edf_config: Initialize scheduler configuration
125  */
126
127 static void 
128 init_edf_config(struct vm_edf_sched_config *edf_config){
129
130     edf_config->min_slice = MIN_SLICE;
131     edf_config->max_slice = MAX_SLICE;
132     edf_config->min_period = MIN_PERIOD;
133     edf_config->max_period = MAX_PERIOD;
134     edf_config->cpu_percent = CPU_PERCENT;
135 }
136
137
138 /*
139  * priv_data_init: Initialize the run queue
140  */
141
142 int 
143 priv_data_init(struct v3_vm_info *vm){
144
145     PrintDebug(vm, VCORE_NONE,"EDF Sched. Initializing EDF Scheduling \n");
146
147     vm->sched_priv_data = V3_Malloc( vm->avail_cores * sizeof(struct vm_edf_rq));
148
149     if (!vm->sched_priv_data) {
150         PrintError(vm, VCORE_NONE,"Cannot allocate in priv_data in priv_data_init\n");
151         return -1;
152     }
153
154     int lcore = 0;
155   
156     PrintDebug(vm, VCORE_NONE,"EDF Sched. priv_data_init. Available cores %d\n", vm->avail_cores);
157
158     for(lcore = 0; lcore < vm->avail_cores ; lcore++){
159
160         PrintDebug(vm, VCORE_NONE,"EDF Sched. priv_data_init. Initializing logical core %d\n", lcore);
161
162         struct vm_edf_rq * edf_rq_list =   (struct vm_edf_rq *)vm->sched_priv_data;
163         struct vm_edf_rq * edf_rq = &edf_rq_list[lcore];
164     
165         edf_rq->vCPUs_tree = RB_ROOT;
166         edf_rq->cpu_u=0;
167         edf_rq->nr_vCPU=0;
168         edf_rq->curr_vCPU=NULL;
169         edf_rq->rb_leftmost=NULL;
170         edf_rq->last_sched_time=0;
171         init_edf_config(&edf_rq->edf_config);
172
173     }
174  
175    return 0;
176    
177 }
178
179 /*
180  * is_admissible_core: Decides if a core is admited to the red black tree according with 
181  * the admisibility formula.
182  */
183
184 static bool 
185 is_admissible_core(struct vm_core_edf_sched * new_sched_core, struct vm_edf_rq *runqueue){
186
187     struct v3_vm_info * vm = new_sched_core->info->vm_info;
188
189     struct v3_time *vm_ts = &(vm->time_state);
190     int tdf = vm_ts->td_denom;
191
192     int curr_utilization = runqueue->cpu_u;
193     int new_utilization = curr_utilization + ((100/tdf) * new_sched_core->slice / new_sched_core->period);
194     int cpu_percent = (runqueue->edf_config).cpu_percent; 
195
196     if (new_utilization <= cpu_percent)
197         return true;
198     else
199         return false;    
200
201 return true;
202 }
203
204
205 /*
206  * count_cores: Function useful to count the number of cores in a runqueue (Not used for now)
207  *
208  */
209
210
211 /*static int count_cores(struct vm_edf_rq *runqueue){
212
213   struct rb_node *node = v3_rb_first(&runqueue->vCPUs_tree);
214   struct vm_core_edf_sched *curr_core;
215   int number_cores = 0;    
216
217     while(node){
218         
219         curr_core = container_of(node, struct vm_core_edf_sched, node);
220         node = v3_rb_next(node);
221         number_cores++;
222     }
223
224    return number_cores;
225 }*/ 
226
227
228
229 /*
230  * insert_core_edf: Finds a place in the tree for a newly activated core, adds the node 
231  * and rebalaces the tree
232  */
233
234 static bool 
235 insert_core_edf(struct vm_core_edf_sched *core, struct vm_edf_rq *runqueue){
236
237     struct rb_node **new_core = &(runqueue->vCPUs_tree.rb_node);
238     struct rb_node *parent = NULL;
239     struct vm_core_edf_sched *curr_core;
240
241     // Find out place in the tree for the new core 
242     while (*new_core) {
243     
244         curr_core = container_of(*new_core, struct vm_core_edf_sched, node);
245         parent = *new_core;
246         
247         if (core->current_deadline < curr_core->current_deadline)
248             new_core = &((*new_core)->rb_left);
249         else if (core->current_deadline > curr_core->current_deadline)
250             new_core = &((*new_core)->rb_right);
251         else // Is Possible to have same current deadlines in both cores!
252             return false;
253     }
254     // Add new node and rebalance tree. 
255     rb_link_node(&core->node, parent, new_core);
256     v3_rb_insert_color(&core->node, &runqueue->vCPUs_tree);
257     
258     return true;
259  } 
260
261
262 /*
263  * get_curr_host_time: Calculates the current host time (microseconds)
264  */
265
266 static uint64_t 
267 get_curr_host_time(struct vm_core_time *core_time){
268
269     uint64_t cur_cycle = v3_get_host_time(core_time);
270     uint64_t cpu_khz = core_time->host_cpu_freq;
271     uint64_t curr_time_us = 1000 * cur_cycle / cpu_khz;
272
273     return curr_time_us;
274
275 }
276
277
278 /*
279  * next_start_period: Given the current host time and the period of a given vCPU, 
280  * calculates the time in which its next period starts.
281  *
282  */
283
284 static uint64_t 
285 next_start_period(uint64_t curr_time_us, uint64_t period_us){
286
287     uint64_t time_period_us = curr_time_us % period_us;
288     uint64_t remaining_time_us = period_us - time_period_us;
289     uint64_t next_start_us = curr_time_us + remaining_time_us;
290
291     return next_start_us;
292
293 }
294
295 /*
296  * get_runqueue: Get the runqueue assigned to a virtual core.
297  */
298
299 struct vm_edf_rq * get_runqueue(struct guest_info *info){
300
301     struct vm_edf_rq *runqueue_list = (struct vm_edf_rq *) info->vm_info->sched_priv_data;
302     struct vm_edf_rq *runqueue = &runqueue_list[info->pcpu_id]; 
303     return runqueue;
304 }
305
306
307 /*
308  * wakeup_core: Wakeup a given vCPU thread
309  */
310
311 static void 
312 wakeup_core(struct guest_info *info){
313
314     struct vm_core_edf_sched *core = info->sched_priv_data;
315     struct vm_edf_rq *runqueue = get_runqueue(info);
316
317     if (!info->core_thread) {
318               PrintError(info->vm_info, info,"ERROR: Tried to wakeup non-existent core thread vCPU_id %d \n",info->vcpu_id);
319     } 
320     else {
321
322         PrintDebug(info->vm_info, info,"EDF Sched. run_next_core. vcpu_id %d, logical id %d, Total time %llu, Miss_deadlines %d, slice_overuses %d extra_time %llu, thread (%p)\n", 
323             core->info->vcpu_id,
324             core->info->pcpu_id,
325             core->total_time,
326             core->miss_deadline,
327             core->slice_overuse,
328             core->extra_time_given,
329             (struct task_struct *)info->core_thread); 
330        
331        V3_Wakeup(info->core_thread);
332        core->last_wakeup_time = get_curr_host_time(&core->info->time_state);
333        runqueue->curr_vCPU = core;
334
335     }
336
337 }
338
339
340 /*
341  * activate_core - Moves a core to the red-black tree.
342  * used time is set to zero and current deadline is calculated 
343  */
344
345 static void 
346 activate_core(struct vm_core_edf_sched * core, struct vm_edf_rq *runqueue){
347
348     struct v3_vm_info * vm = core->info->vm_info;
349
350     struct v3_time *vm_ts = &(vm->time_state);
351     int tdf = vm_ts->td_denom;
352     
353     if (is_admissible_core(core, runqueue)){
354              
355         uint64_t curr_time_us = get_curr_host_time(&core->info->time_state);
356         uint64_t curr_deadline = next_start_period(curr_time_us, core->period);
357         
358         core->current_deadline = curr_deadline;
359         core->used_time=0; 
360         core->remaining_time=core->slice; 
361         
362         bool ins = insert_core_edf(core, runqueue);
363         /* 
364          * If not inserted is possible that there is other core with the same deadline.
365          * Then, the deadline is modified and try again 
366          */   
367         while(!ins){  
368             core->current_deadline ++;
369             ins = insert_core_edf(core, runqueue);  
370         }    
371      
372         runqueue->cpu_u += (100/tdf) * core->slice / core->period;
373         runqueue->nr_vCPU ++;
374         
375         /*
376          * If this is the first time to be activated pick first earliest deadline core to wakeup.
377          */
378
379         if(core->last_wakeup_time == 0){
380
381             struct vm_core_edf_sched *next_core;
382         
383             /*
384              * Pick first earliest deadline core
385              */
386             struct rb_node *node = v3_rb_first(&runqueue->vCPUs_tree);
387             next_core = container_of(node, struct vm_core_edf_sched, node);
388           
389             // Wakeup next_core
390             wakeup_core(next_core->info);
391        
392             //Sleep old core
393   
394             V3_Sleep(0);
395         }
396         
397       }
398       else 
399           PrintError(core->info->vm_info, core->info,"EDF Sched. activate_core. CPU cannot activate the core. It is not admissible");   
400 }
401
402
403 /*
404  * edf_sched_core_init: Initializes per core data structure and 
405  * calls activate function.
406  */
407
408 int 
409 edf_sched_core_init(struct guest_info * info){
410
411     struct vm_edf_rq *runqueue = get_runqueue(info);
412     struct vm_core_edf_sched *core_edf;
413
414     PrintDebug(info->vm_info, info,"EDF Sched. Initializing vcore %d\n", info->vcpu_id);
415
416     core_edf = (struct vm_core_edf_sched *) V3_Malloc(sizeof (struct vm_core_edf_sched));
417     if (!core_edf) {
418         PrintError(info->vm_info, info,"Cannot allocate private_data in edf_sched_core_init\n");
419         return -1;
420     }
421     info->sched_priv_data = core_edf;
422     
423     // Default configuration if not specified in configuration file  
424   
425     core_edf->info = info; 
426     core_edf->period = 500000;
427     core_edf->slice = 50000;
428     core_edf->used_time = 0;
429     core_edf->last_wakeup_time = 0;
430     core_edf->remaining_time = core_edf->slice;  
431     core_edf->miss_deadline = 0;
432     core_edf->extra_time = true;
433     core_edf->total_time = 0;
434     core_edf->slice_overuse = 0;
435     core_edf->extra_time_given = 0;
436
437     v3_cfg_tree_t * cfg_tree = core_edf->info->vm_info->cfg_data->cfg;
438     v3_cfg_tree_t * core = v3_cfg_subtree(v3_cfg_subtree(cfg_tree, "cores"), "core");
439     
440     while (core){
441         char *id = v3_cfg_val(core, "vcpu_id");
442         char *period = v3_cfg_val(core, "period");
443         char *slice = v3_cfg_val(core, "slice");
444         char *extra_time = v3_cfg_val(core, "extra_time");
445         
446         if (atoi(id) == core_edf->info->vcpu_id){
447    
448             core_edf->period = atoi(period);
449             core_edf->slice = atoi(slice);
450             core_edf->remaining_time = core_edf->slice;  
451             if (strcasecmp(extra_time, "true") == 0)
452                 core_edf->extra_time = true;
453             else    
454                 core_edf->extra_time = false;
455             break;
456         }
457         core = v3_cfg_next_branch(core);
458     }
459
460     activate_core(core_edf,runqueue); 
461     return 0; 
462 }
463
464 /*
465  * search_core_edf: Searches a core in the red-black tree by using its vcpu_id
466  */
467 static struct vm_core_edf_sched * 
468 search_core_edf(struct vm_core_edf_sched *core_edf, struct vm_edf_rq *runqueue){
469
470     struct rb_node *node = runqueue->vCPUs_tree.rb_node;
471         
472     while (node) {
473      
474         struct vm_core_edf_sched *core = container_of(node, struct vm_core_edf_sched, node);
475         
476         if (core_edf->current_deadline < core->current_deadline)
477             node = node->rb_left;
478         else if (core_edf->current_deadline > core->current_deadline)
479             node = node->rb_right;
480         else
481             if(core->info->vcpu_id == core_edf->info->vcpu_id){
482                 return core;
483             }
484     }
485     return NULL;
486 }
487
488
489 /* 
490  * delete_core_edf: Deletes a core from the red black tree, generally when it has 
491  * consumed its time slice within the current period.
492  */
493
494 static bool 
495 delete_core_edf( struct vm_core_edf_sched *core_edf  , struct vm_edf_rq *runqueue){
496
497     struct vm_core_edf_sched *core = search_core_edf(core_edf, runqueue);
498         if (core){ 
499
500             v3_rb_erase(&core->node, &runqueue->vCPUs_tree);  
501             return true;
502         } 
503         else{
504             PrintError(core->info->vm_info, core->info,"EDF Sched. delete_core_edf.Attempted to erase unexisting core");
505             return false;         
506         }
507 }
508
509
510 /*
511  * deactivate_core - Removes a core from the red-black tree.
512  */
513
514 static void 
515 deactivate_core(struct vm_core_edf_sched * core, struct vm_edf_rq *runqueue){
516
517      if(delete_core_edf(core, runqueue)){
518          runqueue->cpu_u -= 100 * core->slice / core->period;
519          runqueue->nr_vCPU -- ;
520      }          
521 }
522
523
524 /*
525  * pick_next_core: Returns the next core to be scheduled from the red black tree
526  */
527
528 static struct vm_core_edf_sched * 
529 pick_next_core(struct vm_edf_rq *runqueue){
530   
531   
532     /*
533      * Pick first earliest deadline core
534      */
535     struct rb_node *node = v3_rb_first(&runqueue->vCPUs_tree);
536     struct vm_core_edf_sched *next_core = container_of(node, struct vm_core_edf_sched, node);
537  
538     /* 
539      * Verify if the earliest deadline core has used its complete slice and return it if not
540      */
541
542     if (next_core->used_time < next_core->slice){
543         if(next_core->current_deadline < get_curr_host_time(&next_core->info->time_state))
544             next_core->miss_deadline++; 
545         return next_core;
546     }
547     /*
548      * If slice used, pick the next core that has not used its complete slice    
549      */
550
551     else {  
552         while(next_core->used_time >= next_core->slice){
553             
554             if(next_core->current_deadline < get_curr_host_time(&next_core->info->time_state) || !next_core->extra_time ){
555
556                 deactivate_core(next_core,runqueue); 
557                 activate_core(next_core,runqueue);
558            
559             }            
560
561             node = v3_rb_next(node);
562             if(node){
563                 next_core = container_of(node, struct vm_core_edf_sched, node);
564             }
565             else{   
566                 node = v3_rb_first(&runqueue->vCPUs_tree); // If all cores have used its slice return the first one
567             return container_of(node, struct vm_core_edf_sched, node);
568             }   
569
570         }
571     }
572
573     return next_core;
574 }
575
576
577 static void 
578 adjust_slice(struct guest_info * info, int used_time, int extra_time)
579 {
580     struct vm_core_edf_sched *core = info->sched_priv_data;
581     struct vm_edf_rq *runqueue = get_runqueue(info);
582
583     core->used_time = used_time;
584  
585     if (extra_time >= 0) {
586         core->used_time += extra_time;
587     }
588
589     if( core->used_time >= core->slice){     
590         deactivate_core(core,runqueue);
591         activate_core(core,runqueue);
592     }
593 }
594
595
596 /*
597  * run_next_core: Pick next core to be scheduled and wakeup it
598  */
599
600 static void 
601 run_next_core(struct guest_info *info, int used_time, int usec)
602 {
603     struct vm_core_edf_sched *core = info->sched_priv_data;
604     struct vm_core_edf_sched *next_core;
605     struct vm_edf_rq *runqueue = get_runqueue(info);
606    
607     /* The next core to be scheduled is choosen from the tree (Function pick_next_core). 
608      * The selected core is the one with the earliest deadline and with available time 
609      * to use within the current period (used_time < slice)   
610      */
611    
612      next_core = pick_next_core(runqueue); // Pick next core to schedule
613           
614      if (core != next_core){
615
616          // Wakeup next_core
617          wakeup_core(next_core->info);
618          core->total_time += used_time;
619
620         if (used_time > core->slice){
621             core->slice_overuse++;
622             core->extra_time_given += (used_time - core->slice);
623         }
624
625          // Sleep old core
626   
627          V3_Sleep(usec);
628        
629        }
630 }
631
632
633 /*
634  * edf_schedule: Scheduling function
635  */
636
637 static void
638 edf_schedule(struct guest_info * info, int usec){
639
640     uint64_t host_time = get_curr_host_time(&info->time_state);
641     struct vm_edf_rq *runqueue = get_runqueue(info);  
642     struct vm_core_edf_sched *core = (struct vm_core_edf_sched *) info->sched_priv_data;
643
644     uint64_t used_time = 0;
645     if(core->last_wakeup_time != 0) 
646         used_time =  host_time - core->last_wakeup_time;
647
648     if(usec == 0) runqueue->last_sched_time = host_time; // Called from edf_sched_scheduled
649     adjust_slice(core->info, host_time - core->last_wakeup_time, usec);
650
651     run_next_core(core->info,used_time, usec);
652     return;
653
654 }
655
656 /*
657  * edf_sched_schedule: Main scheduling function. Computes amount of time in period left,
658  * recomputing the current core's deadline if it has expired, then runs
659  * scheduler 
660  * It is called in the following cases:
661  *    A vCPU becomes runnable
662  *    The slice of the current vCPU was used
663  *    The period of a vCPU in the runqueue starts
664  *    Other case?? 
665  * TODO Something to do with extra time?
666  * TODO Check the use of remaining_time
667  */
668
669 void 
670 edf_sched_schedule(struct guest_info * info){
671
672     edf_schedule(info, 0);
673     return;
674 }
675
676 /*
677  * edf_sched_yield: Called when yielding the logical cpu for usec is needed
678  */
679
680 void 
681 edf_sched_yield(struct guest_info * info, int usec){
682  
683     edf_schedule(info, usec);
684     return;
685     
686 }
687
688 /*
689  * edf_sched_deinit: Frees edf scheduler data structures
690  */
691
692
693 int 
694 edf_sched_deinit(struct v3_vm_info *vm)
695 {
696     void *priv_data = vm->sched_priv_data;
697     
698     if (priv_data) 
699         V3_Free(priv_data);
700
701     return 0;
702
703 }
704
705 /*
706  * edf_sched_deinit: Frees virtual core data structures
707  */
708
709 int 
710 edf_sched_core_deinit(struct guest_info *core)
711 {
712     void *priv_data = core->sched_priv_data;
713     
714     if (priv_data) 
715         V3_Free(priv_data);
716
717     return 0;
718 }
719
720 int edf_sched_vm_init(struct v3_vm_info *vm){
721     return 0;
722 }
723
724 int edf_sched_admit(struct v3_vm_info *vm){
725
726     /*
727      * Initialize priv_data for the vm: 
728      * For EDF this is done here because we need the parameter
729      * avail_core which is set in v3_start_vm before the
730      * v3_scheduler_admit_vm function is called.
731      */
732    
733     priv_data_init(vm);
734
735     // TODO Admission
736      
737     return 0;
738 }
739
740
741 static struct vm_scheduler_impl edf_sched = {
742
743     .name = "edf",
744     .init = NULL,
745     .deinit = NULL,
746     .vm_init = edf_sched_vm_init,
747     .vm_deinit = NULL,
748     .core_init = edf_sched_core_init,
749     .core_deinit = edf_sched_core_deinit,
750     .schedule = edf_sched_schedule,
751     .yield = edf_sched_yield,
752     .admit = edf_sched_admit,
753     .remap = NULL,
754     .dvfs=NULL
755 };
756
757 static int 
758 ext_sched_edf_init() {
759     PrintDebug(VM_NONE, VCORE_NONE,"Sched. Creating (%s) scheduler\n",edf_sched.name);
760     return v3_register_scheduler(&edf_sched);
761 }
762
763 static int 
764 ext_sched_edf_vm_init() {
765     return 0;
766 }
767
768 static struct v3_extension_impl sched_edf_impl = {
769         .name = "EDF Scheduler",
770         .init = ext_sched_edf_init,
771         .vm_init = ext_sched_edf_vm_init,
772         .vm_deinit = NULL,
773         .core_init = NULL,
774         .core_deinit = NULL,
775         .on_entry = NULL,
776         .on_exit = NULL
777 };
778
779 register_extension(&sched_edf_impl);