2 * This file is part of the Palacios Virtual Machine Monitor developed
\r
3 * by the V3VEE Project with funding from the United States National
\r
4 * Science Foundation and the Department of Energy.
\r
6 * The V3VEE Project is a joint project between Northwestern University
\r
7 * and the University of New Mexico. You can find out more at
\r
8 * http://www.v3vee.org
\r
10 * Copyright (c) 2013, Oscar Mondragon <omondrag@cs.unm.edu>
\r
11 * Copyright (c) 2013, Patrick G. Bridges <bridges@cs.unm.edu>
\r
12 * Copyright (c) 2013, The V3VEE Project <http://www.v3vee.org>
\r
13 * All rights reserved.
\r
15 * Author: Oscar Mondragon <omondrag@cs.unm.edu>
\r
16 * Patrick G. Bridges <bridges@cs.unm.edu>
\r
18 * This is free software. You are permitted to use,
\r
19 * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
\r
22 #include <palacios/vmm.h>
\r
23 #include <palacios/vm_guest.h>
\r
24 #include <palacios/vmm_scheduler.h>
\r
25 #include <palacios/vmm_hashtable.h>
\r
27 #ifndef V3_CONFIG_DEBUG_SCHEDULER
\r
29 #define PrintDebug(fmt, args...)
\r
32 static char default_strategy[] = "host";
\r
33 static struct hashtable * master_scheduler_table = NULL;
\r
34 static int create_host_scheduler();
\r
36 static struct vm_scheduler_impl *scheduler = NULL;
\r
38 static uint_t scheduler_hash_fn(addr_t key) {
\r
39 char * name = (char *)key;
\r
40 return v3_hash_buffer((uint8_t *)name, strlen(name));
\r
43 static int scheduler_eq_fn(addr_t key1, addr_t key2) {
\r
44 char * name1 = (char *)key1;
\r
45 char * name2 = (char *)key2;
\r
47 return (strcmp(name1, name2) == 0);
\r
50 int V3_init_scheduling() {
\r
52 PrintDebug(VM_NONE, VCORE_NONE,"Initializing scheduler");
\r
54 master_scheduler_table = v3_create_htable(0, scheduler_hash_fn, scheduler_eq_fn);
\r
55 return create_host_scheduler();
\r
59 int v3_register_scheduler(struct vm_scheduler_impl *s) {
\r
61 PrintDebug(VM_NONE, VCORE_NONE,"Registering Scheduler (%s)\n", s->name);
\r
63 if (v3_htable_search(master_scheduler_table, (addr_t)(s->name))) {
\r
64 PrintError(VM_NONE, VCORE_NONE, "Multiple instances of scheduler (%s)\n", s->name);
\r
68 if (v3_htable_insert(master_scheduler_table,
\r
70 (addr_t)(s)) == 0) {
\r
71 PrintError(VM_NONE, VCORE_NONE, "Could not register scheduler (%s)\n", s->name);
\r
78 struct vm_scheduler_impl *v3_scheduler_lookup(char *name)
\r
80 return (struct vm_scheduler_impl *)v3_htable_search(master_scheduler_table, (addr_t)(name));
\r
83 int V3_enable_scheduler() {
\r
84 /* XXX Lookup the specified scheduler to use for palacios and use it */
\r
86 scheduler = v3_scheduler_lookup(default_strategy);
\r
87 PrintDebug(VM_NONE, VCORE_NONE,"Sched. Scheduler %s found",scheduler->name);
\r
90 PrintError(VM_NONE, VCORE_NONE,"Specified Palacios scheduler \"%s\" not found.\n", default_strategy);
\r
93 if (scheduler->init) {
\r
94 return scheduler->init();
\r
100 int v3_scheduler_register_vm(struct v3_vm_info *vm) {
\r
101 if (scheduler->vm_init) {
\r
102 return scheduler->vm_init(vm);
\r
107 int v3_scheduler_register_core(struct guest_info *core) {
\r
108 if (scheduler->core_init) {
\r
109 return scheduler->core_init(core);
\r
114 int v3_scheduler_admit_vm(struct v3_vm_info *vm) {
\r
115 if (scheduler->admit) {
\r
116 return scheduler->admit(vm);
\r
121 int v3_scheduler_notify_remap(struct v3_vm_info *vm) {
\r
122 if (scheduler->remap) {
\r
123 return scheduler->remap(vm);
\r
128 int v3_scheduler_notify_dvfs(struct v3_vm_info *vm) {
\r
129 if (scheduler->dvfs) {
\r
130 return scheduler->dvfs(vm);
\r
135 void v3_schedule(struct guest_info *core) {
\r
136 if (scheduler->schedule) {
\r
137 scheduler->schedule(core);
\r
141 void v3_yield(struct guest_info *core, int usec) {
\r
142 if (scheduler->yield) {
\r
143 scheduler->yield(core, usec);
\r
148 int host_sched_vm_init(struct v3_vm_info *vm)
\r
151 PrintDebug(vm, VCORE_NONE,"Sched. host_sched_init\n");
\r
153 char * schedule_hz_str = v3_cfg_val(vm->cfg_data->cfg, "schedule_hz");
\r
154 uint32_t sched_hz = 100;
\r
157 if (schedule_hz_str) {
\r
158 sched_hz = atoi(schedule_hz_str);
\r
161 PrintDebug(vm, VCORE_NONE,"CPU_KHZ = %d, schedule_freq=%p\n", V3_CPU_KHZ(),
\r
162 (void *)(addr_t)sched_hz);
\r
164 uint64_t yield_cycle_period = (V3_CPU_KHZ() * 1000) / sched_hz;
\r
165 vm->sched_priv_data = (void *)yield_cycle_period;
\r
170 int host_sched_core_init(struct guest_info *core)
\r
172 PrintDebug(core->vm_info, core,"Sched. host_sched_core_init\n");
\r
174 uint64_t t = v3_get_host_time(&core->time_state);
\r
175 core->sched_priv_data = (void *)t;
\r
180 void host_sched_schedule(struct guest_info *core)
\r
182 uint64_t cur_cycle;
\r
183 cur_cycle = v3_get_host_time(&core->time_state);
\r
185 if (cur_cycle > ( (uint64_t)core->sched_priv_data + (uint64_t)core->vm_info->sched_priv_data)) {
\r
189 uint64_t yield_start_cycle = (uint64_t) core->sched_priv_data;
\r
190 yield_start_cycle += (uint64_t)core->vm_info->sched_priv_data;
\r
191 core->sched_priv_data = (void *)yield_start_cycle;
\r
197 * unconditional cpu yield
\r
198 * if the yielding thread is a guest context, the guest quantum is reset on resumption
\r
199 * Non guest context threads should call this function with a NULL argument
\r
201 * usec <0 => the non-timed yield is used
\r
202 * usec >=0 => the timed yield is used, which also usually implies interruptible
\r
204 void host_sched_yield(struct guest_info * core, int usec) {
\r
205 uint64_t yield_start_cycle;
\r
211 yield_start_cycle = (uint64_t) core->sched_priv_data
\r
212 + (uint64_t)core->vm_info->sched_priv_data;
\r
213 core->sched_priv_data = (void *)yield_start_cycle;
\r
217 int host_sched_admit(struct v3_vm_info *vm){
\r
221 static struct vm_scheduler_impl host_sched_impl = {
\r
225 .vm_init = host_sched_vm_init,
\r
227 .core_init = host_sched_core_init,
\r
228 .core_deinit = NULL,
\r
229 .schedule = host_sched_schedule,
\r
230 .yield = host_sched_yield,
\r
231 .admit = host_sched_admit,
\r
236 static int create_host_scheduler()
\r
238 v3_register_scheduler(&host_sched_impl);
\r