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.


Cleanup and sanity-checking of divide-by-zero and floating point use bugs (Coverity...
[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     // important not to remove any keys or values since we don't know
63     // if they are malloced or other
64     v3_free_htable(master_scheduler_table,0,0);
65     return 0;
66 }
67
68
69 int v3_register_scheduler(struct vm_scheduler_impl *s) {
70
71     PrintDebug(VM_NONE, VCORE_NONE,"Registering Scheduler (%s)\n", s->name);
72
73     if (v3_htable_search(master_scheduler_table, (addr_t)(s->name))) {
74         PrintError(VM_NONE, VCORE_NONE, "Multiple instances of scheduler (%s)\n", s->name);
75         return -1;
76     }
77
78     if (v3_htable_insert(master_scheduler_table,
79                          (addr_t)(s->name),
80                          (addr_t)(s)) == 0) {
81         PrintError(VM_NONE, VCORE_NONE, "Could not register scheduler (%s)\n", s->name);
82         return -1;
83     }
84
85     return 0;
86 }
87
88
89 struct vm_scheduler_impl *v3_unregister_scheduler(char *name) {
90
91     PrintDebug(VM_NONE, VCORE_NONE,"Unregistering Scheduler (%s)\n",name);
92
93     struct vm_scheduler_impl *f = (struct vm_scheduler_impl *) v3_htable_remove(master_scheduler_table,(addr_t)(name),0);
94
95     if (!f) { 
96        PrintError(VM_NONE,VCORE_NONE,"Could not find Scheduler (%s)\n",name);
97        return NULL;
98     } else {
99        return f;
100     }
101 }
102
103
104
105
106 struct vm_scheduler_impl *v3_scheduler_lookup(char *name)
107 {
108     return (struct vm_scheduler_impl *)v3_htable_search(master_scheduler_table, (addr_t)(name));
109 }
110
111 int V3_enable_scheduler() {
112     char *sched_name;
113
114     scheduler = NULL;
115     sched_name = v3_lookup_option("scheduler");
116
117     if (sched_name) {
118         scheduler = v3_scheduler_lookup(sched_name);
119     }
120
121     if (!scheduler) {
122         scheduler = v3_scheduler_lookup(default_strategy);
123     }
124
125     if (!scheduler) {
126         PrintError(VM_NONE, VCORE_NONE,"Specified Palacios scheduler \"%s\" not found.\n", default_strategy);
127         return -1;
128     }
129
130     PrintDebug(VM_NONE, VCORE_NONE,"Scheduler %s found",scheduler->name);
131
132     if (scheduler->init) {
133         return scheduler->init();
134     } else {
135         return 0;
136     }
137 }
138
139 int V3_disable_scheduler()
140 {
141     if (scheduler->deinit) { 
142        return scheduler->deinit();
143     } else {
144        return 0;
145     }
146 }
147
148 int v3_scheduler_register_vm(struct v3_vm_info *vm) {
149     if (scheduler->vm_init) {
150         return scheduler->vm_init(vm);
151     } else {
152         return 0;
153     }
154 }
155 int v3_scheduler_register_core(struct guest_info *core) {
156     if (scheduler->core_init) {
157         return scheduler->core_init(core);
158     } else {
159         return 0;
160     }
161 }
162 int v3_scheduler_admit_vm(struct v3_vm_info *vm) {
163     if (scheduler->admit) {
164         return scheduler->admit(vm);
165     } else {
166         return 0;
167     }
168 }
169 int v3_scheduler_notify_remap(struct v3_vm_info *vm) {
170     if (scheduler->remap) {
171         return scheduler->remap(vm);
172     } else {
173         return 0;
174     }
175 }
176 int v3_scheduler_notify_dvfs(struct v3_vm_info *vm) {
177     if (scheduler->dvfs) {
178         return scheduler->dvfs(vm);
179     } else {
180         return 0;
181     }
182 }
183 void v3_schedule(struct guest_info *core) {
184     if (scheduler->schedule) {
185         scheduler->schedule(core);
186     }
187     return;
188 }
189 void v3_yield(struct guest_info *core, int usec) {
190     if (scheduler->yield) {
191         scheduler->yield(core, usec);
192     }
193     return;
194 }
195
196 int host_sched_vm_init(struct v3_vm_info *vm)
197 {
198
199     PrintDebug(vm, VCORE_NONE,"Sched. host_sched_init\n");
200
201     char * schedule_hz_str = v3_cfg_val(vm->cfg_data->cfg, "schedule_hz");
202     uint32_t sched_hz = 100;
203
204
205     if (schedule_hz_str) {
206         sched_hz = atoi(schedule_hz_str);
207         if (sched_hz==0) { 
208             PrintError(vm, VCORE_NONE,"Cannot set Sched Hz to 0\n");
209             return -1;
210         }
211     }
212
213     PrintDebug(vm, VCORE_NONE,"CPU_KHZ = %d, schedule_freq=%p\n", V3_CPU_KHZ(),
214                (void *)(addr_t)sched_hz);
215
216     uint64_t yield_cycle_period = (V3_CPU_KHZ() * 1000) / sched_hz;
217     vm->sched_priv_data = (void *)yield_cycle_period;
218
219     return 0;
220 }
221
222 int host_sched_core_init(struct guest_info *core)
223 {
224     PrintDebug(core->vm_info, core,"Sched. host_sched_core_init\n");
225
226     uint64_t t = v3_get_host_time(&core->time_state);
227     core->sched_priv_data = (void *)t;
228
229     return 0;
230 }
231
232 int host_sched_core_stop(struct guest_info *core){
233
234     v3_yield(NULL,-1);
235     return 0;
236 }
237
238
239 void host_sched_schedule(struct guest_info *core)
240 {
241     uint64_t cur_cycle;
242     cur_cycle = v3_get_host_time(&core->time_state);
243
244     if (cur_cycle > ( (uint64_t)core->sched_priv_data + (uint64_t)core->vm_info->sched_priv_data)) {
245
246         V3_Yield();
247
248 #if 0
249         uint64_t yield_start_cycle = (uint64_t) core->sched_priv_data;
250         yield_start_cycle +=  (uint64_t)core->vm_info->sched_priv_data;
251         core->sched_priv_data = (void *)yield_start_cycle;
252 #else
253         core->sched_priv_data = (void*)v3_get_host_time(&(core->time_state));
254 #endif
255
256     }
257 }
258
259 /*
260  * unconditional cpu yield
261  * if the yielding thread is a guest context, the guest quantum is reset on resumption
262  * Non guest context threads should call this function with a NULL argument
263  *
264  * usec <0  => the non-timed yield is used
265  * usec >=0 => the timed yield is used, which also usually implies interruptible
266  */
267 void host_sched_yield(struct guest_info * core, int usec) {
268     if (usec < 0) {
269         V3_Yield();
270     } else {
271         V3_Sleep(usec);
272     }
273     if (core){
274 #if 0
275     uint64_t yield_start_cycle;
276          yield_start_cycle = (uint64_t) core->sched_priv_data
277                              + (uint64_t)core->vm_info->sched_priv_data;
278          core->sched_priv_data = (void *)yield_start_cycle;
279 #else
280         core->sched_priv_data = (void*)v3_get_host_time(&(core->time_state));
281 #endif
282     }
283 }
284
285
286 int host_sched_admit(struct v3_vm_info *vm){
287     return 0;
288 }
289
290 int v3_scheduler_free_vm(struct v3_vm_info *vm) {
291     if (scheduler->vm_deinit) {
292         return scheduler->vm_deinit(vm);
293     } else {
294         return 0;
295     }
296 }
297
298 int v3_scheduler_free_core(struct guest_info *core) {
299     if (scheduler->core_deinit) {
300         return scheduler->core_deinit(core);
301     } else {
302         return 0;
303     }
304 }
305
306
307 int v3_scheduler_stop_core(struct guest_info *core){
308     if (scheduler->core_stop) {
309         return scheduler->core_stop(core);
310     } else {
311         return 0;
312     }
313 }
314
315 static struct vm_scheduler_impl host_sched_impl = {
316     .name = "host",
317     .init = NULL,
318     .deinit = NULL,
319     .vm_init = host_sched_vm_init,
320     .vm_deinit = NULL,
321     .core_init = host_sched_core_init,
322     .core_stop = host_sched_core_stop,
323     .core_deinit = NULL,
324     .schedule = host_sched_schedule,
325     .yield = host_sched_yield,
326     .admit = host_sched_admit,
327     .remap = NULL,
328     .dvfs=NULL
329 };
330
331 static int create_host_scheduler()
332 {
333         v3_register_scheduler(&host_sched_impl);
334         return 0;
335 }
336
337 static int destroy_host_scheduler()
338 {
339        v3_unregister_scheduler(host_sched_impl.name);
340        // no deletion of this since it's a pointer to a global var
341        return 0;
342 }