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.


EDF scheduler bugfixes from Oscar
[palacios.git] / palacios / src / palacios / vmm_scheduler.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 #include <palacios/vmm.h>
23 #include <palacios/vm_guest.h>
24 #include <palacios/vmm_scheduler.h>
25 #include <palacios/vmm_hashtable.h>
26
27 #ifndef V3_CONFIG_DEBUG_SCHEDULER
28 #undef PrintDebug
29 #define PrintDebug(fmt, args...)
30 #endif
31
32 static char default_strategy[] = "host";
33 static struct hashtable * master_scheduler_table = NULL;
34 static int create_host_scheduler();
35 static int destroy_host_scheduler();
36
37 static struct vm_scheduler_impl *scheduler = NULL;
38
39 static uint_t scheduler_hash_fn(addr_t key) {
40     char * name = (char *)key;
41     return v3_hash_buffer((uint8_t *)name, strlen(name));
42 }
43
44 static int scheduler_eq_fn(addr_t key1, addr_t key2) {
45     char * name1 = (char *)key1;
46     char * name2 = (char *)key2;
47
48     return (strcmp(name1, name2) == 0);
49 }
50
51 int V3_init_scheduling() {
52
53      PrintDebug(VM_NONE, VCORE_NONE,"Initializing scheduler");
54
55     master_scheduler_table = v3_create_htable(0, scheduler_hash_fn, scheduler_eq_fn);
56     return create_host_scheduler();
57 }
58
59 int V3_deinit_scheduling()
60 {
61     destroy_host_scheduler();
62     v3_free_htable(master_scheduler_table,1,1);
63     return 0;
64 }
65
66
67 int v3_register_scheduler(struct vm_scheduler_impl *s) {
68
69     PrintDebug(VM_NONE, VCORE_NONE,"Registering Scheduler (%s)\n", s->name);
70
71     if (v3_htable_search(master_scheduler_table, (addr_t)(s->name))) {
72         PrintError(VM_NONE, VCORE_NONE, "Multiple instances of scheduler (%s)\n", s->name);
73         return -1;
74     }
75
76     if (v3_htable_insert(master_scheduler_table,
77                          (addr_t)(s->name),
78                          (addr_t)(s)) == 0) {
79         PrintError(VM_NONE, VCORE_NONE, "Could not register scheduler (%s)\n", s->name);
80         return -1;
81     }
82
83     return 0;
84 }
85
86
87 struct vm_scheduler_impl *v3_unregister_scheduler(char *name) {
88
89     PrintDebug(VM_NONE, VCORE_NONE,"Unregistering Scheduler (%s)\n",name);
90
91     struct vm_scheduler_impl *f = (struct vm_scheduler_impl *) v3_htable_remove(master_scheduler_table,(addr_t)(name),0);
92
93     if (!f) { 
94        PrintError(VM_NONE,VCORE_NONE,"Could not find Scheduler (%s)\n",name);
95        return NULL;
96     } else {
97        return f;
98     }
99 }
100
101
102
103
104 struct vm_scheduler_impl *v3_scheduler_lookup(char *name)
105 {
106     return (struct vm_scheduler_impl *)v3_htable_search(master_scheduler_table, (addr_t)(name));
107 }
108
109 int V3_enable_scheduler() {
110     char *sched_name;
111
112     scheduler = NULL;
113     sched_name = v3_lookup_option("scheduler");
114
115     if (sched_name) {
116         scheduler = v3_scheduler_lookup(sched_name);
117     }
118
119     if (!scheduler) {
120         scheduler = v3_scheduler_lookup(default_strategy);
121     }
122
123     if (!scheduler) {
124         PrintError(VM_NONE, VCORE_NONE,"Specified Palacios scheduler \"%s\" not found.\n", default_strategy);
125         return -1;
126     }
127
128     PrintDebug(VM_NONE, VCORE_NONE,"Scheduler %s found",scheduler->name);
129
130     if (scheduler->init) {
131         return scheduler->init();
132     } else {
133         return 0;
134     }
135 }
136
137 int V3_disable_scheduler()
138 {
139     if (scheduler->deinit) { 
140        return scheduler->deinit();
141     } else {
142        return 0;
143     }
144 }
145
146 int v3_scheduler_register_vm(struct v3_vm_info *vm) {
147     if (scheduler->vm_init) {
148         return scheduler->vm_init(vm);
149     } else {
150         return 0;
151     }
152 }
153 int v3_scheduler_register_core(struct guest_info *core) {
154     if (scheduler->core_init) {
155         return scheduler->core_init(core);
156     } else {
157         return 0;
158     }
159 }
160 int v3_scheduler_admit_vm(struct v3_vm_info *vm) {
161     if (scheduler->admit) {
162         return scheduler->admit(vm);
163     } else {
164         return 0;
165     }
166 }
167 int v3_scheduler_notify_remap(struct v3_vm_info *vm) {
168     if (scheduler->remap) {
169         return scheduler->remap(vm);
170     } else {
171         return 0;
172     }
173 }
174 int v3_scheduler_notify_dvfs(struct v3_vm_info *vm) {
175     if (scheduler->dvfs) {
176         return scheduler->dvfs(vm);
177     } else {
178         return 0;
179     }
180 }
181 void v3_schedule(struct guest_info *core) {
182     if (scheduler->schedule) {
183         scheduler->schedule(core);
184     }
185     return;
186 }
187 void v3_yield(struct guest_info *core, int usec) {
188     if (scheduler->yield) {
189         scheduler->yield(core, usec);
190     }
191     return;
192 }
193
194 int host_sched_vm_init(struct v3_vm_info *vm)
195 {
196
197     PrintDebug(vm, VCORE_NONE,"Sched. host_sched_init\n");
198
199     char * schedule_hz_str = v3_cfg_val(vm->cfg_data->cfg, "schedule_hz");
200     uint32_t sched_hz = 100;
201
202
203     if (schedule_hz_str) {
204         sched_hz = atoi(schedule_hz_str);
205     }
206
207     PrintDebug(vm, VCORE_NONE,"CPU_KHZ = %d, schedule_freq=%p\n", V3_CPU_KHZ(),
208                (void *)(addr_t)sched_hz);
209
210     uint64_t yield_cycle_period = (V3_CPU_KHZ() * 1000) / sched_hz;
211     vm->sched_priv_data = (void *)yield_cycle_period;
212
213     return 0;
214 }
215
216 int host_sched_core_init(struct guest_info *core)
217 {
218     PrintDebug(core->vm_info, core,"Sched. host_sched_core_init\n");
219
220     uint64_t t = v3_get_host_time(&core->time_state);
221     core->sched_priv_data = (void *)t;
222
223     return 0;
224 }
225
226 int host_sched_core_stop(struct guest_info *core){
227
228     v3_yield(NULL,-1);
229     return 0;
230 }
231
232
233 void host_sched_schedule(struct guest_info *core)
234 {
235     uint64_t cur_cycle;
236     cur_cycle = v3_get_host_time(&core->time_state);
237
238     if (cur_cycle > ( (uint64_t)core->sched_priv_data + (uint64_t)core->vm_info->sched_priv_data)) {
239
240         V3_Yield();
241
242 #if 0
243         uint64_t yield_start_cycle = (uint64_t) core->sched_priv_data;
244         yield_start_cycle +=  (uint64_t)core->vm_info->sched_priv_data;
245         core->sched_priv_data = (void *)yield_start_cycle;
246 #else
247         core->sched_priv_data = (void*)v3_get_host_time(&(core->time_state));
248 #endif
249
250     }
251 }
252
253 /*
254  * unconditional cpu yield
255  * if the yielding thread is a guest context, the guest quantum is reset on resumption
256  * Non guest context threads should call this function with a NULL argument
257  *
258  * usec <0  => the non-timed yield is used
259  * usec >=0 => the timed yield is used, which also usually implies interruptible
260  */
261 void host_sched_yield(struct guest_info * core, int usec) {
262     if (usec < 0) {
263         V3_Yield();
264     } else {
265         V3_Sleep(usec);
266     }
267     if (core){
268 #if 0
269     uint64_t yield_start_cycle;
270          yield_start_cycle = (uint64_t) core->sched_priv_data
271                              + (uint64_t)core->vm_info->sched_priv_data;
272          core->sched_priv_data = (void *)yield_start_cycle;
273 #else
274         core->sched_priv_data = (void*)v3_get_host_time(&(core->time_state));
275 #endif
276     }
277 }
278
279
280 int host_sched_admit(struct v3_vm_info *vm){
281     return 0;
282 }
283
284 int v3_scheduler_free_vm(struct v3_vm_info *vm) {
285     if (scheduler->vm_deinit) {
286         return scheduler->vm_deinit(vm);
287     } else {
288         return 0;
289     }
290 }
291
292 int v3_scheduler_free_core(struct guest_info *core) {
293     if (scheduler->core_deinit) {
294         return scheduler->core_deinit(core);
295     } else {
296         return 0;
297     }
298 }
299
300
301 int v3_scheduler_stop_core(struct guest_info *core){
302     if (scheduler->core_stop) {
303         return scheduler->core_stop(core);
304     } else {
305         return 0;
306     }
307 }
308
309 static struct vm_scheduler_impl host_sched_impl = {
310     .name = "host",
311     .init = NULL,
312     .deinit = NULL,
313     .vm_init = host_sched_vm_init,
314     .vm_deinit = NULL,
315     .core_init = host_sched_core_init,
316     .core_stop = host_sched_core_stop,
317     .core_deinit = NULL,
318     .schedule = host_sched_schedule,
319     .yield = host_sched_yield,
320     .admit = host_sched_admit,
321     .remap = NULL,
322     .dvfs=NULL
323 };
324
325 static int create_host_scheduler()
326 {
327         v3_register_scheduler(&host_sched_impl);
328         return 0;
329 }
330
331 static int destroy_host_scheduler()
332 {
333        v3_unregister_scheduler(host_sched_impl.name);
334        return 0;
335 }