X-Git-Url: http://info.iut-bm.univ-fcomte.fr/pub/gitweb/simgrid.git/blobdiff_plain/d3154c75960afc4f3fe7e53c835e35f2584ed97a..578f8560bc178994f6d8857695b9a8f478b03f2b:/src/msg/msg_task.cpp diff --git a/src/msg/msg_task.cpp b/src/msg/msg_task.cpp index b7e6a6d1a8..d3416fc5ee 100644 --- a/src/msg/msg_task.cpp +++ b/src/msg/msg_task.cpp @@ -1,166 +1,240 @@ -/* Copyright (c) 2004-2015. The SimGrid Team. - * All rights reserved. */ +/* Copyright (c) 2004-2019. 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 "msg_private.h" -#include "src/simix/smx_private.h" -#include "xbt/sysdep.h" -#include "xbt/log.h" +#include "msg_private.hpp" +#include "src/instr/instr_private.hpp" +#include +#include +#include +#include -/** @addtogroup m_task_management - * - * Since most scheduling algorithms rely on a concept of task that can be either computed locally or - * transferred on another processor, it seems to be the right level of abstraction for our purposes. - * A task may then be defined by a computing amount, a message size and - * some private data. - */ +#include +#include XBT_LOG_NEW_DEFAULT_SUBCATEGORY(msg_task, msg, "Logging specific to MSG (task)"); -/********************************* Task **************************************/ -/** \ingroup m_task_management - * \brief Creates a new #msg_task_t. - * - * A constructor for #msg_task_t taking four arguments and returning the corresponding object. - * \param name a name for the object. It is for user-level information and can be NULL. - * \param flop_amount a value of the processing amount (in flop) needed to process this new task. - * If 0, then it cannot be executed with MSG_task_execute(). This value has to be >=0. - * \param message_size a value of the amount of data (in bytes) needed to transfer this new task. If 0, then it cannot - * be transfered with MSG_task_send() and MSG_task_recv(). This value has to be >=0. - * \param data a pointer to any data may want to attach to the new object. It is for user-level information and can - * be NULL. It can be retrieved with the function \ref MSG_task_get_data. - * \see msg_task_t - * \return The new corresponding object. - */ -msg_task_t MSG_task_create(const char *name, double flop_amount, double message_size, void *data) +namespace simgrid { +namespace msg { + +Task::Task(std::string name, double flops_amount, double bytes_amount, void* data) + : name_(std::move(name)), userdata_(data), flops_amount(flops_amount), bytes_amount(bytes_amount) { - msg_task_t task = xbt_new(s_msg_task_t, 1); - simdata_task_t simdata = xbt_new(s_simdata_task_t, 1); - task->simdata = simdata; - - /* Task structure */ - task->name = xbt_strdup(name); - task->data = data; - - /* Simulator Data */ - simdata->compute = NULL; - simdata->comm = NULL; - simdata->bytes_amount = message_size; - simdata->flops_amount = flop_amount; - simdata->sender = NULL; - simdata->receiver = NULL; - simdata->source = NULL; - simdata->priority = 1.0; - simdata->bound = 0; - simdata->affinity_mask_db = xbt_dict_new_homogeneous(NULL); - simdata->rate = -1.0; - simdata->isused = 0; - - simdata->host_nb = 0; - simdata->host_list = NULL; - simdata->flops_parallel_amount = NULL; - simdata->bytes_parallel_amount = NULL; - TRACE_msg_task_create(task); - - return task; -} - -/** \ingroup m_task_management - * \brief Creates a new #msg_task_t (a parallel one....). - * - * A constructor for #msg_task_t taking six arguments and returning the corresponding object. - * \param name a name for the object. It is for user-level information and can be NULL. - * \param host_nb the number of hosts implied in the parallel task. - * \param host_list an array of \p host_nb msg_host_t. - * \param flops_amount an array of \p host_nb doubles. - * flops_amount[i] is the total number of operations that have to be performed on host_list[i]. - * \param bytes_amount an array of \p host_nb* \p host_nb doubles. - * \param data a pointer to any data may want to attach to the new object. - * It is for user-level information and can be NULL. - * It can be retrieved with the function \ref MSG_task_get_data. - * \see msg_task_t - * \return The new corresponding object. - */ -msg_task_t MSG_parallel_task_create(const char *name, int host_nb, const msg_host_t * host_list, - double *flops_amount, double *bytes_amount, void *data) + static std::atomic_ullong counter{0}; + id_ = counter++; + if (MC_is_active()) + MC_ignore_heap(&(id_), sizeof(id_)); +} + +Task::Task(std::string name, std::vector hosts, std::vector flops_amount, + std::vector bytes_amount, void* data) + : Task(std::move(name), 1.0, 0, data) { - msg_task_t task = MSG_task_create(name, 0, 0, data); - simdata_task_t simdata = task->simdata; - int i; + parallel_ = true; + hosts_ = std::move(hosts); + flops_parallel_amount = std::move(flops_amount); + bytes_parallel_amount = std::move(bytes_amount); +} - /* Simulator Data specific to parallel tasks */ - simdata->host_nb = host_nb; - simdata->host_list = xbt_new0(sg_host_t, host_nb); - simdata->flops_parallel_amount = flops_amount; - simdata->bytes_parallel_amount = bytes_amount; +Task* Task::create(std::string name, double flops_amount, double bytes_amount, void* data) +{ + return new Task(std::move(name), flops_amount, bytes_amount, data); +} + +Task* Task::create_parallel(std::string name, int host_nb, const msg_host_t* host_list, double* flops_amount, + double* bytes_amount, void* data) +{ + std::vector hosts; + std::vector flops; + std::vector bytes; + + for (int i = 0; i < host_nb; i++) { + hosts.push_back(host_list[i]); + if (flops_amount != nullptr) + flops.push_back(flops_amount[i]); + if (bytes_amount != nullptr) { + for (int j = 0; j < host_nb; j++) + bytes.push_back(bytes_amount[host_nb * i + j]); + } + } + return new Task(std::move(name), std::move(hosts), std::move(flops), std::move(bytes), data); +} + +msg_error_t Task::execute() +{ + /* checking for infinite values */ + xbt_assert(std::isfinite(flops_amount), "flops_amount is not finite!"); + + msg_error_t status = MSG_OK; + if (flops_amount <= 0.0) + return MSG_OK; + + set_used(); + try { + s4u::ExecPtr e = s4u::this_actor::exec_init(flops_amount) + ->set_priority(1 / priority_) + ->set_bound(bound_) + ->set_tracing_category(tracing_category_) + ->start(); + compute = boost::static_pointer_cast(e->get_impl()); + + e->wait(); + + set_not_used(); + XBT_DEBUG("Execution task '%s' finished", get_cname()); + } catch (HostFailureException& e) { + status = MSG_HOST_FAILURE; + } catch (TimeoutError& e) { + status = MSG_TIMEOUT; + } catch (CancelException& e) { + status = MSG_TASK_CANCELED; + } - for (i = 0; i < host_nb; i++) - simdata->host_list[i] = host_list[i]; + /* action ended, set comm and compute = nullptr, the actions is already destroyed in the main function */ + flops_amount = 0.0; + comm = nullptr; + compute = nullptr; - return task; + return status; } -/*************** Begin GPU ***************/ -/** \ingroup m_task_management - * \brief Creates a new #msg_gpu_task_t. +s4u::CommPtr Task::send_async(std::string alias, void_f_pvoid_t cleanup, bool detached) +{ + if (TRACE_actor_is_enabled()) { + container_t process_container = simgrid::instr::Container::by_name(instr_pid(MSG_process_self())); + std::string key = std::string("p") + std::to_string(get_id()); + simgrid::instr::Container::get_root()->get_link("ACTOR_TASK_LINK")->start_event(process_container, "SR", key); + } + + /* Prepare the task to send */ + set_used(); + this->comm = nullptr; + msg_global->sent_msg++; - * A constructor for #msg_gpu_task_t taking four arguments and returning a pointer to the new created GPU task. + s4u::CommPtr comm = s4u::Mailbox::by_name(alias)->put_init(this, bytes_amount)->set_rate(get_rate()); + this->comm = comm; - * \param name a name for the object. It is for user-level information and can be NULL. - * \param flops_amount a value of the processing amount (in flop)needed to process this new task. If 0, then it cannot - * be executed with MSG_gpu_task_execute(). This value has to be >=0. - * \param dispatch_latency time in seconds to load this task on the GPU - * \param collect_latency time in seconds to transfer result from the GPU back to the CPU (host) when done + if (detached) + comm->detach(cleanup); + else + comm->start(); - * \see msg_gpu_task_t - * \return The new corresponding object. - */ -msg_gpu_task_t MSG_gpu_task_create(const char *name, double flops_amount, double dispatch_latency, - double collect_latency) + if (TRACE_is_enabled() && has_tracing_category()) + simgrid::simix::simcall([comm, this] { comm->get_impl()->set_category(std::move(tracing_category_)); }); + + return comm; +} + +void Task::cancel() { - msg_gpu_task_t task = xbt_new(s_msg_gpu_task_t, 1); - simdata_gpu_task_t simdata = xbt_new(s_simdata_gpu_task_t, 1); - task->simdata = simdata; - /* Task structure */ - task->name = xbt_strdup(name); + if (compute) { + simgrid::simix::simcall([this] { compute->cancel(); }); + } else if (comm) { + comm->cancel(); + } + set_not_used(); +} - /* Simulator Data */ - simdata->flops_amount = flops_amount; - simdata->dispatch_latency = dispatch_latency; - simdata->collect_latency = collect_latency; +void Task::set_priority(double priority) +{ + xbt_assert(std::isfinite(1.0 / priority), "priority is not finite!"); + priority_ = 1.0 / priority; +} - /* TRACE_msg_gpu_task_create(task); FIXME*/ - return task; +s4u::Actor* Task::get_sender() +{ + return comm ? comm->get_sender().get() : nullptr; +} + +s4u::Host* Task::get_source() +{ + return comm ? comm->get_sender()->get_host() : nullptr; +} + +void Task::set_used() +{ + if (is_used_) + report_multiple_use(); + is_used_ = true; +} + +void Task::report_multiple_use() const +{ + if (msg_global->debug_multiple_use){ + XBT_ERROR("This task is already used in there:"); + // TODO, backtrace + XBT_ERROR(""); + XBT_ERROR("And you try to reuse it from here:"); + xbt_backtrace_display_current(); + } else { + xbt_die("This task is still being used somewhere else. You cannot send it now. Go fix your code!" + "(use --cfg=msg/debug-multiple-use:on to get the backtrace of the other process)"); + } } -/*************** End GPU ***************/ +} // namespace msg +} // namespace simgrid -/** \ingroup m_task_management - * \brief Return the user data of a #msg_task_t. +/********************************* Task **************************************/ +/** @brief Creates a new task + * + * A constructor for msg_task_t taking four arguments. * - * This function checks whether \a task is a valid pointer and return the user data associated to \a task if possible. + * @param name a name for the object. It is for user-level information and can be nullptr. + * @param flop_amount a value of the processing amount (in flop) needed to process this new task. + * If 0, then it cannot be executed with MSG_task_execute(). This value has to be >=0. + * @param message_size a value of the amount of data (in bytes) needed to transfer this new task. If 0, then it cannot + * be transfered with MSG_task_send() and MSG_task_recv(). This value has to be >=0. + * @param data a pointer to any data may want to attach to the new object. It is for user-level information and can + * be nullptr. It can be retrieved with the function @ref MSG_task_get_data. + * @return The new corresponding object. */ -void *MSG_task_get_data(msg_task_t task) +msg_task_t MSG_task_create(const char *name, double flop_amount, double message_size, void *data) { - xbt_assert((task != NULL), "Invalid parameter"); - return (task->data); + return simgrid::msg::Task::create(name ? std::string(name) : "", flop_amount, message_size, data); } -/** \ingroup m_task_management - * \brief Sets the user data of a #msg_task_t. +/** @brief Creates a new parallel task + * + * A constructor for #msg_task_t taking six arguments. * - * This function allows to associate a new pointer to the user data associated of \a task. + * \rst + * See :cpp:func:`void simgrid::s4u::this_actor::parallel_execute(int, s4u::Host**, double*, double*)` for + * the exact semantic of the parameters. + * \endrst + * + * @param name a name for the object. It is for user-level information and can be nullptr. + * @param host_nb the number of hosts implied in the parallel task. + * @param host_list an array of @p host_nb msg_host_t. + * @param flops_amount an array of @p host_nb doubles. + * flops_amount[i] is the total number of operations that have to be performed on host_list[i]. + * @param bytes_amount an array of @p host_nb* @p host_nb doubles. + * @param data a pointer to any data may want to attach to the new object. + * It is for user-level information and can be nullptr. + * It can be retrieved with the function @ref MSG_task_get_data(). */ +msg_task_t MSG_parallel_task_create(const char *name, int host_nb, const msg_host_t * host_list, + double *flops_amount, double *bytes_amount, void *data) +{ + // Task's flops amount is set to an arbitrary value > 0.0 to be able to distinguish, in + // MSG_task_get_remaining_work_ratio(), a finished task and a task that has not started yet. + return simgrid::msg::Task::create_parallel(name ? name : "", host_nb, host_list, flops_amount, bytes_amount, data); +} + +/** @brief Return the user data of the given task */ +void* MSG_task_get_data(msg_task_t task) +{ + return task->get_user_data(); +} + +/** @brief Sets the user data of a given task */ void MSG_task_set_data(msg_task_t task, void *data) { - xbt_assert((task != NULL), "Invalid parameter"); - task->data = data; + task->set_user_data(data); } -/** \ingroup m_task_management - * \brief Sets a function to be called when a task has just been copied. - * \param callback a callback function +/** @brief Sets a function to be called when a task has just been copied. + * @param callback a callback function */ void MSG_task_set_copy_callback(void (*callback) (msg_task_t task, msg_process_t sender, msg_process_t receiver)) { @@ -173,54 +247,121 @@ void MSG_task_set_copy_callback(void (*callback) (msg_task_t task, msg_process_t } } -/** \ingroup m_task_management - * \brief Return the sender of a #msg_task_t. +/** @brief Returns the sender of the given task */ +msg_process_t MSG_task_get_sender(msg_task_t task) +{ + return task->get_sender(); +} + +/** @brief Returns the source (the sender's host) of the given task */ +msg_host_t MSG_task_get_source(msg_task_t task) +{ + return task->get_source(); +} + +/** @brief Returns the name of the given task. */ +const char *MSG_task_get_name(msg_task_t task) +{ + return task->get_cname(); +} + +/** @brief Sets the name of the given task. */ +void MSG_task_set_name(msg_task_t task, const char *name) +{ + task->set_name(name); +} + +/** + * @brief Executes a task and waits for its termination. * - * This functions returns the #msg_process_t which sent this task + * This function is used for describing the behavior of a process. It takes only one parameter. + * @param task a #msg_task_t to execute on the location on which the process is running. + * @return #MSG_OK if the task was successfully completed, #MSG_TASK_CANCELED or #MSG_HOST_FAILURE otherwise */ -msg_process_t MSG_task_get_sender(msg_task_t task) +msg_error_t MSG_task_execute(msg_task_t task) { - xbt_assert(task, "Invalid parameters"); - return ((simdata_task_t) task->simdata)->sender; + return task->is_parallel() ? MSG_parallel_task_execute(task) : task->execute(); +} +/** + * @brief Sends a task on a mailbox. + * + * This is a non blocking function: use MSG_comm_wait() or MSG_comm_test() to end the communication. + * + * @param task a #msg_task_t to send on another location. + * @param alias name of the mailbox to sent the task to + * @return the msg_comm_t communication created + */ +msg_comm_t MSG_task_isend(msg_task_t task, const char* alias) +{ + return new simgrid::msg::Comm(task, nullptr, task->send_async(alias, nullptr, false)); } -/** \ingroup m_task_management - * \brief Return the source of a #msg_task_t. +/** + * @brief Sends a task on a mailbox with a maximum rate + * + * This is a non blocking function: use MSG_comm_wait() or MSG_comm_test() to end the communication. The maxrate + * parameter allows the application to limit the bandwidth utilization of network links when sending the task. * - * This functions returns the #msg_host_t from which this task was sent + * @param task a #msg_task_t to send on another location. + * @param alias name of the mailbox to sent the task to + * @param maxrate the maximum communication rate for sending this task (byte/sec). + * @return the msg_comm_t communication created */ -msg_host_t MSG_task_get_source(msg_task_t task) +msg_comm_t MSG_task_isend_bounded(msg_task_t task, const char* alias, double maxrate) { - xbt_assert(task, "Invalid parameters"); - return ((simdata_task_t) task->simdata)->source; + task->set_rate(maxrate); + return new simgrid::msg::Comm(task, nullptr, task->send_async(alias, nullptr, false)); } -/** \ingroup m_task_management - * \brief Return the name of a #msg_task_t. +/** + * @brief Sends a task on a mailbox. + * + * This is a non blocking detached send function. + * Think of it as a best effort send. Keep in mind that the third parameter is only called if the communication fails. + * If the communication does work, it is responsibility of the receiver code to free anything related to the task, as + * usual. More details on this can be obtained on + * this thread + * in the SimGrid-user mailing list archive. * - * This functions returns the name of a #msg_task_t as specified on creation + * @param task a #msg_task_t to send on another location. + * @param alias name of the mailbox to sent the task to + * @param cleanup a function to destroy the task if the communication fails, e.g. MSG_task_destroy + * (if nullptr, no function will be called) */ -const char *MSG_task_get_name(msg_task_t task) +void MSG_task_dsend(msg_task_t task, const char* alias, void_f_pvoid_t cleanup) { - xbt_assert(task, "Invalid parameters"); - return task->name; + task->send_async(alias, cleanup, true); } -/** \ingroup m_task_management - * \brief Sets the name of a #msg_task_t. +/** + * @brief Sends a task on a mailbox with a maximal rate. + * + * This is a non blocking detached send function. + * Think of it as a best effort send. Keep in mind that the third parameter is only called if the communication fails. + * If the communication does work, it is responsibility of the receiver code to free anything related to the task, as + * usual. More details on this can be obtained on + * this thread + * in the SimGrid-user mailing list archive. + * + * The rate parameter can be used to send a task with a limited bandwidth (smaller than the physical available value). + * Use MSG_task_dsend() if you don't limit the rate (or pass -1 as a rate value do disable this feature). + * + * @param task a #msg_task_t to send on another location. + * @param alias name of the mailbox to sent the task to + * @param cleanup a function to destroy the task if the communication fails, e.g. MSG_task_destroy (if nullptr, no + * function will be called) + * @param maxrate the maximum communication rate for sending this task (byte/sec) * - * This functions allows to associate a name to a task */ -void MSG_task_set_name(msg_task_t task, const char *name) +void MSG_task_dsend_bounded(msg_task_t task, const char* alias, void_f_pvoid_t cleanup, double maxrate) { - xbt_assert(task, "Invalid parameters"); - task->name = xbt_strdup(name); + task->set_rate(maxrate); + task->send_async(alias, cleanup, true); } -/** \ingroup m_task_management - * \brief Destroy a #msg_task_t. +/** @brief Destroys the given task. * - * Destructor for #msg_task_t. Note that you should free user data, if any, \b before calling this function. + * You should free user data, if any, @b before calling this destructor. * * Only the process that owns the task can destroy it. * The owner changes after a successful send. @@ -230,217 +371,159 @@ void MSG_task_set_name(msg_task_t task, const char *name) */ msg_error_t MSG_task_destroy(msg_task_t task) { - smx_synchro_t action = NULL; - xbt_assert((task != NULL), "Invalid parameter"); - - if (task->simdata->isused) { + if (task->is_used()) { /* the task is being sent or executed: cancel it first */ - MSG_task_cancel(task); + task->cancel(); } - TRACE_msg_task_destroy(task); - - xbt_free(task->name); - - action = task->simdata->compute; - if (action) - simcall_execution_destroy(action); - - /* parallel tasks only */ - xbt_free(task->simdata->host_list); - - xbt_dict_free(&task->simdata->affinity_mask_db); /* free main structures */ - xbt_free(task->simdata); - xbt_free(task); + delete task; return MSG_OK; } -/** \ingroup m_task_usage - * \brief Cancel a #msg_task_t. - * \param task the task to cancel. If it was executed or transfered, it stops the process that were working on it. +/** @brief Cancel the given task + * + * If it was currently executed or transfered, the working process is stopped. */ msg_error_t MSG_task_cancel(msg_task_t task) { - xbt_assert((task != NULL), "Cannot cancel a NULL task"); + xbt_assert((task != nullptr), "Cannot cancel a nullptr task"); + task->cancel(); + return MSG_OK; +} - if (task->simdata->compute) { - simcall_execution_cancel(task->simdata->compute); - } - else if (task->simdata->comm) { - simdata_task_t simdata = task->simdata; - simcall_comm_cancel(simdata->comm); - if (msg_global->debug_multiple_use && simdata->isused!=0) - xbt_ex_free(*(xbt_ex_t*)simdata->isused); - simdata->isused = 0; +/** @brief Returns a value in ]0,1[ that represent the task remaining work + * to do: starts at 1 and goes to 0. Returns 0 if not started or finished. + * + * It works for either parallel or sequential tasks. + */ +double MSG_task_get_remaining_work_ratio(msg_task_t task) { + + xbt_assert((task != nullptr), "Cannot get information from a nullptr task"); + if (task->compute) { + // Task in progress + return task->compute->get_remaining_ratio(); + } else { + // Task not started (flops_amount is > 0.0) or finished (flops_amount is set to 0.0) + return task->flops_amount > 0.0 ? 1.0 : 0.0; } - return MSG_OK; } -/** \ingroup m_task_management - * \brief Returns the remaining amount of flops needed to execute a task #msg_task_t. +/** @brief Returns the amount of flops that remain to be computed * - * Once a task has been processed, this amount is set to 0. If you want, you can reset this value with - * #MSG_task_set_flops_amount before restarting the task. + * The returned value is initially the cost that you defined for the task, then it decreases until it reaches 0 + * + * It works for sequential tasks, but the remaining amount of work is not a scalar value for parallel tasks. + * So you will get an exception if you call this function on parallel tasks. Just don't do it. */ double MSG_task_get_flops_amount(msg_task_t task) { - if (task->simdata->compute) { - return simcall_execution_get_remains(task->simdata->compute); + if (task->compute != nullptr) { + return task->compute->get_remaining(); } else { - return task->simdata->flops_amount; + // Not started or already done. + // - Before starting, flops_amount is initially the task cost + // - After execution, flops_amount is set to 0 (until someone uses MSG_task_set_flops_amount, if any) + return task->flops_amount; } } -/** \ingroup m_task_management - * \brief set the computation amount needed to process a task #msg_task_t. +/** @brief set the computation amount needed to process the given task. * - * \warning If the computation is ongoing (already started and not finished), + * @warning If the computation is ongoing (already started and not finished), * it is not modified by this call. Moreover, after its completion, the ongoing execution with set the flops_amount to * zero, overriding any value set during the execution. */ void MSG_task_set_flops_amount(msg_task_t task, double flops_amount) { - task->simdata->flops_amount = flops_amount; + task->flops_amount = flops_amount; } -/** \ingroup m_task_management - * \brief set the amount data attached with a task #msg_task_t. +/** @brief set the amount data attached with the given task. * - * \warning If the transfer is ongoing (already started and not finished), it is not modified by this call. + * @warning If the transfer is ongoing (already started and not finished), it is not modified by this call. */ void MSG_task_set_bytes_amount(msg_task_t task, double data_size) { - task->simdata->bytes_amount = data_size; + task->bytes_amount = data_size; } -/** \ingroup m_task_management - * \brief Returns the total amount received by a task #msg_task_t. - * If the communication does not exist it will return 0. - * So, if the communication has FINISHED or FAILED it returns zero. +/** @brief Returns the total amount received by the given task + * + * If the communication does not exist it will return 0. + * So, if the communication has FINISHED or FAILED it returns zero. */ double MSG_task_get_remaining_communication(msg_task_t task) { - xbt_assert((task != NULL) && (task->simdata != NULL), "Invalid parameter"); - XBT_DEBUG("calling simcall_communication_get_remains(%p)", task->simdata->comm); - return simcall_comm_get_remains(task->simdata->comm); + XBT_DEBUG("calling simcall_communication_get_remains(%p)", task->comm.get()); + return task->comm->get_remaining(); } -/** \ingroup m_task_management - * \brief Returns the size of the data attached to a task #msg_task_t. - */ +/** @brief Returns the size of the data attached to the given task. */ double MSG_task_get_bytes_amount(msg_task_t task) { - xbt_assert((task != NULL) && (task->simdata != NULL), "Invalid parameter"); - return task->simdata->bytes_amount; + xbt_assert(task != nullptr, "Invalid parameter"); + return task->bytes_amount; } -/** \ingroup m_task_management - * \brief Changes the priority of a computation task. This priority doesn't affect the transfer rate. A priority of 2 - * will make a task receive two times more cpu power than the other ones. +/** @brief Changes the priority of a computation task. + * + * This priority doesn't affect the transfer rate. A priority of 2 + * will make a task receive two times more cpu power than regular tasks. */ void MSG_task_set_priority(msg_task_t task, double priority) { - xbt_assert((task != NULL) && (task->simdata != NULL), "Invalid parameter"); - task->simdata->priority = 1 / priority; - if (task->simdata->compute) - simcall_execution_set_priority(task->simdata->compute, - task->simdata->priority); + task->set_priority(priority); } -/** \ingroup m_task_management - * \brief Changes the maximum CPU utilization of a computation task. - * Unit is flops/s. +/** @brief Changes the maximum CPU utilization of a computation task (in flops/s). * * For VMs, there is a pitfall. Please see MSG_vm_set_bound(). */ void MSG_task_set_bound(msg_task_t task, double bound) { - xbt_assert(task, "Invalid parameter"); - xbt_assert(task->simdata, "Invalid parameter"); - - if (bound == 0) + if (bound < 1e-12) /* close enough to 0 without any floating precision surprise */ XBT_INFO("bound == 0 means no capping (i.e., unlimited)."); - - task->simdata->bound = bound; - if (task->simdata->compute) - simcall_execution_set_bound(task->simdata->compute, task->simdata->bound); + task->set_bound(bound); } -/** \ingroup m_task_management - * \brief Changes the CPU affinity of a computation task. +/** + * @brief Sets the tracing category of a task. * - * When pinning the given task to the first CPU core of the given host, use 0x01 for the mask value. Each bit of the - * mask value corresponds to each CPU core. See taskset(1) on Linux. + * This function should be called after the creation of a MSG task, to define the category of that task. The + * first parameter task must contain a task that was =created with the function #MSG_task_create. The second + * parameter category must contain a category that was previously declared with the function #TRACE_category + * (or with #TRACE_category_with_color). * - * \param task a target task - * \param host the host having a multi-core CPU - * \param mask the bit mask of a new CPU affinity setting for the task + * See @ref outcomes_vizu for details on how to trace the (categorized) resource utilization. * - * Usage: - * 0. Define a host with multiple cores. - * \ + * @param task the task that is going to be categorized + * @param category the name of the category to be associated to the task * - * 1. Pin a given task to the first CPU core of a host. - * MSG_task_set_affinity(task, pm0, 0x01); - * - * 2. Pin a given task to the third CPU core of a host. Turn on the third bit of the mask. - * MSG_task_set_affinity(task, pm0, 0x04); // 0x04 == 100B - * - * 3. Pin a given VM to the first CPU core of a host. - * MSG_vm_set_affinity(vm, pm0, 0x01); - * - * See examples/msg/cloud/multicore.c for more information. - * - * Note: - * 1. The current code does not allow an affinity of a task to multiple cores. - * The mask value 0x03 (i.e., a given task will be executed on the first core or the second core) is not allowed. - * The mask value 0x01 or 0x02 works. See cpu_cas01.c for details. - * - * 2. It is recommended to first compare simulation results in both the Lazy and Full calculation modes - * (using --cfg=cpu/optim:Full or not). Fix cpu_cas01.c if you find wrong results in the Lazy mode. + * @see MSG_task_get_category, TRACE_category, TRACE_category_with_color */ -void MSG_task_set_affinity(msg_task_t task, msg_host_t host, unsigned long mask) -{ - xbt_assert(task, "Invalid parameter"); - xbt_assert(task->simdata, "Invalid parameter"); - - if (mask == 0) { - /* 0 means clear */ - /* We need remove_ext() not throwing exception. */ - void *ret = xbt_dict_get_or_null_ext(task->simdata->affinity_mask_db, (char *) host, sizeof(msg_host_t)); - if (ret != NULL) - xbt_dict_remove_ext(task->simdata->affinity_mask_db, (char *) host, sizeof(host)); - } else - xbt_dict_set_ext(task->simdata->affinity_mask_db, (char *) host, sizeof(host), (void *)(uintptr_t) mask, NULL); - - /* We set affinity data of this task. If the task is being executed, we actually change the affinity setting of the - * task. Otherwise, this change will be applied when the task is executed. */ - if (!task->simdata->compute) { - /* task is not yet executed */ - XBT_INFO("set affinity(0x%04lx@%s) for %s (not active now)", mask, MSG_host_get_name(host), - MSG_task_get_name(task)); - return; - } - - { - smx_synchro_t compute = task->simdata->compute; - msg_host_t host_now = compute->execution.host; // simix_private.h is necessary - if (host_now != host) { - /* task is not yet executed on this host */ - XBT_INFO("set affinity(0x%04lx@%s) for %s (not active now)", mask, MSG_host_get_name(host), - MSG_task_get_name(task)); - return; - } - - /* task is being executed on this host. so change the affinity now */ - { - /* check it works. remove me if it works. */ - xbt_assert((unsigned long)(uintptr_t) xbt_dict_get_or_null_ext(task->simdata->affinity_mask_db, - (char *) host, sizeof(msg_host_t)) == mask); - } +void MSG_task_set_category(msg_task_t task, const char* category) +{ + xbt_assert(not task->has_tracing_category(), "Task %p(%s) already has a category (%s).", task, task->get_cname(), + task->get_tracing_category().c_str()); - XBT_INFO("set affinity(0x%04lx@%s) for %s", mask, MSG_host_get_name(host), MSG_task_get_name(task)); - simcall_execution_set_affinity(task->simdata->compute, host, mask); + // if user provides a nullptr category, task is no longer traced + if (category == nullptr) { + task->set_tracing_category(""); + XBT_DEBUG("MSG task %p(%s), category removed", task, task->get_cname()); + } else { + // set task category + task->set_tracing_category(category); + XBT_DEBUG("MSG task %p(%s), category %s", task, task->get_cname(), task->get_tracing_category().c_str()); } } + +/** + * @brief Gets the current tracing category of a task. (@see MSG_task_set_category) + * @param task the task to be considered + * @return Returns the name of the tracing category of the given task, "" otherwise + */ +const char* MSG_task_get_category(msg_task_t task) +{ + return task->get_tracing_category().c_str(); +}