Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
further cosmetics in simix VM, which really needs them
[simgrid.git] / src / simix / smx_vm.cpp
1 /* Copyright (c) 2007-2015. The SimGrid Team. All rights reserved.          */
2
3 /* This program is free software; you can redistribute it and/or modify it
4  * under the terms of the license (GNU LGPL) which comes with this package. */
5
6 #include "smx_private.h"
7 #include "mc/mc.h"
8 #include "src/surf/virtual_machine.hpp"
9 #include "src/surf/HostImpl.hpp"
10
11 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(simix_vm, simix, "Logging specific to SIMIX Virtual Machines");
12
13 /* works for VMs and PMs */
14 static long host_get_ramsize(sg_host_t vm, int *overcommit)
15 {
16   s_vm_params_t params;
17   vm->extension<simgrid::surf::HostImpl>()->getParams(&params);
18
19   if (overcommit)
20     *overcommit = params.overcommit;
21
22   return params.ramsize;
23 }
24
25 /* **** start a VM **** */
26 static int __can_be_started(sg_host_t vm)
27 {
28   sg_host_t pm = surf_vm_get_pm(vm);
29
30   int pm_overcommit = 0;
31   long pm_ramsize = host_get_ramsize(pm, &pm_overcommit);
32   long vm_ramsize = host_get_ramsize(vm, nullptr);
33
34   if (!pm_ramsize) {
35     /* We assume users do not want to care about ramsize. */
36     return 1;
37   }
38
39   if (pm_overcommit) {
40     XBT_VERB("%s allows memory overcommit.", sg_host_get_name(pm));
41     return 1;
42   }
43
44   long total_ramsize_of_vms = 0;
45   xbt_dynar_t dyn_vms = pm->extension<simgrid::surf::HostImpl>()->getVms();
46   {
47     unsigned int cursor = 0;
48     sg_host_t another_vm;
49     xbt_dynar_foreach(dyn_vms, cursor, another_vm) {
50       long another_vm_ramsize = host_get_ramsize(vm, nullptr);
51       total_ramsize_of_vms += another_vm_ramsize;
52     }
53   }
54
55   if (vm_ramsize > pm_ramsize - total_ramsize_of_vms) {
56     XBT_WARN("cannnot start %s@%s due to memory shortage: vm_ramsize %ld, free %ld, pm_ramsize %ld (bytes).",
57         sg_host_get_name(vm), sg_host_get_name(pm),
58         vm_ramsize, pm_ramsize - total_ramsize_of_vms, pm_ramsize);
59     xbt_dynar_free(&dyn_vms);
60     return 0;
61   }
62
63   return 1;
64 }
65
66 void SIMIX_vm_start(sg_host_t vm)
67 {
68   if (__can_be_started(vm))
69     static_cast<simgrid::surf::VirtualMachine*>(
70       vm->extension<simgrid::surf::HostImpl>()
71     )->setState(SURF_VM_STATE_RUNNING);
72   else
73     THROWF(vm_error, 0, "The VM %s cannot be started", vm->name().c_str());
74 }
75
76
77 e_surf_vm_state_t SIMIX_vm_get_state(sg_host_t vm)
78 {
79   return static_cast<simgrid::surf::VirtualMachine*>(
80     vm->extension<simgrid::surf::HostImpl>()
81   )->getState();
82 }
83
84 /**
85  * @brief Function to migrate a SIMIX VM host.
86  *
87  * @param host the vm host to migrate (a sg_host_t)
88  */
89 void SIMIX_vm_migrate(sg_host_t vm, sg_host_t dst_pm)
90 {
91   /* precopy migration makes the VM temporally paused */
92   xbt_assert(SIMIX_vm_get_state(vm) == SURF_VM_STATE_SUSPENDED);
93
94   /* jump to vm_ws_xigrate(). this will update the vm location. */
95   surf_vm_migrate(vm, dst_pm);
96 }
97
98 /**
99  * @brief Encompassing simcall to prevent the removal of the src or the dst node at the end of a VM migration
100  *  The simcall actually invokes the following calls: 
101  *     simcall_vm_migrate(vm, dst_pm); 
102  *     simcall_vm_resume(vm);
103  *
104  * It is called at the end of the migration_rx_fun function from msg/msg_vm.c
105  *
106  * @param vm VM to migrate
107  * @param src_pm  Source physical host
108  * @param dst_pmt Destination physical host
109  */
110 void SIMIX_vm_migratefrom_resumeto(sg_host_t vm, sg_host_t src_pm, sg_host_t dst_pm)
111 {
112   /* Update the vm location */
113   SIMIX_vm_migrate(vm, dst_pm);
114  
115   /* Resume the VM */
116   smx_actor_t self = SIMIX_process_self(); 
117   SIMIX_vm_resume(vm, self->simcall.issuer);
118
119
120 /**
121  * @brief Function to get the physical host of the given SIMIX VM host.
122  *
123  * @param host the vm host to get_phys_host (a sg_host_t)
124  */
125 void *SIMIX_vm_get_pm(sg_host_t host)
126 {
127   return surf_vm_get_pm(host);
128 }
129
130 /**
131  * @brief Function to set the CPU bound of the given SIMIX VM host.
132  *
133  * @param host the vm host (a sg_host_t)
134  * @param bound bound (a double)
135  */
136 void SIMIX_vm_set_bound(sg_host_t vm, double bound)
137 {
138   surf_vm_set_bound(vm, bound);
139 }
140
141 /**
142  * @brief Function to suspend a SIMIX VM host. This function stops the execution of the
143  * VM. All the processes on this VM will pause. The state of the VM is
144  * preserved on memory. We can later resume it again.
145  *
146  * @param vm the vm host to suspend (a sg_host_t)
147  */
148 void SIMIX_vm_suspend(sg_host_t vm, smx_actor_t issuer)
149 {
150   if (SIMIX_vm_get_state(vm) != SURF_VM_STATE_RUNNING)
151     THROWF(vm_error, 0, "VM(%s) is not running", vm->name().c_str());
152
153   XBT_DEBUG("suspend VM(%s), where %d processes exist", vm->name().c_str(), xbt_swag_size(sg_host_simix(vm)->process_list));
154
155   /* jump to vm_ws_suspend. The state will be set. */
156   surf_vm_suspend(vm);
157
158   smx_actor_t smx_process, smx_process_safe;
159   xbt_swag_foreach_safe(smx_process, smx_process_safe, sg_host_simix(vm)->process_list) {
160     XBT_DEBUG("suspend %s", smx_process->name.c_str());
161     SIMIX_process_suspend(smx_process, issuer);
162   }
163
164   XBT_DEBUG("suspend all processes on the VM done done");
165 }
166
167 void simcall_HANDLER_vm_suspend(smx_simcall_t simcall, sg_host_t vm)
168 {
169   xbt_assert(simcall->issuer->host != vm, "cannot suspend the VM where I run");
170
171   SIMIX_vm_suspend(vm, simcall->issuer);
172
173   XBT_DEBUG("simcall_HANDLER_vm_suspend done");
174 }
175
176
177 /**
178  * @brief Function to resume a SIMIX VM host. This function restart the execution of the
179  * VM. All the processes on this VM will run again.
180  *
181  * @param vm the vm host to resume (a sg_host_t)
182  */
183 void SIMIX_vm_resume(sg_host_t vm, smx_actor_t issuer)
184 {
185   if (SIMIX_vm_get_state(vm) != SURF_VM_STATE_SUSPENDED)
186     THROWF(vm_error, 0, "VM(%s) was not suspended", vm->name().c_str());
187
188   XBT_DEBUG("resume VM(%s), where %d processes exist",
189       vm->name().c_str(), xbt_swag_size(sg_host_simix(vm)->process_list));
190
191   /* jump to vm_ws_resume() */
192   surf_vm_resume(vm);
193
194   smx_actor_t smx_process, smx_process_safe;
195   xbt_swag_foreach_safe(smx_process, smx_process_safe, sg_host_simix(vm)->process_list) {
196     XBT_DEBUG("resume %s", smx_process->name.c_str());
197     SIMIX_process_resume(smx_process, issuer);
198   }
199 }
200
201 void simcall_HANDLER_vm_resume(smx_simcall_t simcall, sg_host_t vm)
202 {
203   SIMIX_vm_resume(vm, simcall->issuer);
204 }
205
206
207 /**
208  * @brief Function to save a SIMIX VM host.
209  * This function is the same as vm_suspend, but the state of the VM is saved to the disk, and not preserved on memory.
210  * We can later restore it again.
211  *
212  * @param vm the vm host to save (a sg_host_t)
213  */
214 void SIMIX_vm_save(sg_host_t vm, smx_actor_t issuer)
215 {
216   const char *name = sg_host_get_name(vm);
217
218   if (SIMIX_vm_get_state(vm) != SURF_VM_STATE_RUNNING)
219     THROWF(vm_error, 0, "VM(%s) is not running", name);
220
221   XBT_DEBUG("save VM(%s), where %d processes exist", name, xbt_swag_size(sg_host_simix(vm)->process_list));
222
223   /* jump to vm_ws_save() */
224   surf_vm_save(vm);
225
226   smx_actor_t smx_process, smx_process_safe;
227   xbt_swag_foreach_safe(smx_process, smx_process_safe, sg_host_simix(vm)->process_list) {
228     XBT_DEBUG("suspend %s", smx_process->name.c_str());
229     SIMIX_process_suspend(smx_process, issuer);
230   }
231 }
232
233 void simcall_HANDLER_vm_save(smx_simcall_t simcall, sg_host_t vm)
234 {
235   SIMIX_vm_save(vm, simcall->issuer);
236 }
237
238
239 /**
240  * @brief Function to restore a SIMIX VM host. This function restart the execution of the
241  * VM. All the processes on this VM will run again.
242  *
243  * @param vm the vm host to restore (a sg_host_t)
244  */
245 void SIMIX_vm_restore(sg_host_t vm, smx_actor_t issuer)
246 {
247   if (SIMIX_vm_get_state(vm) != SURF_VM_STATE_SAVED)
248     THROWF(vm_error, 0, "VM(%s) was not saved", vm->name().c_str());
249
250   XBT_DEBUG("restore VM(%s), where %d processes exist",
251       vm->name().c_str(), xbt_swag_size(sg_host_simix(vm)->process_list));
252
253   /* jump to vm_ws_restore() */
254   surf_vm_resume(vm);
255
256   smx_actor_t smx_process, smx_process_safe;
257   xbt_swag_foreach_safe(smx_process, smx_process_safe, sg_host_simix(vm)->process_list) {
258     XBT_DEBUG("resume %s", smx_process->name.c_str());
259     SIMIX_process_resume(smx_process, issuer);
260   }
261 }
262
263 void simcall_HANDLER_vm_restore(smx_simcall_t simcall, sg_host_t vm)
264 {
265   SIMIX_vm_restore(vm, simcall->issuer);
266 }
267
268
269 /**
270  * @brief Function to shutdown a SIMIX VM host. This function powers off the
271  * VM. All the processes on this VM will be killed. But, the state of the VM is
272  * preserved on memory. We can later start it again.
273  *
274  * @param vm the VM to shutdown (a sg_host_t)
275  */
276 void SIMIX_vm_shutdown(sg_host_t vm, smx_actor_t issuer)
277 {
278   if (SIMIX_vm_get_state(vm) != SURF_VM_STATE_RUNNING)
279     THROWF(vm_error, 0, "VM(%s) is not running", vm->name().c_str());
280
281   XBT_DEBUG("shutdown VM %s, that contains %d processes",
282       vm->name().c_str(),xbt_swag_size(sg_host_simix(vm)->process_list));
283
284   smx_actor_t smx_process, smx_process_safe;
285   xbt_swag_foreach_safe(smx_process, smx_process_safe, sg_host_simix(vm)->process_list) {
286     XBT_DEBUG("kill %s", smx_process->name.c_str());
287     SIMIX_process_kill(smx_process, issuer);
288   }
289
290   /* FIXME: we may have to do something at the surf layer, e.g., vcpu action */
291   static_cast<simgrid::surf::VirtualMachine*>(
292     vm->extension<simgrid::surf::HostImpl>()
293   )->setState(SURF_VM_STATE_CREATED);
294 }
295
296 void simcall_HANDLER_vm_shutdown(smx_simcall_t simcall, sg_host_t vm)
297 {
298   SIMIX_vm_shutdown(vm, simcall->issuer);
299 }
300
301 /**
302  * @brief Function to destroy a SIMIX VM host.
303  *
304  * @param vm the vm host to destroy (a sg_host_t)
305  */
306 void SIMIX_vm_destroy(sg_host_t vm)
307 {
308   /* this code basically performs a similar thing like SIMIX_host_destroy() */
309   XBT_DEBUG("destroy %s", vm->name().c_str());
310
311   /* FIXME: this is really strange that everything fails if the next line is removed.
312    * This is as if we shared these data with the PM, which definitely should not be the case...
313    *
314    * We need to test that suspending a VM does not suspends the processes running on its PM, for example.
315    * Or we need to simplify this code enough to make it actually readable (but this sounds harder than testing)
316    */
317   vm->extension_set<simgrid::simix::Host>(nullptr);
318
319   /* Don't free these things twice: they are the ones of my physical host */
320   vm->pimpl_cpu = nullptr;
321   vm->pimpl_netcard = nullptr;
322 }