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.


Basic host scheduler bug fix
[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
36 static struct vm_scheduler_impl *scheduler = NULL;
37
38 static uint_t scheduler_hash_fn(addr_t key) {
39     char * name = (char *)key;
40     return v3_hash_buffer((uint8_t *)name, strlen(name));
41 }
42
43 static int scheduler_eq_fn(addr_t key1, addr_t key2) {
44     char * name1 = (char *)key1;
45     char * name2 = (char *)key2;
46
47     return (strcmp(name1, name2) == 0);
48 }
49
50 int V3_init_scheduling() {
51    
52      PrintDebug(VM_NONE, VCORE_NONE,"Initializing scheduler");
53
54     master_scheduler_table = v3_create_htable(0, scheduler_hash_fn, scheduler_eq_fn);
55     return create_host_scheduler();
56 }
57
58
59 int v3_register_scheduler(struct vm_scheduler_impl *s) {
60
61     PrintDebug(VM_NONE, VCORE_NONE,"Registering Scheduler (%s)\n", s->name);
62
63     if (v3_htable_search(master_scheduler_table, (addr_t)(s->name))) {
64         PrintError(VM_NONE, VCORE_NONE, "Multiple instances of scheduler (%s)\n", s->name);
65         return -1;
66     }
67   
68     if (v3_htable_insert(master_scheduler_table,
69                          (addr_t)(s->name),
70                          (addr_t)(s)) == 0) {
71         PrintError(VM_NONE, VCORE_NONE, "Could not register scheduler (%s)\n", s->name);
72         return -1;
73     }
74
75     return 0;
76 }
77
78 struct vm_scheduler_impl *v3_scheduler_lookup(char *name)
79 {
80     return (struct vm_scheduler_impl *)v3_htable_search(master_scheduler_table, (addr_t)(name));
81 }
82
83 int V3_enable_scheduler() {
84     char *sched_name;
85
86     scheduler = NULL;
87     sched_name = v3_lookup_option("scheduler");
88
89     if (sched_name) {
90         scheduler = v3_scheduler_lookup(sched_name);
91     } 
92
93     if (!scheduler) {
94         scheduler = v3_scheduler_lookup(default_strategy);
95     }
96
97     if (!scheduler) {
98         PrintError(VM_NONE, VCORE_NONE,"Specified Palacios scheduler \"%s\" not found.\n", default_strategy);
99         return -1;
100     }
101
102     PrintDebug(VM_NONE, VCORE_NONE,"Scheduler %s found",scheduler->name);
103
104     if (scheduler->init) {
105         return scheduler->init();
106     } else {
107         return 0;
108     }
109 }
110
111 int v3_scheduler_register_vm(struct v3_vm_info *vm) {
112     if (scheduler->vm_init) {
113         return scheduler->vm_init(vm);
114     } else {
115         return 0;
116     }
117 }
118 int v3_scheduler_register_core(struct guest_info *core) {
119     if (scheduler->core_init) {
120         return scheduler->core_init(core);
121     } else {
122         return 0;
123     }
124 }
125 int v3_scheduler_admit_vm(struct v3_vm_info *vm) {
126     if (scheduler->admit) {
127         return scheduler->admit(vm);
128     } else {
129         return 0;
130     }
131 }
132 int v3_scheduler_notify_remap(struct v3_vm_info *vm) {
133     if (scheduler->remap) {
134         return scheduler->remap(vm);
135     } else {
136         return 0;
137     }
138 }
139 int v3_scheduler_notify_dvfs(struct v3_vm_info *vm) {
140     if (scheduler->dvfs) {
141         return scheduler->dvfs(vm);
142     } else {
143         return 0;
144     }
145 }
146 void v3_schedule(struct guest_info *core) {
147     if (scheduler->schedule) {
148         scheduler->schedule(core);
149     }
150     return;
151 }
152 void v3_yield(struct guest_info *core, int usec) {
153     if (scheduler->yield) {
154         scheduler->yield(core, usec);
155     } 
156     return;
157 }
158
159 int host_sched_vm_init(struct v3_vm_info *vm)
160 {
161
162     PrintDebug(vm, VCORE_NONE,"Sched. host_sched_init\n"); 
163
164     char * schedule_hz_str = v3_cfg_val(vm->cfg_data->cfg, "schedule_hz");
165     uint32_t sched_hz = 100;    
166
167
168     if (schedule_hz_str) {
169         sched_hz = atoi(schedule_hz_str);
170     }
171
172     PrintDebug(vm, VCORE_NONE,"CPU_KHZ = %d, schedule_freq=%p\n", V3_CPU_KHZ(), 
173                (void *)(addr_t)sched_hz);
174
175     uint64_t yield_cycle_period = (V3_CPU_KHZ() * 1000) / sched_hz;
176     vm->sched_priv_data = (void *)yield_cycle_period; 
177
178     return 0;
179 }
180
181 int host_sched_core_init(struct guest_info *core)
182 {
183     PrintDebug(core->vm_info, core,"Sched. host_sched_core_init\n"); 
184
185     uint64_t t = v3_get_host_time(&core->time_state); 
186     core->sched_priv_data = (void *)t;
187
188     return 0;
189 }
190
191 void host_sched_schedule(struct guest_info *core)
192 {
193     uint64_t cur_cycle;
194     cur_cycle = v3_get_host_time(&core->time_state);
195
196     if (cur_cycle > ( (uint64_t)core->sched_priv_data + (uint64_t)core->vm_info->sched_priv_data)) {
197         
198         V3_Yield();
199       
200         core->sched_priv_data = (void*)v3_get_host_time(&(core->time_state));
201       
202     }
203 }
204
205 /* 
206  * unconditional cpu yield 
207  * if the yielding thread is a guest context, the guest quantum is reset on resumption 
208  * Non guest context threads should call this function with a NULL argument
209  *
210  * usec <0  => the non-timed yield is used
211  * usec >=0 => the timed yield is used, which also usually implies interruptible
212  */
213 void host_sched_yield(struct guest_info * core, int usec) {
214
215     if (usec < 0) {
216         V3_Yield();
217     } else {
218         V3_Sleep(usec);
219     }
220     if (core){
221         core->sched_priv_data = (void*)v3_get_host_time(&(core->time_state));
222     }
223 }
224
225
226 int host_sched_admit(struct v3_vm_info *vm){
227     return 0;
228 }
229
230 static struct vm_scheduler_impl host_sched_impl = {
231     .name = "host",
232     .init = NULL,
233     .deinit = NULL,
234     .vm_init = host_sched_vm_init,
235     .vm_deinit = NULL,
236     .core_init = host_sched_core_init,
237     .core_deinit = NULL,
238     .schedule = host_sched_schedule,
239     .yield = host_sched_yield,
240     .admit = host_sched_admit,
241     .remap = NULL,
242     .dvfs=NULL
243 };
244
245 static int create_host_scheduler()
246 {
247         v3_register_scheduler(&host_sched_impl);
248         return 0;
249 }