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.


null check in host_sched_yield
[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     PrintDebug(VM_NONE, VCORE_NONE,"Scheduler %s found",scheduler->name);
98     
99     if (!scheduler) {
100         PrintError(VM_NONE, VCORE_NONE,"Specified Palacios scheduler \"%s\" not found.\n", default_strategy);
101         return -1;
102     }
103     if (scheduler->init) {
104         return scheduler->init();
105     } else {
106         return 0;
107     }
108 }
109
110 int v3_scheduler_register_vm(struct v3_vm_info *vm) {
111     if (scheduler->vm_init) {
112         return scheduler->vm_init(vm);
113     } else {
114         return 0;
115     }
116 }
117 int v3_scheduler_register_core(struct guest_info *core) {
118     if (scheduler->core_init) {
119         return scheduler->core_init(core);
120     } else {
121         return 0;
122     }
123 }
124 int v3_scheduler_admit_vm(struct v3_vm_info *vm) {
125     if (scheduler->admit) {
126         return scheduler->admit(vm);
127     } else {
128         return 0;
129     }
130 }
131 int v3_scheduler_notify_remap(struct v3_vm_info *vm) {
132     if (scheduler->remap) {
133         return scheduler->remap(vm);
134     } else {
135         return 0;
136     }
137 }
138 int v3_scheduler_notify_dvfs(struct v3_vm_info *vm) {
139     if (scheduler->dvfs) {
140         return scheduler->dvfs(vm);
141     } else {
142         return 0;
143     }
144 }
145 void v3_schedule(struct guest_info *core) {
146     if (scheduler->schedule) {
147         scheduler->schedule(core);
148     }
149     return;
150 }
151 void v3_yield(struct guest_info *core, int usec) {
152     if (scheduler->yield) {
153         scheduler->yield(core, usec);
154     } 
155     return;
156 }
157
158 int host_sched_vm_init(struct v3_vm_info *vm)
159 {
160
161     PrintDebug(vm, VCORE_NONE,"Sched. host_sched_init\n"); 
162
163     char * schedule_hz_str = v3_cfg_val(vm->cfg_data->cfg, "schedule_hz");
164     uint32_t sched_hz = 100;    
165
166
167     if (schedule_hz_str) {
168         sched_hz = atoi(schedule_hz_str);
169     }
170
171     PrintDebug(vm, VCORE_NONE,"CPU_KHZ = %d, schedule_freq=%p\n", V3_CPU_KHZ(), 
172                (void *)(addr_t)sched_hz);
173
174     uint64_t yield_cycle_period = (V3_CPU_KHZ() * 1000) / sched_hz;
175     vm->sched_priv_data = (void *)yield_cycle_period; 
176
177     return 0;
178 }
179
180 int host_sched_core_init(struct guest_info *core)
181 {
182     PrintDebug(core->vm_info, core,"Sched. host_sched_core_init\n"); 
183
184     uint64_t t = v3_get_host_time(&core->time_state); 
185     core->sched_priv_data = (void *)t;
186
187     return 0;
188 }
189
190 void host_sched_schedule(struct guest_info *core)
191 {
192     uint64_t cur_cycle;
193     cur_cycle = v3_get_host_time(&core->time_state);
194
195     if (cur_cycle > ( (uint64_t)core->sched_priv_data + (uint64_t)core->vm_info->sched_priv_data)) {
196         
197         V3_Yield();
198       
199         uint64_t yield_start_cycle = (uint64_t) core->sched_priv_data;
200         yield_start_cycle +=  (uint64_t)core->vm_info->sched_priv_data;
201         core->sched_priv_data = (void *)yield_start_cycle;
202       
203     }
204 }
205
206 /* 
207  * unconditional cpu yield 
208  * if the yielding thread is a guest context, the guest quantum is reset on resumption 
209  * Non guest context threads should call this function with a NULL argument
210  *
211  * usec <0  => the non-timed yield is used
212  * usec >=0 => the timed yield is used, which also usually implies interruptible
213  */
214 void host_sched_yield(struct guest_info * core, int usec) {
215     uint64_t yield_start_cycle;
216     if (usec < 0) {
217         V3_Yield();
218     } else {
219         V3_Sleep(usec);
220     }
221     if(core){
222         yield_start_cycle = (uint64_t) core->sched_priv_data
223                             + (uint64_t)core->vm_info->sched_priv_data;
224         core->sched_priv_data = (void *)yield_start_cycle;
225     }
226 }
227
228
229 int host_sched_admit(struct v3_vm_info *vm){
230     return 0;
231 }
232
233 static struct vm_scheduler_impl host_sched_impl = {
234     .name = "host",
235     .init = NULL,
236     .deinit = NULL,
237     .vm_init = host_sched_vm_init,
238     .vm_deinit = NULL,
239     .core_init = host_sched_core_init,
240     .core_deinit = NULL,
241     .schedule = host_sched_schedule,
242     .yield = host_sched_yield,
243     .admit = host_sched_admit,
244     .remap = NULL,
245     .dvfs=NULL
246 };
247
248 static int create_host_scheduler()
249 {
250         v3_register_scheduler(&host_sched_impl);
251         return 0;
252 }