/* 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 "simdag_private.hpp"
#include "simgrid/simdag.h"
-#include "xbt/misc.h"
+#include "xbt/file.h" /* xbt_basename() */
#include "xbt/log.h"
+#include "xbt/misc.h"
#include "xbt/str.h"
-#include "xbt/file.h" /* xbt_basename() */
-#include "simdag_private.hpp"
+#include <unordered_map>
XBT_LOG_NEW_DEFAULT_SUBCATEGORY(sd_daxparse, sd, "Parsing DAX files");
}
/* Ensure that transfer tasks have unique names even though a file is used several times */
-
void uniq_transfer_task_name(SD_task_t task)
{
SD_task_t child = *(task->successors->begin());
SD_task_t parent = *(task->predecessors->begin());
- char *new_name = bprintf("%s_%s_%s", SD_task_get_name(parent), SD_task_get_name(task), SD_task_get_name(child));
+ std::string new_name =
+ std::string(SD_task_get_name(parent)) + "_" + SD_task_get_name(task) + "_" + SD_task_get_name(child);
- SD_task_set_name(task, new_name);
-
- free(new_name);
+ SD_task_set_name(task, new_name.c_str());
}
static bool children_are_marked(SD_task_t task){
static YY_BUFFER_STATE input_buffer;
static xbt_dynar_t result;
-static xbt_dict_t jobs;
+static std::unordered_map<std::string, SD_task_t> jobs;
static xbt_dict_t files;
static SD_task_t current_job;
static SD_task_t root_task;
{
xbt_dict_cursor_t cursor;
SD_task_t file;
- char *name;
- FILE *in_file = fopen(filename, "r");
+ char* name;
+ FILE* in_file = fopen(filename, "r");
xbt_assert(in_file, "Unable to open \"%s\"\n", filename);
input_buffer = dax__create_buffer(in_file, 10);
dax__switch_to_buffer(input_buffer);
result = xbt_dynar_new(sizeof(SD_task_t), dax_task_free);
files = xbt_dict_new_homogeneous(&dax_task_free);
- jobs = xbt_dict_new_homogeneous(nullptr);
root_task = SD_task_create_comp_seq("root", nullptr, 0);
/* by design the root task is always SCHEDULABLE */
SD_task_set_state(root_task, SD_SCHEDULABLE);
dax__delete_buffer(input_buffer);
fclose(in_file);
dax_lex_destroy();
- xbt_dict_free(&jobs);
/* And now, post-process the files.
* We want a file task per pair of computation tasks exchanging the file. Duplicate on need
void STag_dax__adag()
{
- XBT_ATTRIB_UNUSED double version;
- version = xbt_str_parse_double(A_dax__adag_version, "Parse error: %s is not a double");
-
- xbt_assert(version == 2.1, "Expected version 2.1 in <adag> tag, got %f. Fix the parser or your file", version);
+ try {
+ double version = std::stod(std::string(A_dax__adag_version));
+ xbt_assert(version == 2.1, "Expected version 2.1 in <adag> tag, got %f. Fix the parser or your file", version);
+ } catch (std::invalid_argument& ia) {
+ throw std::invalid_argument(std::string("Parse error: ") + A_dax__adag_version + " is not a double");
+ }
}
void STag_dax__job()
{
- double runtime = xbt_str_parse_double(A_dax__job_runtime, "Parse error: %s is not a double");
- char *name = bprintf("%s@%s", A_dax__job_id, A_dax__job_name);
- runtime *= 4200000000.; /* Assume that timings were done on a 4.2GFlops machine. I mean, why not? */
- XBT_DEBUG("See <job id=%s runtime=%s %.0f>",A_dax__job_id,A_dax__job_runtime,runtime);
- current_job = SD_task_create_comp_seq(name, nullptr, runtime);
- xbt_dict_set(jobs, A_dax__job_id, current_job, nullptr);
- free(name);
- xbt_dynar_push(result, ¤t_job);
+ try {
+ double runtime = std::stod(std::string(A_dax__job_runtime));
+
+ std::string name = std::string(A_dax__job_id) + "@" + A_dax__job_name;
+ runtime *= 4200000000.; /* Assume that timings were done on a 4.2GFlops machine. I mean, why not? */
+ XBT_DEBUG("See <job id=%s runtime=%s %.0f>", A_dax__job_id, A_dax__job_runtime, runtime);
+ current_job = SD_task_create_comp_seq(name.c_str(), nullptr, runtime);
+ jobs.insert({A_dax__job_id, current_job});
+ xbt_dynar_push(result, ¤t_job);
+ } catch (std::invalid_argument& ia) {
+ throw std::invalid_argument(std::string("Parse error: ") + A_dax__job_runtime + " is not a double");
+ }
}
void STag_dax__uses()
{
- double size = xbt_str_parse_double(A_dax__uses_size, "Parse error: %s is not a double");
- int is_input = (A_dax__uses_link == A_dax__uses_link_input);
+ double size;
+ try {
+ size = std::stod(std::string(A_dax__uses_size));
+ } catch (std::invalid_argument& ia) {
+ throw std::invalid_argument(std::string("Parse error: ") + A_dax__uses_size + " is not a double");
+ }
+ bool is_input = (A_dax__uses_link == A_dax__uses_link_input);
XBT_DEBUG("See <uses file=%s %s>",A_dax__uses_file,(is_input?"in":"out"));
SD_task_t file = static_cast<SD_task_t>(xbt_dict_get_or_null(files, A_dax__uses_file));
static SD_task_t current_child;
void STag_dax__child()
{
- current_child = static_cast<SD_task_t>(xbt_dict_get_or_null(jobs, A_dax__child_ref));
- xbt_assert(current_child != nullptr,"Parse error on line %d: Asked to add dependencies to the non-existent %s task",
- dax_lineno, A_dax__child_ref);
+ try {
+ current_child = jobs.at(A_dax__child_ref);
+ } catch (std::out_of_range& unfound) {
+ throw std::out_of_range(std::string("Parse error on line ") + std::to_string(dax_lineno) +
+ ": Asked to add dependencies to the non-existent " + A_dax__child_ref + "task");
+ }
}
void ETag_dax__child()
void STag_dax__parent()
{
- SD_task_t parent = static_cast<SD_task_t>(xbt_dict_get_or_null(jobs, A_dax__parent_ref));
- xbt_assert(parent != nullptr, "Parse error on line %d: Asked to add a dependency from %s to %s, but %s does not exist",
- dax_lineno, current_child->name, A_dax__parent_ref, A_dax__parent_ref);
- SD_task_dependency_add(nullptr, nullptr, parent, current_child);
- XBT_DEBUG("Control-flow dependency from %s to %s", current_child->name, parent->name);
+ try {
+ SD_task_t parent = jobs.at(A_dax__parent_ref);
+ SD_task_dependency_add(nullptr, nullptr, parent, current_child);
+ XBT_DEBUG("Control-flow dependency from %s to %s", current_child->name, parent->name);
+ } catch (std::out_of_range& unfound) {
+ throw std::out_of_range(std::string("Parse error on line ") + std::to_string(dax_lineno) +
+ ": Asked to add a dependency from " + current_child->name + " to " + A_dax__parent_ref +
+ ", but " + A_dax__parent_ref + " does not exist");
+ }
}
void ETag_dax__adag()
/** @addtogroup plugin_energy
-
-This is the energy plugin, enabling to account not only for computation time,
-but also for the dissipated energy in the simulated platform.
-To activate this plugin, first call sg_host_energy_plugin_init() before your #MSG_init(),
-and then use MSG_host_get_consumed_energy() to retrieve the consumption of a given host.
-
-When the host is on, this energy consumption naturally depends on both the
-current CPU load and the host energy profile. According to our measurements,
-the consumption is somehow linear in the amount of cores at full speed,
-with an abnormality when all the cores are idle. The full details are in
+This is the energy plugin, enabling to account not only for computation time, but also for the dissipated energy in the
+simulated platform.
+To activate this plugin, first call sg_host_energy_plugin_init() before your #MSG_init(), and then use
+MSG_host_get_consumed_energy() to retrieve the consumption of a given host.
+
+When the host is on, this energy consumption naturally depends on both the current CPU load and the host energy profile.
+According to our measurements, the consumption is somehow linear in the amount of cores at full speed, with an
+abnormality when all the cores are idle. The full details are in
<a href="https://hal.inria.fr/hal-01523608">our scientific paper</a> on that topic.
As a result, our energy model takes 4 parameters:
### What if a given core is only at load 50%?
-This is impossible in SimGrid because we recompute everything each time
-that the CPU starts or stops doing something. So if a core is at load 50% over
-a period, it means that it is at load 100% half of the time and at load 0% the
-rest of the time, and our model holds.
+This is impossible in SimGrid because we recompute everything each time that the CPU starts or stops doing something.
+So if a core is at load 50% over a period, it means that it is at load 100% half of the time and at load 0% the rest of
+the time, and our model holds.
### What if the host has only one core?
### How does DVFS interact with the host energy model?
-If your host has several DVFS levels (several pstates), then you should
-give the energetic profile of each pstate level:
+If your host has several DVFS levels (several pstates), then you should give the energetic profile of each pstate level:
\code{.xml}
<host id="HostC" power="100.0Mf,50.0Mf,20.0Mf" cores="4">
### How accurate are these models?
-This model cannot be more accurate than your instantiation:
-with the default values, your result will not be accurate at all. You can still get
-accurate energy prediction, provided that you carefully instantiate the model.
-The first step is to ensure that your timing prediction match perfectly. But this
-is only the first step of the path, and you really want to read
-<a href="https://hal.inria.fr/hal-01523608">this paper</a> to see all what you need
-to do before you can get accurate energy predictions.
-
+This model cannot be more accurate than your instantiation: with the default values, your result will not be accurate at
+all. You can still get accurate energy prediction, provided that you carefully instantiate the model.
+The first step is to ensure that your timing prediction match perfectly. But this is only the first step of the path,
+and you really want to read <a href="https://hal.inria.fr/hal-01523608">this paper</a> to see all what you need to do
+before you can get accurate energy predictions.
*/
XBT_LOG_NEW_DEFAULT_SUBCATEGORY(surf_energy, surf, "Logging specific to the SURF energy plugin");
std::vector<PowerRange>
power_range_watts_list; /*< List of (min_power,max_power) pairs corresponding to each cpu pstate */
- /* We need to keep track of what pstate has been used, as we will sometimes
- * be notified only *after* a pstate has been used (but we need to update the energy consumption
- * with the old pstate!)
+ /* We need to keep track of what pstate has been used, as we will sometimes be notified only *after* a pstate has been
+ * used (but we need to update the energy consumption with the old pstate!)
*/
int pstate = 0;
const int pstate_off = -1;
simgrid::xbt::Extension<simgrid::s4u::Host, HostEnergy> HostEnergy::EXTENSION_ID;
-/* Computes the consumption so far. Called lazily on need. */
+/* Computes the consumption so far. Called lazily on need. */
void HostEnergy::update()
{
double start_time = this->last_updated;
const char* off_power_str = host->getProperty("watt_off");
if (off_power_str != nullptr) {
- char* msg = bprintf("Invalid value for property watt_off of host %s: %%s", host->getCname());
- this->watts_off = xbt_str_parse_double(off_power_str, msg);
- xbt_free(msg);
+ try {
+ this->watts_off = std::stod(std::string(off_power_str));
+ } catch (std::invalid_argument& ia) {
+ throw std::invalid_argument(std::string("Invalid value for property watt_off of host ") + host->getCname() +
+ ": " + off_power_str);
+ }
}
/* watts_off is 0 by default */
}