4 * Created on: Nov 12, 2013
7 #include "vm_workstation_hl13.hpp"
8 #include "cpu_cas01.hpp"
10 XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(surf_vm_workstation);
12 void surf_vm_workstation_model_init_current_default(void){
13 if (surf_cpu_model_vm) {
14 surf_vm_workstation_model = new WorkstationVMHL13Model();
15 ModelPtr model = static_cast<ModelPtr>(surf_vm_workstation_model);
17 xbt_dynar_push(model_list, &model);
18 xbt_dynar_push(model_list_invoke, &model);
26 WorkstationVMHL13Model::WorkstationVMHL13Model() : WorkstationVMModel() {
27 p_cpuModel = surf_cpu_model_vm;
30 void WorkstationVMHL13Model::updateActionsState(double /*now*/, double /*delta*/){
34 xbt_dynar_t WorkstationVMHL13Model::getRoute(WorkstationPtr src, WorkstationPtr dst){
35 XBT_DEBUG("ws_get_route");
36 return surf_network_model->getRoute(src->p_netElm, dst->p_netElm);
39 ActionPtr WorkstationVMHL13Model::communicate(WorkstationPtr src, WorkstationPtr dst, double size, double rate){
40 return surf_network_model->communicate(src->p_netElm, dst->p_netElm, size, rate);
43 /* ind means ''indirect'' that this is a reference on the whole dict_elm
44 * structure (i.e not on the surf_resource_private infos) */
46 void WorkstationVMHL13Model::createResource(const char *name, void *ind_phys_workstation)
48 WorkstationVMHL13Ptr ws = new WorkstationVMHL13(this, name, NULL, static_cast<surf_resource_t>(ind_phys_workstation));
50 xbt_lib_set(host_lib, name, SURF_WKS_LEVEL, static_cast<ResourcePtr>(ws));
53 * - check how network requests are scheduled between distinct processes competing for the same card.
57 static inline double get_solved_value(CpuActionPtr cpu_action)
59 return cpu_action->getVariable()->value;
62 /* In the real world, processes on the guest operating system will be somewhat
63 * degraded due to virtualization overhead. The total CPU share that these
64 * processes get is smaller than that of the VM process gets on a host
65 * operating system. */
66 // const double virt_overhead = 0.95;
67 const double virt_overhead = 1;
69 double WorkstationVMHL13Model::shareResources(double now)
71 /* TODO: udpate action's cost with the total cost of processes on the VM. */
74 /* 0. Make sure that we already calculated the resource share at the physical
77 ModelPtr ws_model = static_cast<ModelPtr>(surf_workstation_model);
78 ModelPtr vm_ws_model = static_cast<ModelPtr>(surf_vm_workstation_model);
79 unsigned int index_of_pm_ws_model = xbt_dynar_search(model_list_invoke, &ws_model);
80 unsigned int index_of_vm_ws_model = xbt_dynar_search(model_list_invoke, &vm_ws_model);
81 xbt_assert((index_of_pm_ws_model < index_of_vm_ws_model), "Cannot assume surf_workstation_model comes before");
83 /* Another option is that we call sub_ws->share_resource() here. The
84 * share_resource() function has no side-effect. We can call it here to
89 /* 1. Now we know how many resource should be assigned to each virtual
90 * machine. We update constraints of the virtual machine layer.
93 * If we have two virtual machine (VM1 and VM2) on a physical machine (PM1).
94 * X1 + X2 = C (Equation 1)
96 * the resource share of VM1: X1
97 * the resource share of VM2: X2
98 * the capacity of PM1: C
100 * Then, if we have two process (P1 and P2) on VM1.
101 * X1_1 + X1_2 = X1 (Equation 2)
103 * the resource share of P1: X1_1
104 * the resource share of P2: X1_2
105 * the capacity of VM1: X1
107 * Equation 1 was solved in the physical machine layer.
108 * Equation 2 is solved in the virtual machine layer (here).
109 * X1 must be passed to the virtual machine laye as a constraint value.
113 /* iterate for all hosts including virtual machines */
114 xbt_lib_cursor_t cursor;
117 xbt_lib_foreach(host_lib, cursor, key, ind_host) {
118 WorkstationPtr ws = dynamic_cast<WorkstationPtr>(
119 static_cast<ResourcePtr>(ind_host[SURF_WKS_LEVEL]));
120 CpuPtr cpu = dynamic_cast<CpuPtr>(
121 static_cast<ResourcePtr>(ind_host[SURF_CPU_LEVEL]));
125 /* skip if it is not a virtual machine */
126 if (ws->getModel() != static_cast<ModelPtr>(surf_vm_workstation_model))
128 xbt_assert(cpu, "cpu-less workstation");
130 /* It is a virtual machine, so we can cast it to workstation_VM2013_t */
131 WorkstationVMPtr ws_vm = dynamic_cast<WorkstationVMPtr>(ws);
133 double solved_value = get_solved_value(reinterpret_cast<CpuActionPtr>(ws_vm->p_action));
134 XBT_DEBUG("assign %f to vm %s @ pm %s", solved_value,
135 ws->getName(), ws_vm->p_subWs->getName());
137 // TODO: check lmm_update_constraint_bound() works fine instead of the below manual substitution.
138 // cpu_cas01->constraint->bound = solved_value;
139 xbt_assert(cpu->getModel() == static_cast<ModelPtr>(surf_cpu_model_vm));
140 lmm_system_t vcpu_system = cpu->getModel()->getMaxminSystem();
141 lmm_update_constraint_bound(vcpu_system, cpu->getConstraint(), virt_overhead * solved_value);
145 /* 2. Calculate resource share at the virtual machine layer. */
146 adjustWeightOfDummyCpuActions();
148 double min_by_cpu = p_cpuModel->shareResources(now);
149 double min_by_net = surf_network_model->shareResources(now);
150 double min_by_sto = -1;
151 if (p_cpuModel == surf_cpu_model_pm)
152 min_by_sto = surf_storage_model->shareResources(now);
154 XBT_DEBUG("model %p, %s min_by_cpu %f, %s min_by_net %f, %s min_by_sto %f",
155 this, surf_cpu_model_pm->getName(), min_by_cpu,
156 surf_network_model->getName(), min_by_net,
157 surf_storage_model->getName(), min_by_sto);
159 double ret = max(max(min_by_cpu, min_by_net), min_by_sto);
160 if (min_by_cpu >= 0.0 && min_by_cpu < ret)
162 if (min_by_net >= 0.0 && min_by_net < ret)
164 if (min_by_sto >= 0.0 && min_by_sto < ret)
167 /* FIXME: 3. do we have to re-initialize our cpu_action object? */
169 /* iterate for all hosts including virtual machines */
170 xbt_lib_foreach(host_lib, cursor, key, ind_host) {
171 WorkstationCLM03Ptr ws_clm03 = ind_host[SURF_WKS_LEVEL];
173 /* skip if it is not a virtual machine */
176 if (ws_clm03->getModel() != surf_vm_workstation_model)
179 /* It is a virtual machine, so we can cast it to workstation_VM2013_t */
182 WorkstationVM2013Ptr ws_vm2013 = (workstation_VM2013_t) ws_clm03;
183 XBT_INFO("cost %f remains %f start %f finish %f", ws_vm2013->cpu_action->cost,
184 ws_vm2013->cpu_action->remains,
185 ws_vm2013->cpu_action->start,
186 ws_vm2013->cpu_action->finish
190 void *ind_sub_host = xbt_lib_get_elm_or_null(host_lib, ws_vm2013->sub_ws->generic_resource.getName);
191 surf_cpu_model_pm->action_unref(ws_vm2013->cpu_action);
192 /* FIXME: this means busy loop? */
193 // ws_vm2013->cpu_action = surf_cpu_model_pm->extension.cpu.execute(ind_sub_host, GUESTOS_NOISE);
194 ws_vm2013->cpu_action = surf_cpu_model_pm->extension.cpu.execute(ind_sub_host, 0);
205 ActionPtr WorkstationVMHL13Model::executeParallelTask(int workstation_nb,
206 void **workstation_list,
207 double *computation_amount,
208 double *communication_amount,
210 #define cost_or_zero(array,pos) ((array)?(array)[pos]:0.0)
211 if ((workstation_nb == 1)
212 && (cost_or_zero(communication_amount, 0) == 0.0))
213 return ((WorkstationCLM03Ptr)workstation_list[0])->execute(computation_amount[0]);
214 else if ((workstation_nb == 1)
215 && (cost_or_zero(computation_amount, 0) == 0.0))
216 return communicate((WorkstationCLM03Ptr)workstation_list[0], (WorkstationCLM03Ptr)workstation_list[0],communication_amount[0], rate);
217 else if ((workstation_nb == 2)
218 && (cost_or_zero(computation_amount, 0) == 0.0)
219 && (cost_or_zero(computation_amount, 1) == 0.0)) {
223 for (i = 0; i < workstation_nb * workstation_nb; i++) {
224 if (cost_or_zero(communication_amount, i) > 0.0) {
226 value = cost_or_zero(communication_amount, i);
230 return communicate((WorkstationCLM03Ptr)workstation_list[0], (WorkstationCLM03Ptr)workstation_list[1],value, rate);
234 THROW_UNIMPLEMENTED; /* This model does not implement parallel tasks */
242 WorkstationVMHL13::WorkstationVMHL13(WorkstationVMModelPtr model, const char* name, xbt_dict_t props,
243 surf_resource_t ind_phys_workstation)
244 : WorkstationVM(model, name, props, NULL, NULL)
246 WorkstationPtr sub_ws = dynamic_cast<WorkstationPtr>(
247 static_cast<ResourcePtr>(
248 surf_workstation_resource_priv(ind_phys_workstation)));
250 /* Currently, we assume a VM has no storage. */
253 /* Currently, a VM uses the network resource of its physical host. In
254 * host_lib, this network resource object is refered from two different keys.
255 * When deregistering the reference that points the network resource object
256 * from the VM name, we have to make sure that the system does not call the
257 * free callback for the network resource object. The network resource object
258 * is still used by the physical machine. */
259 p_netElm = static_cast<RoutingEdgePtr>(xbt_lib_get_or_null(host_lib, sub_ws->getName(), ROUTING_HOST_LEVEL));
260 xbt_lib_set(host_lib, name, ROUTING_HOST_LEVEL, p_netElm);
263 p_currentState = SURF_VM_STATE_CREATED;
265 // //// CPU RELATED STUFF ////
266 // Roughly, create a vcpu resource by using the values of the sub_cpu one.
267 CpuCas01Ptr sub_cpu = dynamic_cast<CpuCas01Ptr>(
268 static_cast<ResourcePtr>(
269 surf_cpu_resource_priv(ind_phys_workstation)));
271 /* We can assume one core and cas01 cpu for the first step.
272 * Do xbt_lib_set(host_lib, name, SURF_CPU_LEVEL, cpu) if you get the resource. */
274 p_cpu = static_cast<CpuCas01ModelPtr>(surf_cpu_model_vm)->createResource(name, // name
275 sub_cpu->p_powerPeakList, // host->power_peak,
277 1, // host->power_scale,
278 NULL, // host->power_trace,
279 1, // host->core_amount,
280 SURF_RESOURCE_ON, // host->initial_state,
281 NULL, // host->state_trace,
282 NULL); // host->properties,
284 /* We create cpu_action corresponding to a VM process on the host operating system. */
285 /* FIXME: TODO: we have to peridocally input GUESTOS_NOISE to the system? how ? */
286 // vm_ws->cpu_action = surf_cpu_model_pm->extension.cpu.execute(ind_phys_workstation, GUESTOS_NOISE);
287 p_action = dynamic_cast<CpuActionPtr>(sub_cpu->execute(0));
289 /* The SURF_WKS_LEVEL at host_lib saves workstation_CLM03 objects. Please
290 * note workstation_VM2013 objects, inheriting the workstation_CLM03
291 * structure, are also saved there.
293 * If you want to get a workstation_VM2013 object from host_lib, see
294 * ws->generic_resouce.model->type first. If it is
295 * SURF_MODEL_TYPE_VM_WORKSTATION, you can cast ws to vm_ws. */
296 XBT_INFO("Create VM(%s)@PM(%s) with %ld mounted disks", name, sub_ws->getName(), xbt_dynar_length(p_storage));
300 * A physical host does not disapper in the current SimGrid code, but a VM may
301 * disapper during a simulation.
303 WorkstationVMHL13::~WorkstationVMHL13()
305 /* ind_phys_workstation equals to smx_host_t */
306 surf_resource_t ind_vm_workstation = xbt_lib_get_elm_or_null(host_lib, getName());
308 /* Before clearing the entries in host_lib, we have to pick up resources. */
309 CpuCas01Ptr cpu = dynamic_cast<CpuCas01Ptr>(
310 static_cast<ResourcePtr>(
311 surf_cpu_resource_priv(ind_vm_workstation)));
313 /* We deregister objects from host_lib, without invoking the freeing callback
316 * Do not call xbt_lib_remove() here. It deletes all levels of the key,
317 * including MSG_HOST_LEVEL and others. We should unregister only what we know.
319 xbt_lib_unset(host_lib, getName(), SURF_CPU_LEVEL, 0);
320 xbt_lib_unset(host_lib, getName(), ROUTING_HOST_LEVEL, 0);
321 xbt_lib_unset(host_lib, getName(), SURF_WKS_LEVEL, 0);
323 /* TODO: comment out when VM stroage is implemented. */
324 // xbt_lib_unset(host_lib, name, SURF_STORAGE_LEVEL, 0);
327 /* Free the cpu_action of the VM. */
328 int ret = p_action->unref();
329 xbt_assert(ret == 1, "Bug: some resource still remains");
331 /* Free the cpu resource of the VM. If using power_trace, we will have to */
334 /* Free the network resource of the VM. */
335 // Nothing has to be done, because net_elmts is just a pointer on the physical one
337 /* Free the storage resource of the VM. */
340 /* Free the workstation resource of the VM. */
343 void WorkstationVMHL13::updateState(tmgr_trace_event_t event_type, double value, double date) {
344 THROW_IMPOSSIBLE; /* This model does not implement parallel tasks */
347 bool WorkstationVMHL13::isUsed() {
348 THROW_IMPOSSIBLE; /* This model does not implement parallel tasks */
352 e_surf_resource_state_t WorkstationVMHL13::getState()
354 return (e_surf_resource_state_t) p_currentState;
357 void WorkstationVMHL13::setState(e_surf_resource_state_t state)
359 p_currentState = (e_surf_vm_state_t) state;
362 void WorkstationVMHL13::suspend()
365 p_currentState = SURF_VM_STATE_SUSPENDED;
368 void WorkstationVMHL13::resume()
371 p_currentState = SURF_VM_STATE_RUNNING;
374 void WorkstationVMHL13::save()
376 p_currentState = SURF_VM_STATE_SAVING;
378 /* FIXME: do something here */
380 p_currentState = SURF_VM_STATE_SAVED;
383 void WorkstationVMHL13::restore()
385 p_currentState = SURF_VM_STATE_RESTORING;
387 /* FIXME: do something here */
389 p_currentState = SURF_VM_STATE_RUNNING;
393 * Update the physical host of the given VM
395 void WorkstationVMHL13::migrate(surf_resource_t ind_dst_pm)
397 /* ind_phys_workstation equals to smx_host_t */
398 WorkstationPtr ws_dst = dynamic_cast<WorkstationPtr>(
399 static_cast<ResourcePtr>(
400 surf_workstation_resource_priv(ind_dst_pm)));
401 const char *vm_name = getName();
402 const char *pm_name_src = p_subWs->getName();
403 const char *pm_name_dst = ws_dst->getName();
409 /* update net_elm with that of the destination physical host */
410 RoutingEdgePtr old_net_elm = p_netElm;
411 RoutingEdgePtr new_net_elm = static_cast<RoutingEdgePtr>(xbt_lib_get_or_null(host_lib, pm_name_dst, ROUTING_HOST_LEVEL));
412 xbt_assert(new_net_elm);
414 /* Unregister the current net_elm from host_lib. Do not call the free callback. */
415 xbt_lib_unset(host_lib, vm_name, ROUTING_HOST_LEVEL, 0);
417 /* Then, resister the new one. */
418 p_netElm = new_net_elm;
419 xbt_lib_set(host_lib, vm_name, ROUTING_HOST_LEVEL, p_netElm);
423 /* Update vcpu's action for the new pm */
426 XBT_INFO("cpu_action->remains %g", p_action->remains);
427 XBT_INFO("cost %f remains %f start %f finish %f", p_action->cost,
432 XBT_INFO("cpu_action state %d", surf_action_get_state(p_action));
435 /* create a cpu action bound to the pm model at the destination. */
436 CpuActionPtr new_cpu_action = dynamic_cast<CpuActionPtr>(
437 dynamic_cast<CpuCas01Ptr>(
438 static_cast<ResourcePtr>(
439 surf_cpu_resource_priv(ind_dst_pm)))->execute(0));
441 e_surf_action_state_t state = p_action->getState();
442 if (state != SURF_ACTION_DONE)
443 XBT_CRITICAL("FIXME: may need a proper handling, %d", state);
444 if (p_action->getRemains() > 0)
445 XBT_CRITICAL("FIXME: need copy the state(?), %f", p_action->getRemains());
447 int ret = p_action->unref();
448 xbt_assert(ret == 1, "Bug: some resource still remains");
450 /* keep the bound value of the cpu action of the VM. */
451 double old_bound = p_action->getBound();
452 if (old_bound != 0) {
453 XBT_INFO("migrate VM(%s): set bound (%lf) at %s", vm_name, old_bound, pm_name_dst);
454 new_cpu_action->setBound(old_bound);
457 p_action = new_cpu_action;
460 XBT_DEBUG("migrate VM(%s): change net_elm (%p to %p)", vm_name, old_net_elm, new_net_elm);
461 XBT_DEBUG("migrate VM(%s): change PM (%s to %s)", vm_name, pm_name_src, pm_name_dst);
464 void WorkstationVMHL13::setBound(double bound){
465 p_action->setBound(bound);
468 void WorkstationVMHL13::setAffinity(CpuPtr cpu, unsigned long mask){
469 p_action->setAffinity(cpu, mask);
473 * A surf level object will be useless in the upper layer. Returing the
474 * dict_elm of the host.
476 surf_resource_t WorkstationVMHL13::getPm()
478 return xbt_lib_get_elm_or_null(host_lib, p_subWs->getName());
481 /* Adding a task to a VM updates the VCPU task on its physical machine. */
482 ActionPtr WorkstationVMHL13::execute(double size)
484 double old_cost = p_action->getCost();
485 double new_cost = old_cost + size;
487 XBT_DEBUG("VM(%s)@PM(%s): update dummy action's cost (%f -> %f)",
488 getName(), p_subWs->getName(),
491 p_action->setCost(new_cost);
493 return p_cpu->execute(size);
496 ActionPtr WorkstationVMHL13::sleep(double duration) {
497 return p_cpu->sleep(duration);
504 //FIME:: handle action cancel