From: alebre Date: Thu, 31 Jan 2013 22:51:36 +0000 (+0100) Subject: Merge branch 'master' into hypervisor X-Git-Tag: v3_11_beta~297^2^2~112 X-Git-Url: http://bilbo.iut-bm.univ-fcomte.fr/pub/gitweb/simgrid.git/commitdiff_plain/6a87962ff2bd64e3c863ea894dd745647e380c93?hp=a0717ebd450c0d360a4ef5c5898d51e3b12cbb81 Merge branch 'master' into hypervisor --- diff --git a/buildtools/Cmake/DefinePackages.cmake b/buildtools/Cmake/DefinePackages.cmake index d5e39396f4..9b0323be9b 100644 --- a/buildtools/Cmake/DefinePackages.cmake +++ b/buildtools/Cmake/DefinePackages.cmake @@ -216,6 +216,7 @@ set(SURF_SRC src/surf/trace_mgr.c src/surf/workstation.c src/surf/workstation_ptask_L07.c + src/surf/vm_workstation.c src/xbt/xbt_sg_stubs.c ) @@ -233,6 +234,7 @@ set(SIMIX_SRC src/simix/smx_smurf.c src/simix/smx_synchro.c src/simix/smx_user.c + src/simix/smx_vm.c ) set(SIMGRID_SRC diff --git a/include/msg/datatypes.h b/include/msg/datatypes.h index 0536dbb264..e5b3ea12ec 100644 --- a/include/msg/datatypes.h +++ b/include/msg/datatypes.h @@ -46,7 +46,10 @@ typedef xbt_dictelm_t msg_host_t; typedef s_xbt_dictelm_t s_msg_host_t; typedef struct msg_host_priv { - xbt_swag_t vms; + + // TODO Warning keeping such vms attribut may lead to some complexity at the SURF Level. + // Please check with Arnaud + xbt_dynar_t vms; #ifdef MSG_USE_DEPRECATED msg_mailbox_t *mailboxes; /**< the channels */ #endif @@ -81,22 +84,42 @@ typedef struct msg_task { */ typedef struct msg_task *msg_task_t; +/* ******************************** Hypervisor ************************************* */ +typedef struct msg_hypervisor *msg_hypervisor_t; + +typedef struct msg_hypervisor { + const char *name; + s_xbt_swag_hookup_t all_hypervisor_hookup; + xbt_dynar_t vms; // vms on this hypervisor + msg_host_t host; // physical host of this hypervisor + +/* The hypervisor object does not have parameters like the number of CPU +* cores and the size of memory. These parameters come from those of the +* physical host. +**/ + int overcommit; + +} s_msg_hypervisor_t; + /* ******************************** VM ************************************* */ -typedef struct msg_vm *msg_vm_t; +typedef msg_host_t msg_vm_t; +typedef msg_host_priv_t msg_vm_priv_t; typedef enum { - msg_vm_state_suspended, msg_vm_state_running, msg_vm_state_migrating +msg_vm_state_created, +msg_vm_state_running, +msg_vm_state_sleeping, +msg_vm_state_migrating, +msg_vm_state_resuming, +msg_vm_state_suspended, +msg_vm_state_saved, +msg_vm_state_restoring, } e_msg_vm_state_t; -typedef struct msg_vm { - const char *name; - s_xbt_swag_hookup_t all_vms_hookup; - s_xbt_swag_hookup_t host_vms_hookup; - xbt_dynar_t processes; - e_msg_vm_state_t state; - msg_host_t location; - int coreAmount; -} s_msg_vm_t; +static inline msg_vm_priv_t MSG_vm_priv(msg_vm_t vm){ + return xbt_lib_get_level(vm, MSG_HOST_LEVEL); +} + /* ******************************** File ************************************ */ typedef struct simdata_file *simdata_file_t; diff --git a/include/msg/msg.h b/include/msg/msg.h index 330ed564c4..daa38184aa 100644 --- a/include/msg/msg.h +++ b/include/msg/msg.h @@ -341,7 +341,12 @@ XBT_PUBLIC(int) MSG_get_channel_number(void); * */ /* This function should not be called directly, but rather from MSG_vm_start_from_template that does not exist yet*/ -XBT_PUBLIC(msg_vm_t) MSG_vm_start(msg_host_t location, const char *name, int coreAmount); + +// TODO add VDI later +XBT_PUBLIC(msg_vm_t) MSG_vm_create(msg_host_t location, const char *name, + int core_nb, int mem_cap, int net_cap); + +XBT_PUBLIC(void) MSG_vm_start(msg_vm_t); XBT_PUBLIC(int) MSG_vm_is_suspended(msg_vm_t); XBT_PUBLIC(int) MSG_vm_is_running(msg_vm_t); diff --git a/include/simgrid/simix.h b/include/simgrid/simix.h index a856c0bc37..7e678c6b24 100644 --- a/include/simgrid/simix.h +++ b/include/simgrid/simix.h @@ -328,6 +328,13 @@ XBT_PUBLIC(e_smx_state_t) simcall_host_execution_get_state(smx_action_t executio XBT_PUBLIC(void) simcall_host_execution_set_priority(smx_action_t execution, double priority); XBT_PUBLIC(e_smx_state_t) simcall_host_execution_wait(smx_action_t execution); +/******************************* VM simcalls ********************************/ +// Create the vm_workstation at the SURF level +XBT_PUBLIC(void*) simcall_vm_ws_create(const char *name, smx_host_t host); +XBT_PUBLIC(void*) simcall_get_vm_state(smx_host_t vm); +XBT_PUBLIC(void) simcall_vm_start(smx_host_t vm); +XBT_PUBLIC(void) simcall_vm_suspend(smx_host_t vm); +XBT_PUBLIC(void) simcall_vm_destroy(smx_host_t vm); /**************************** Process simcalls ********************************/ /* Constructor and Destructor */ diff --git a/include/xbt/ex.h b/include/xbt/ex.h index 82573e0ad6..b10156214f 100644 --- a/include/xbt/ex.h +++ b/include/xbt/ex.h @@ -262,7 +262,8 @@ typedef enum { thread_error, /**< error while [un]locking */ host_error, /**< host failed */ tracing_error, /**< error during the simulation tracing */ - io_error /**< disk or file error */ + io_error, /**< disk or file error */ + vm_error /**< vm error */ } xbt_errcat_t; XBT_PUBLIC(const char *) xbt_ex_catname(xbt_errcat_t cat); diff --git a/include/xbt/lib.h b/include/xbt/lib.h index cdc9fc7942..3b0ef3ce62 100644 --- a/include/xbt/lib.h +++ b/include/xbt/lib.h @@ -26,10 +26,12 @@ XBT_PUBLIC(void) xbt_lib_free(xbt_lib_t * lib); XBT_PUBLIC(int) xbt_lib_add_level(xbt_lib_t lib, void_f_pvoid_t free_f); XBT_PUBLIC(void) xbt_lib_set(xbt_lib_t lib, const char *name, int level, void *obj); +XBT_PUBLIC(void) xbt_lib_unset(xbt_lib_t lib, const char *key, int level); XBT_PUBLIC(void *) xbt_lib_get_or_null(xbt_lib_t lib, const char *name, int level); XBT_PUBLIC(xbt_dictelm_t) xbt_lib_get_elm_or_null(xbt_lib_t lib, const char *key); XBT_PUBLIC(void *) xbt_lib_get_level(xbt_dictelm_t elm, int level); +XBT_PUBLIC(void) xbt_lib_remove(xbt_lib_t lib, const char *key); #define xbt_lib_length(lib) xbt_dict_length((lib)->dict) diff --git a/src/include/surf/surf.h b/src/include/surf/surf.h index 5a612accf1..441070fc92 100644 --- a/src/include/surf/surf.h +++ b/src/include/surf/surf.h @@ -276,8 +276,14 @@ typedef struct surf_workstation_model_extension_public { } s_surf_model_extension_workstation_t; - - +typedef struct surf_vm_workstation_model_extension_public { + s_surf_model_extension_workstation_t basic; + void* (*create) (const char *name, void *ind_phys_workstation); // First operation of the VM model + // start does not appear here as it corresponds to turn the state from created to running (see smx_vm.c) + int (*get_state) (void *ind_phys_workstation); + void (*set_state) (void *ind_phys_workstation, int state); + void (*destroy) (void *ind_phys_workstation); // will be vm_ws_destroy(), which destroies the vm-specific data +} s_surf_model_extension_vm_workstation_t; /** \ingroup SURF_models * \brief Model datatype @@ -323,6 +329,8 @@ typedef struct surf_model { s_surf_model_extension_network_t network; s_surf_model_extension_storage_t storage; s_surf_model_extension_workstation_t workstation; + // TODO Implement the corresponding model + s_surf_model_extension_vm_workstation_t vm_workstation; /*******************************************/ /* TUTORIAL: New model */ s_surf_model_extension_new_model_t new_model; @@ -600,6 +608,16 @@ XBT_PUBLIC_DATA(s_surf_model_description_t) surf_storage_model_description[]; */ XBT_PUBLIC_DATA(surf_model_t) surf_workstation_model; +/** \ingroup SURF_models + * \brief The vm_workstation model + * + * Note that when you create an API on top of SURF, + * the vm_workstation model should be the only one you use + * because depending on the platform model, the network model and the CPU model + * may not exist. + */ +XBT_PUBLIC_DATA(surf_model_t) surf_vm_workstation_model; + /** \ingroup SURF_models * \brief Initializes the platform with a compound workstation model * diff --git a/src/msg/instr_msg_vm.c b/src/msg/instr_msg_vm.c index 7b7e3e4d6f..770f4cf9c9 100644 --- a/src/msg/instr_msg_vm.c +++ b/src/msg/instr_msg_vm.c @@ -13,7 +13,7 @@ XBT_LOG_NEW_DEFAULT_SUBCATEGORY (instr_msg_vm, instr, "MSG VM"); char *instr_vm_id (msg_vm_t vm, char *str, int len) { - return instr_vm_id_2 (vm->name, str, len); + return instr_vm_id_2 (MSG_get_vm_name(vm), str, len); } char *instr_vm_id_2 (const char *vm_name, char *str, int len) @@ -66,6 +66,20 @@ void TRACE_msg_vm_create (const char *vm_name, msg_host_t host) } } +void TRACE_msg_vm_start (msg_vm_t vm) +{ + if (TRACE_msg_vm_is_enabled()){ + int len = INSTR_DEFAULT_STR_SIZE; + char str[INSTR_DEFAULT_STR_SIZE]; + + container_t vm_container = PJ_container_get (instr_vm_id(vm, str, len)); + type_t type = PJ_type_get ("MSG_VM_STATE", vm_container->type); + val_t value = PJ_value_get ("start", type); + new_pajePushState (MSG_get_clock(), vm_container, type, value); + } + +} + void TRACE_msg_vm_kill(msg_vm_t vm) { if (TRACE_msg_vm_is_enabled()) { int len = INSTR_DEFAULT_STR_SIZE; diff --git a/src/msg/msg_global.c b/src/msg/msg_global.c index 3a3ad8ce9a..de9710749e 100644 --- a/src/msg/msg_global.c +++ b/src/msg/msg_global.c @@ -37,7 +37,7 @@ void MSG_init_nocheck(int *argc, char **argv) { xbt_getpid = MSG_process_self_PID; if (!msg_global) { - s_msg_vm_t vm; // to compute the offset + // s_msg_vm_t vm; // to compute the offset SIMIX_global_init(argc, argv); @@ -49,7 +49,7 @@ void MSG_init_nocheck(int *argc, char **argv) { msg_global->sent_msg = 0; msg_global->task_copy_callback = NULL; msg_global->process_data_cleanup = NULL; - msg_global->vms = xbt_swag_new(xbt_swag_offset(vm,all_vms_hookup)); +// msg_global->vms = xbt_swag_new(xbt_swag_offset(vm,all_vms_hookup)); /* initialization of the action module */ _MSG_action_init(); diff --git a/src/msg/msg_host.c b/src/msg/msg_host.c index a767553db3..8098e236b8 100644 --- a/src/msg/msg_host.c +++ b/src/msg/msg_host.c @@ -30,9 +30,8 @@ msg_host_t __MSG_host_create(smx_host_t workstation) { const char *name = SIMIX_host_get_name(workstation); msg_host_priv_t host = xbt_new0(s_msg_host_priv_t, 1); - s_msg_vm_t vm; // simply to compute the offset - host->vms = xbt_swag_new(xbt_swag_offset(vm,host_vms_hookup)); + host->vms = xbt_dynar_new(sizeof(msg_vm_t),NULL); #ifdef MSG_USE_DEPRECATED int i; diff --git a/src/msg/msg_private.h b/src/msg/msg_private.h index cbc10c8df3..cfc212189e 100644 --- a/src/msg/msg_private.h +++ b/src/msg/msg_private.h @@ -68,8 +68,6 @@ typedef struct simdata_process { int argc; /* arguments number if any */ msg_error_t last_errno; /* the last value returned by a MSG_function */ - msg_vm_t vm; /* virtual machine the process is in */ - void* data; /* user data */ } s_simdata_process_t, *simdata_process_t; diff --git a/src/msg/msg_process.c b/src/msg/msg_process.c index 097cfaa4a5..471e2a614d 100644 --- a/src/msg/msg_process.c +++ b/src/msg/msg_process.c @@ -50,12 +50,6 @@ void MSG_process_cleanup_from_SIMIX(smx_process_t smx_proc) msg_global->process_data_cleanup(msg_proc->data); } - // remove the process from its virtual machine - if (msg_proc->vm) { - int pos = xbt_dynar_search(msg_proc->vm->processes,&smx_proc); - xbt_dynar_remove_at(msg_proc->vm->processes,pos, NULL); - } - // free the MSG process xbt_free(msg_proc); } diff --git a/src/msg/msg_vm.c b/src/msg/msg_vm.c index c025372f06..71a614db5d 100644 --- a/src/msg/msg_vm.c +++ b/src/msg/msg_vm.c @@ -3,6 +3,12 @@ /* This program is free software; you can redistribute it and/or modify it * under the terms of the license (GNU LGPL) which comes with this package. */ + +// TODO +// 1./ check how and where a new VM is added to the list of the hosts +// 2./ MSG_TRACE can be revisited in order to use the host + + #include "msg_private.h" #include "xbt/sysdep.h" #include "xbt/log.h" @@ -10,117 +16,212 @@ XBT_LOG_NEW_DEFAULT_SUBCATEGORY(msg_vm, msg, "Cloud-oriented parts of the MSG API"); -/** @brief Create a new (empty) VMs. - * @ingroup msg_VMs + +/* **** ******** GENERAL ********* **** */ + +/** \ingroup m_vm_management + * \brief Returns the value of a given vm property * - * @bug it is expected that in the future, the coreAmount parameter will be used - * to add extra constraints on the execution, but the argument is ignored for now. + * \param vm a vm + * \param name a property name + * \return value of a property (or NULL if property not set) */ -msg_vm_t MSG_vm_start(msg_host_t location, const char *name, int coreAmount) { - msg_vm_t res = xbt_new0(s_msg_vm_t,1); - res->all_vms_hookup.prev = NULL; - res->host_vms_hookup.prev = NULL; - res->state = msg_vm_state_running; - res->location = location; - res->coreAmount = coreAmount; - res->name = xbt_strdup(name); - res->processes = xbt_dynar_new(sizeof(msg_process_t),NULL); +const char *MSG_vm_get_property_value(msg_vm_t vm, const char *name) +{ + return MSG_host_get_property_value(vm, name); +} - xbt_swag_insert(res,msg_global->vms); - xbt_swag_insert(res, MSG_host_priv(location)->vms); +/** \ingroup m_vm_management + * \brief Returns a xbt_dict_t consisting of the list of properties assigned to this host + * + * \param vm a vm + * \return a dict containing the properties + */ +xbt_dict_t MSG_vm_get_properties(msg_vm_t vm) +{ + xbt_assert((vm != NULL), "Invalid parameters (vm is NULL)"); - #ifdef HAVE_TRACING - TRACE_msg_vm_create(name, location); - #endif + return (simcall_host_get_properties(vm)); +} +/** \ingroup m_host_management + * \brief Change the value of a given host property + * + * \param host a host + * \param name a property name + * \param value what to change the property to + * \param free_ctn the freeing function to use to kill the value on need + */ +void MSG_vm_set_property_value(msg_vm_t vm, const char *name, void *value,void_f_pvoid_t free_ctn) { - return res; + xbt_dict_set(MSG_host_get_properties(vm), name, value,free_ctn); } -/** @brief Returns a newly constructed dynar containing all existing VMs in the system. - * @ingroup msg_VMs + +/** \ingroup msg_vm_management + * \brief Finds a msg_vm_t using its name. * - * Don't forget to free the dynar after use. + * This is a name directory service + * \param name the name of a vm. + * \return the corresponding vm + * + * Please note that a VM is a specific host. Hence, you should give a different name + * for each VM/PM. */ -xbt_dynar_t MSG_vms_as_dynar(void) { - xbt_dynar_t res = xbt_dynar_new(sizeof(msg_vm_t),NULL); - msg_vm_t vm; - xbt_swag_foreach(vm,msg_global->vms) { - xbt_dynar_push(res,&vm); - } - return res; + +msg_vm_t MSG_vm_get_by_name(const char *name){ + return MSG_get_host_by_name(name); } -/** @brief Returns whether the given VM is currently suspended - * @ingroup msg_VMs +/** \ingroup m_vm_management + * + * \brief Return the name of the #msg_host_t. + * + * This functions checks whether \a host is a valid pointer or not and return + its name. */ -int MSG_vm_is_suspended(msg_vm_t vm) { - return vm->state == msg_vm_state_suspended; +const char *MSG_vm_get_name(msg_vm_t vm) { + return MSG_host_get_name(vm); } -/** @brief Returns whether the given VM is currently running - * @ingroup msg_VMs + +/* **** ******** MSG vm actions ********* **** */ + +/** @brief Create a new VM (the VM is just attached to the location but it is not started yet). + * @ingroup msg_VMs* + * + * Please note that a VM is a specific host. Hence, you should give a different name + * for each VM/PM. */ -int MSG_vm_is_running(msg_vm_t vm) { - return vm->state == msg_vm_state_running; +msg_vm_t MSG_vm_create(msg_host_t ind_host, const char *name, + int core_nb, int mem_cap, int net_cap){ + + // Note new and vm_workstation refer to the same area (due to the lib/dict appraoch) + msg_vm_t new = NULL; + void *ind_vm_workstation = NULL; + // Ask simix to create the surf vm resource + ind_vm_workstation = simcall_vm_ws_create(name,ind_host); + new = (msg_vm_t) __MSG_host_create(ind_vm_workstation); + + MSG_vm_set_property_value(new, "CORE_NB", bprintf("%d", core_nb), free); + MSG_vm_set_property_value(new, "MEM_CAP", bprintf("%d", core_nb), free); + MSG_vm_set_property_value(new, "NET_CAP", bprintf("%d", core_nb), free); + + XBT_DEBUG("A new VM has been created"); + // TODO check whether the vm (i.e the virtual host) has been correctly added into the list of all hosts. + + #ifdef HAVE_TRACING + TRACE_msg_vm_create(name, ind_host); + #endif + + return new; } -/** @brief Add the given process into the VM. + +/** @brief Start a vm (ie. boot) * @ingroup msg_VMs * - * Afterward, when the VM is migrated or suspended or whatever, the process will have the corresponding handling, too. + * If the VM cannot be started, an exception is generated. * */ -void MSG_vm_bind(msg_vm_t vm, msg_process_t process) { - /* check if the process is already in a VM */ - simdata_process_t simdata = simcall_process_get_data(process); - if (simdata->vm) { - msg_vm_t old_vm = simdata->vm; - int pos = xbt_dynar_search(old_vm->processes,&process); - xbt_dynar_remove_at(old_vm->processes,pos, NULL); - } - /* check if the host is in the right host */ - if (simdata->m_host != vm->location) { - MSG_process_migrate(process,vm->location); - } - simdata->vm = vm; +void MSG_vm_start(msg_vm_t vm) { - XBT_DEBUG("binding Process %s to %p",MSG_process_get_name(process),vm); + //Please note that vm start can raise an exception if the VM cannot be started. + simcall_vm_start(vm); - xbt_dynar_push_as(vm->processes,msg_process_t,process); + #ifdef HAVE_TRACING + TRACE_msg_vm_start(vm); + #endif +} + +/* **** Check state of a VM **** */ +int __MSG_vm_is_state(msg_vm_t vm, e_msg_vm_state_t state) { + return simcall_get_vm_state(vm) == state ; } -/** @brief Removes the given process from the given VM, and kill it + +/** @brief Returns whether the given VM is currently suspended * @ingroup msg_VMs - * - * Will raise a not_found exception if the process were not binded to that VM */ -void MSG_vm_unbind(msg_vm_t vm, msg_process_t process) { - int pos = xbt_dynar_search(vm->processes,process); - xbt_dynar_remove_at(vm->processes,pos, NULL); - MSG_process_kill(process); +int MSG_vm_is_suspended(msg_vm_t vm) { + return __MSG_vm_is_state(vm, msg_vm_state_suspended); } - -/** @brief Immediately change the host on which all processes are running. +/** @brief Returns whether the given VM is currently running * @ingroup msg_VMs - * - * No migration cost occurs. If you want to simulate this too, you want to use a - * MSG_task_send() before or after, depending on whether you want to do cold or hot - * migration. */ -void MSG_vm_migrate(msg_vm_t vm, msg_host_t destination) { - unsigned int cpt; - msg_process_t process; - xbt_dynar_foreach(vm->processes,cpt,process) { - MSG_process_migrate(process,destination); - } - xbt_swag_remove(vm, MSG_host_priv(vm->location)->vms); - xbt_swag_insert_at_tail(vm, MSG_host_priv(destination)->vms); - - #ifdef HAVE_TRACING - TRACE_msg_vm_change_host(vm,vm->location,destination); - #endif +int MSG_vm_is_running(msg_vm_t vm) { + return __MSG_vm_is_state(vm, msg_vm_state_running); +} + +// TODO Implement the functions for the different state + +void MSG_vm_shutdown(msg_vm_t vm) +{ + /* msg_vm_t equals to msg_host_t */ + simcall_vm_shutdown(vm); - vm->location = destination; + // #ifdef HAVE_TRACING + // TRACE_msg_vm_(vm); + // #endif } + +///** @brief Add the given process into the VM. +// * @ingroup msg_VMs +// * +// * Afterward, when the VM is migrated or suspended or whatever, the process will have the corresponding handling, too. +// * +// */ +//void MSG_vm_bind(msg_vm_t vm, msg_process_t process) { +// /* check if the process is already in a VM */ +// simdata_process_t simdata = simcall_process_get_data(process); +// if (simdata->vm) { +// msg_vm_t old_vm = simdata->vm; +// int pos = xbt_dynar_search(old_vm->processes,&process); +// xbt_dynar_remove_at(old_vm->processes,pos, NULL); +// } +// /* check if the host is in the right host */ +// if (simdata->m_host != vm->location) { +// MSG_process_migrate(process,vm->location); +// } +// simdata->vm = vm; +// +// XBT_DEBUG("binding Process %s to %p",MSG_process_get_name(process),vm); +// +// xbt_dynar_push_as(vm->processes,msg_process_t,process); +//} +///** @brief Removes the given process from the given VM, and kill it +// * @ingroup msg_VMs +// * +// * Will raise a not_found exception if the process were not binded to that VM +// */ +//void MSG_vm_unbind(msg_vm_t vm, msg_process_t process) { +// int pos = xbt_dynar_search(vm->processes,process); +// xbt_dynar_remove_at(vm->processes,pos, NULL); +// MSG_process_kill(process); +//} +// +///** @brief Immediately change the host on which all processes are running. +// * @ingroup msg_VMs +// * +// * No migration cost occurs. If you want to simulate this too, you want to use a +// * MSG_task_send() before or after, depending on whether you want to do cold or hot +// * migration. +// */ +//void MSG_vm_migrate(msg_vm_t vm, msg_host_t destination) { +// unsigned int cpt; +// msg_process_t process; +// xbt_dynar_foreach(vm->processes,cpt,process) { +// MSG_process_migrate(process,destination); +// } +// xbt_swag_remove(vm, MSG_host_priv(vm->location)->vms); +// xbt_swag_insert_at_tail(vm, MSG_host_priv(destination)->vms); +// +// #ifdef HAVE_TRACING +// TRACE_msg_vm_change_host(vm,vm->location,destination); +// #endif +// +// vm->location = destination; +//} +// + /** @brief Immediately suspend the execution of all processes within the given VM. * @ingroup msg_VMs * @@ -128,86 +229,87 @@ void MSG_vm_migrate(msg_vm_t vm, msg_host_t destination) { * use a \ref MSG_file_write() before or after, depending on the exact semantic * of VM suspend to you. */ -void MSG_vm_suspend(msg_vm_t vm) { - unsigned int cpt; - msg_process_t process; - xbt_dynar_foreach(vm->processes,cpt,process) { - XBT_DEBUG("suspend process %s of host %s",MSG_process_get_name(process),MSG_host_get_name(MSG_process_get_host(process))); - MSG_process_suspend(process); - } +void MSG_vm_suspend(msg_vm_t vm) +{ + simcall_vm_suspend(vm); #ifdef HAVE_TRACING TRACE_msg_vm_suspend(vm); #endif -} - -/** @brief Immediately resumes the execution of all processes within the given VM. - * @ingroup msg_VMs - * - * No resume cost occurs. If you want to simulate this too, you want to - * use a \ref MSG_file_read() before or after, depending on the exact semantic - * of VM resume to you. - */ -void MSG_vm_resume(msg_vm_t vm) { +#if 0 unsigned int cpt; msg_process_t process; xbt_dynar_foreach(vm->processes,cpt,process) { - XBT_DEBUG("resume process %s of host %s",MSG_process_get_name(process),MSG_host_get_name(MSG_process_get_host(process))); - MSG_process_resume(process); + XBT_DEBUG("suspend process %s of host %s",MSG_process_get_name(process),MSG_host_get_name(MSG_process_get_host(process))); + MSG_process_suspend(process); } - - #ifdef HAVE_TRACING - TRACE_msg_vm_resume(vm); - #endif +#endif } -/** @brief Immediately kills all processes within the given VM. Any memory that they allocated will be leaked. +// +// +///** @brief Immediately resumes the execution of all processes within the given VM. +// * @ingroup msg_VMs +// * +// * No resume cost occurs. If you want to simulate this too, you want to +// * use a \ref MSG_file_read() before or after, depending on the exact semantic +// * of VM resume to you. +// */ +//void MSG_vm_resume(msg_vm_t vm) { +// unsigned int cpt; +// msg_process_t process; +// xbt_dynar_foreach(vm->processes,cpt,process) { +// XBT_DEBUG("resume process %s of host %s",MSG_process_get_name(process),MSG_host_get_name(MSG_process_get_host(process))); +// MSG_process_resume(process); +// } +// +// #ifdef HAVE_TRACING +// TRACE_msg_vm_resume(vm); +// #endif +//} +// +// +///** +// * \ingroup msg_VMs +// * \brief Reboot the VM, restarting all the processes in it. +// */ +//void MSG_vm_reboot(msg_vm_t vm) +//{ +// xbt_dynar_t new_processes = xbt_dynar_new(sizeof(msg_process_t),NULL); +// +// msg_process_t process; +// unsigned int cpt; +// +// xbt_dynar_foreach(vm->processes,cpt,process) { +// msg_process_t new_process = MSG_process_restart(process); +// xbt_dynar_push_as(new_processes,msg_process_t,new_process); +// +// } +// +// xbt_dynar_foreach(new_processes, cpt, process) { +// MSG_vm_bind(vm,process); +// } +// +// xbt_dynar_free(&new_processes); +//} +// + +/** @brief Destroy a VM. Destroy the VM object from the simulation. * @ingroup msg_VMs - * - * No extra delay occurs. If you want to simulate this too, you want to - * use a #MSG_process_sleep() or something. I'm not quite sure. */ -void MSG_vm_shutdown(msg_vm_t vm) +void MSG_vm_destroy(msg_vm_t vm) { - msg_process_t process; - XBT_DEBUG("%lu processes in the VM", xbt_dynar_length(vm->processes)); - while (xbt_dynar_length(vm->processes) > 0) { - process = xbt_dynar_get_as(vm->processes,0,msg_process_t); - MSG_process_kill(process); - } + /* First, terminate all processes on the VM */ + simcall_vm_shutdown(vm); + + /* Then, destroy the VM object */ + simcall_vm_destroy(vm); #ifdef HAVE_TRACING - TRACE_msg_vm_kill(vm); + TRACE_msg_vm_end(vm); #endif -} -/** - * \ingroup msg_VMs - * \brief Reboot the VM, restarting all the processes in it. - */ -void MSG_vm_reboot(msg_vm_t vm) -{ - xbt_dynar_t new_processes = xbt_dynar_new(sizeof(msg_process_t),NULL); - - msg_process_t process; - unsigned int cpt; - - xbt_dynar_foreach(vm->processes,cpt,process) { - msg_process_t new_process = MSG_process_restart(process); - xbt_dynar_push_as(new_processes,msg_process_t,new_process); - - } - - xbt_dynar_foreach(new_processes, cpt, process) { - MSG_vm_bind(vm,process); - } - - xbt_dynar_free(&new_processes); -} -/** @brief Destroy a msg_vm_t. - * @ingroup msg_VMs - */ -void MSG_vm_destroy(msg_vm_t vm) { +#if 0 unsigned int cpt; msg_process_t process; xbt_dynar_foreach(vm->processes,cpt,process) { @@ -216,11 +318,7 @@ void MSG_vm_destroy(msg_vm_t vm) { simdata->vm = NULL; } - #ifdef HAVE_TRACING - TRACE_msg_vm_end(vm); - #endif - - xbt_dynar_free(&vm->processes); xbt_free(vm); +#endif } diff --git a/src/simgrid/sg_config.c b/src/simgrid/sg_config.c index 3d853d4482..1b8a6a6d6e 100644 --- a/src/simgrid/sg_config.c +++ b/src/simgrid/sg_config.c @@ -785,6 +785,9 @@ void surf_config_models_setup() XBT_DEBUG("Call workstation_model_init"); surf_workstation_model_description[workstation_id].model_init_preparse(); + XBT_DEBUG("Call vm_workstation_model_init"); + surf_vm_workstation_model_init(); + XBT_DEBUG("Call storage_model_init"); storage_id = find_model_description(surf_storage_model_description, storage_model_name); surf_storage_model_description[storage_id].model_init_preparse(); diff --git a/src/simix/smx_smurf_private.h b/src/simix/smx_smurf_private.h index aaa090fb28..fcd229d69a 100644 --- a/src/simix/smx_smurf_private.h +++ b/src/simix/smx_smurf_private.h @@ -274,6 +274,13 @@ ACTION(SIMCALL_HOST_EXECUTION_GET_REMAINS, host_execution_get_remains, WITH_ANSW ACTION(SIMCALL_HOST_EXECUTION_GET_STATE, host_execution_get_state, WITH_ANSWER, TINT(result), TSPEC(execution, smx_action_t)) sep \ ACTION(SIMCALL_HOST_EXECUTION_SET_PRIORITY, host_execution_set_priority, WITH_ANSWER, TVOID(result), TSPEC(execution, smx_action_t), TDOUBLE(priority)) sep \ ACTION(SIMCALL_HOST_EXECUTION_WAIT, host_execution_wait, WITHOUT_ANSWER, TINT(result), TSPEC(execution, smx_action_t)) sep \ +ACTION(SIMCALL_VM_WS_CREATE, vm_ws_create, WITH_ANSWER, TPTR(result), TSTRING(name), TSPEC(phys_host, smx_host_t)) sep \ +ACTION(SIMCALL_VM_START, vm_start, WITHOUT_ANSWER, TVOID(result), TSPEC(ind_phys_host, smx_host_t)) sep \ +ACTION(SIMCALL_VM_SET_STATE, vm_set_state, WITHOUT_ANSWER, TVOID(result), TSPEC(ind_vm, smx_host_t), TINT(state)) sep \ +ACTION(SIMCALL_VM_GET_STATE, vm_get_state, WITH_ANSWER, TINT(result), TSPEC(ind_vm, smx_host_t)) sep \ +ACTION(SIMCALL_VM_DESTROY, vm_destroy, WITHOUT_ANSWER, TVOID(result), TSPEC(ind_vm, smx_host_t)) sep \ +ACTION(SIMCALL_VM_SUSPEND, vm_suspend, WITHOUT_ANSWER, TVOID(result), TSPEC(vm, smx_host_t)) sep \ +ACTION(SIMCALL_VM_SHUTDOWN, vm_shutdown, WITHOUT_ANSWER, TVOID(result), TSPEC(vm, smx_host_t)) sep \ ACTION(SIMCALL_PROCESS_CREATE, process_create, WITH_ANSWER, TVOID(result), TSPEC(process, smx_process_t*), TSTRING(name), TSPEC(code, xbt_main_func_t), TPTR(data), TSTRING(hostname), TDOUBLE(kill_time), TINT(argc), TSPEC(argv, char**), TSPEC(properties, xbt_dict_t), TINT(auto_restart)) sep \ ACTION(SIMCALL_PROCESS_KILL, process_kill, WITH_ANSWER, TVOID(result), TSPEC(process, smx_process_t)) sep \ ACTION(SIMCALL_PROCESS_KILLALL, process_killall, WITH_ANSWER, TVOID(result), TINT(reset_pid)) sep \ diff --git a/src/simix/smx_user.c b/src/simix/smx_user.c index b9099f5877..6743b04973 100644 --- a/src/simix/smx_user.c +++ b/src/simix/smx_user.c @@ -274,6 +274,44 @@ e_smx_state_t simcall_host_execution_wait(smx_action_t execution) return simcall_BODY_host_execution_wait(execution); } + +/** + * \ingroup simix_vm_management + * \brief Returns a dict of the properties assigned to a host. + * + * \param host A host + * \return The properties of this host + */ +void* simcall_vm_ws_create(const char *name, smx_host_t phys_host){ + return simcall_BODY_vm_ws_create(name, phys_host); +} + +void simcall_vm_start(smx_host_t vm) { +{ + simcall_BODY_set_vm_state(vm, msg_vm_state_running); +} + +void simcall_vm_suspend(smx_host_t vm) +{ + /* will jump to SIMIX_pre_vm_suspend */ + simcall_BODY_vm_suspend(vm); +} + +void simcall_vm_shutdown(smx_host_t vm) +{ + /* will jump to SIMIX_pre_vm_shutdown */ + simcall_BODY_vm_shutdown(vm); +} + +void simcall_vm_destroy(smx_host_t vm) +{ + /* + * simcall_BODY_ is defined in src/simix/smx_smurf_private.h. + * This function will jump to SIMIX_pre_vm_destroy. + **/ + simcall_BODY_vm_destroy(vm); +} + /** * \ingroup simix_process_management * \brief Creates and runs a new SIMIX process. diff --git a/src/simix/smx_vm.c b/src/simix/smx_vm.c new file mode 100644 index 0000000000..e00aabc5e9 --- /dev/null +++ b/src/simix/smx_vm.c @@ -0,0 +1,163 @@ +/* Copyright (c) 2007-2012. The SimGrid Team. + * All rights reserved. */ + +/* This program is free software; you can redistribute it and/or modify it + * under the terms of the license (GNU LGPL) which comes with this package. */ + +#include "smx_private.h" +#include "xbt/sysdep.h" +#include "xbt/log.h" +#include "xbt/dict.h" +#include "mc/mc.h" + +//If you need to log some stuffs, just uncomment these two lines and uses XBT_DEBUG for instance +//XBT_LOG_NEW_DEFAULT_SUBCATEGORY(simix_vm, simix, +// "Logging specific to SIMIX (vms)"); + +/* **** create a VM **** */ + +/** + * \brief Internal function to create a SIMIX host. + * \param name name of the host to create + * \param data some user data (may be NULL) + */ +smx_host_t SIMIX_vm_create(const char *name, smx_host_t ind_phys_host) +{ + + smx_host_priv_t smx_host = xbt_new0(s_smx_host_priv_t, 1); + s_smx_process_t proc; + + // TODO check why we do not have any VM here and why we have the host_proc_hookup ? + + /* Host structure */ + smx_host->data = NULL; + smx_host->process_list = + xbt_swag_new(xbt_swag_offset(proc, host_proc_hookup)); + + /* Update global variables */ + xbt_lib_set(host_lib,name,SIMIX_HOST_LEVEL,smx_host); + + /* Create surf associated resource */ + // TODO change phys_host into the right workstation surf model + surf_vm_workstation_model->extension.vm_workstation.create(name, ind_phys_host); + + return xbt_lib_get_elm_or_null(host_lib, name); +} + + +smx_host_t SIMIX_pre_vm_create(smx_simcall_t simcall, const char *name, smx_host_t ind_phys_host){ + return SIMIX_vm_create(name, ind_phys_host); +} + + +/* **** start a VM **** */ +int __can_be_started(smx_host_t vm){ + // TODO add checking code related to overcommitment or not. + return 1; +} +void SIMIX_vm_start(smx_host_t ind_vm){ + + //TODO only start the VM if you can + if (can_be_started(ind_vm)) + SIMIX_set_vm_state(ind_vm, msg_vm_state_running); + else + THROWF(vm_error, 0, "The VM %s cannot be started", SIMIX_host_get_name(ind_vm)); +} + +void SIMIX_pre_vm_start(smx_simcall_t simcall, smx_host_t ind_vm){ + SIMIX_vm_start(vm); +} + +/* ***** set/get state of a VM ***** */ +void SIMIX_set_vm_state(smx_host_t ind_vm, int state){ + surf_vm_workstation_model->extension.vm_workstation.set_state(ind_vm, state); +} +void SIMIX_prev_set_vm_state(smx_host_t ind_vm, int state){ + SIMIX_set_vm_state(ind_vm, state); +} + +int SIMIX_get_vm_state(smx_host_t ind_vm){ + return surf_vm_workstation_model->extension.vm_workstation.get_state(ind_vm); +} +int SIMIX_pre_vm_state(smx_host_t ind_vm){ + return SIMIX_get_vm_state(ind_vm); +} + +/** + * \brief Function to suspend a SIMIX VM host. This function powers off the + * VM. All the processes on this VM will be killed. But, the state of the VM is + * perserved. We can later start it again. + * + * \param host the vm host to suspend (a smx_host_t) + */ +void SIMIX_vm_suspend(smx_host_t host) +{ + /* TODO: check state */ + + XBT_DEBUG("%lu processes in the VM", xbt_swag_size(SIMIX_host_priv(host)->process_list)); + + smx_process_t smx_process, smx_process_safe; + xbt_swag_foreach_safe(smx_process, smx_process_safe, SIMIX_host_priv(host)->process_list) { + XBT_DEBUG("suspend %s", SIMIX_host_get_name(host)); + simcall_process_suspend(smx_process); + } + + /* TODO: Using the variable of the MSG layer is not clean. */ + SIMIX_set_vm_state(host, msg_vm_state_suspended); +} + +void SIMIX_pre_vm_suspend(smx_simcall_t simcall, smx_host_t vm){ + SIMIX_vm_suspend(vm); +} + +/** + * \brief Function to shutdown a SIMIX VM host. This function powers off the + * VM. All the processes on this VM will be killed. But, the state of the VM is + * perserved. We can later start it again. + * + * \param host the vm host to shutdown (a smx_host_t) + */ +void SIMIX_vm_shutdown(smx_host_t host) +{ + /* TODO: check state */ + + XBT_DEBUG("%lu processes in the VM", xbt_swag_size(SIMIX_host_priv(host)->process_list)); + + smx_process_t smx_process, smx_process_safe; + xbt_swag_foreach_safe(smx_process, smx_process_safe, SIMIX_host_priv(host)->process_list) { + XBT_DEBUG("kill %s", SIMIX_host_get_name(host)); + simcall_process_kill(smx_process); + } + + /* TODO: Using the variable of the MSG layer is not clean. */ + SIMIX_set_vm_state(host, msg_vm_state_sleeping); +} + +void SIMIX_pre_vm_shutdown(smx_simcall_t simcall, smx_host_t vm){ + SIMIX_vm_shutdown(vm); +} + +/** + * \brief Function to destroy a SIMIX VM host. + * + * \param host the vm host to destroy (a smx_host_t) + */ +void SIMIX_vm_destroy(smx_host_t ind_vm) +{ + /* this code basically performs a similar thing like SIMIX_host_destroy() */ + + xbt_assert((host != NULL), "Invalid parameters"); + char *hostname = SIMIX_host_get_name(ind_vm); + + smx_host_priv_t host_priv = SIMIX_host_priv(host); + + /* this will call the registered callback function, i.e., SIMIX_host_destroy(). */ + xbt_lib_unset(host_lib, hostname, SIMIX_HOST_LEVEL); + + /* jump to vm_ws_destroy(). The surf level resource will be freed. */ + surf_vm_workstation_model->extension.vm_workstation.destroy(ind_vm); +} + +void SIMIX_pre_vm_destroy(smx_simcall_t simcall, smx_host_t vm){ + SIMIX_vm_destroy(vm); +} diff --git a/src/surf/vm_workstation.c b/src/surf/vm_workstation.c new file mode 100644 index 0000000000..94933ebd1e --- /dev/null +++ b/src/surf/vm_workstation.c @@ -0,0 +1,81 @@ +/* Copyright (c) 2004, 2005, 2006, 2007, 2008, 2009, 2010. The SimGrid Team. + * All rights reserved. */ + +/* This program is free software; you can redistribute it and/or modify it + * under the terms of the license (GNU LGPL) which comes with this package. */ + +#include "xbt/ex.h" +#include "xbt/dict.h" +#include "portable.h" +#include "surf_private.h" +#include "surf/surf_resource.h" +#include "simgrid/sg_config.h" + +typedef struct workstation_VM2013 { + s_surf_resource_t generic_resource; /* Must remain first to add this to a trace */ + surf_resource_t physical_workstation; // Pointer to the host OS + e_msg_vm_state_t current_state; // See include/msg/datatypes.h +} s_workstation_VM2013_t, *workstation_VM2013_t; + +XBT_LOG_NEW_DEFAULT_SUBCATEGORY(surf_vm_workstation, surf, + "Logging specific to the SURF VM workstation module"); + +surf_model_t surf_vm_workstation_model = NULL; + +static void vm_ws_create(const char *name, void *ind_phys_workstation) +{ + workstation_VM2013_t vm_ws = xbt_new0(s_workstation_VM2013_t, 1); +// TODO Complete the surf vm workstation model + vm_ws->generic_resource.model = surf_vm_workstation_model; + vm_ws->generic_resource.name = xbt_strdup(name); + // ind means ''indirect'' that this is a reference on the whole dict_elm structure (i.e not on the surf_resource_private infos) + vm_ws->physical_workstation = surf_workstation_resource_priv(ind_phys_workstation); + vm_ws->current_state=msg_vm_state_created, + xbt_lib_set(host_lib, name, SURF_WKS_LEVEL, vm_ws); +} + + +/* + * A physical host does not disapper in the current SimGrid code, but a VM may + * disapper during a simulation. + */ +static void vm_ws_destroy(void *ind_phys_workstation) +{ + /* ind_phys_workstation equals to smx_host_t */ + workstation_VM2013_t vm_ws = surf_workstation_resource_priv(ind_phys_workstation); + xbt_assert(vm_ws); + xbt_assert(vm_ws->generic_resource.model == surf_vm_workstation_model); + + const char *name = vm_ws->generic_resource.name; + /* this will call surf_resource_free() */ + xbt_lib_unset(host_lib, name, SURF_WKS_LEVEL); + + xbt_free(vm_ws->generic_resource.name); + xbt_free(vm_ws); +} + +static int vm_ws_get_state(void *ind_vm_ws){ + return ((workstation_VM2013_t) surf_workstation_resource_priv(ind_vm_ws))->current_state; +} + +static void vm_ws_set_state(void *ind_vm_ws, int state){ + ((workstation_VM2013_t) surf_workstation_resource_priv(ind_vm_ws))->current_state=state; +} +static void surf_vm_workstation_model_init_internal(void) +{ + surf_vm_workstation_model = surf_model_init(); + + surf_vm_workstation_model->name = "Virtual Workstation"; + + surf_vm_workstation_model->extension.vm_workstation.create = vm_ws_create; + surf_vm_workstation_model->extension.vm_workstation.set_state = vm_ws_set_state; + surf_vm_workstation_model->extension.vm_workstation.get_state = vm_ws_get_state; + surf_vm_workstation_model->extension.vm_workstation.destroy = vm_ws_destroy; + +} + +void surf_vm_workstation_model_init() +{ + surf_vm_workstation_model_init_internal(); + xbt_dynar_push(model_list, &surf_vm_workstation_model); +} diff --git a/src/xbt/ex.c b/src/xbt/ex.c index ac2fa9b01b..7faa0f0079 100644 --- a/src/xbt/ex.c +++ b/src/xbt/ex.c @@ -222,6 +222,9 @@ const char *xbt_ex_catname(xbt_errcat_t cat) return "tracing error"; case io_error: return "io error"; + case vm_error: + return "vm error"; + } return "INVALID ERROR"; } diff --git a/src/xbt/lib.c b/src/xbt/lib.c index ccb1e0ef42..a76ca15468 100644 --- a/src/xbt/lib.c +++ b/src/xbt/lib.c @@ -70,6 +70,37 @@ void xbt_lib_set(xbt_lib_t lib, const char *key, int level, void *obj) elts[level] = obj; } +/* for vm */ +void xbt_lib_unset(xbt_lib_t lib, const char *key, int level) +{ + void **elts = xbt_dict_get_or_null(lib->dict, key); + if (!elts) { + XBT_WARN("no key %s", key); + return; + } + + void *obj = elts[level]; + + if (!obj) { + XBT_WARN("no key %s at level %d", key, level); + return; + } else { + XBT_DEBUG("Remove %p of key %s at level %d", obj, key, level); + lib->free_f[level](obj); + elts[level] = NULL; + } + + /* check if there are elements of this key */ + int i; + for (i = 0; i < lib->levels; i++) { + if (elts[i] != NULL) + return; + } + + /* there is no element at any level, so delete the key */ + xbt_dict_remove(lib->dict, key); +} + void *xbt_lib_get_or_null(xbt_lib_t lib, const char *key, int level) { void **elts = xbt_dict_get_or_null(lib->dict, key); @@ -85,3 +116,7 @@ void *xbt_lib_get_level(xbt_dictelm_t elm, int level){ void **elts = elm->content; return elts ? elts[level] : NULL; } + +void xbt_lib_remove(xbt_lib_t lib, const char *key){ + xbt_dict_remove(lib->dict, key); +}