Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
less dict, bprintf, and xbt_str_parse
authorFrederic Suter <frederic.suter@cc.in2p3.fr>
Thu, 27 Jul 2017 09:00:37 +0000 (11:00 +0200)
committerFrederic Suter <frederic.suter@cc.in2p3.fr>
Thu, 27 Jul 2017 09:46:45 +0000 (11:46 +0200)
src/simdag/sd_daxloader.cpp
src/smpi/internals/smpi_process.cpp
src/smpi/internals/smpi_utils.cpp
src/surf/plugins/host_energy.cpp

index e642431..843e43e 100644 (file)
@@ -4,12 +4,13 @@
 /* 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");
 
@@ -22,17 +23,15 @@ extern "C" {
 }
 
 /* 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){
@@ -142,7 +141,7 @@ bool acyclic_graph_detail(xbt_dynar_t dag){
 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;
@@ -161,8 +160,8 @@ xbt_dynar_t SD_daxload(const char *filename)
 {
   xbt_dict_cursor_t cursor;
   SD_task_t file;
-  char *name;
-  FILE *in_file = fopen(filename, "r");
+  charname;
+  FILEin_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);
@@ -170,7 +169,6 @@ xbt_dynar_t SD_daxload(const char *filename)
 
   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);
@@ -184,7 +182,6 @@ xbt_dynar_t SD_daxload(const char *filename)
   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
@@ -263,28 +260,39 @@ xbt_dynar_t SD_daxload(const char *filename)
 
 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, &current_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, &current_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));
@@ -310,9 +318,12 @@ void STag_dax__uses()
 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()
@@ -322,11 +333,15 @@ 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()
index 451f3cf..4ffaea8 100644 (file)
@@ -158,10 +158,8 @@ smx_actor_t Process::process(){
   return process_;
 }
 
-
 /**
- * \brief Returns a structure that stores the location (filename + linenumber)
- *        of the last calls to MPI_* functions.
+ * \brief Returns a structure that stores the location (filename + linenumber) of the last calls to MPI_* functions.
  *
  * \see smpi_trace_set_call_location
  */
@@ -281,8 +279,12 @@ void Process::init(int *argc, char ***argv){
     }
 
     char* instance_id = (*argv)[1];
-    int rank = xbt_str_parse_int((*argv)[2], "Invalid rank: %s");
-    smpi_deployment_register_process(instance_id, rank, index);
+    try {
+      int rank = std::stoi(std::string((*argv)[2]));
+      smpi_deployment_register_process(instance_id, rank, index);
+    } catch (std::invalid_argument& ia) {
+      throw std::invalid_argument(std::string("Invalid rank: ") + (*argv)[2]);
+    }
 
     if(smpi_privatize_global_variables == SMPI_PRIVATIZE_MMAP){
       /* Now using segment index of the process  */
index 91e01ce..e0ef96f 100644 (file)
@@ -40,16 +40,22 @@ std::vector<s_smpi_factor_t> parse_factor(const char *smpi_coef_string)
     unsigned int iteration = 0;
     for (Tokenizer::iterator factor_iter = factor_values.begin(); factor_iter != factor_values.end(); factor_iter++) {
       iteration++;
-      char *errmsg;
 
       if (factor_iter == factor_values.begin()) { /* first element */
-        errmsg = bprintf("Invalid factor in chunk #%zu: %%s", smpi_factor.size()+1);
-        fact.factor = xbt_str_parse_int(factor_iter->c_str(), errmsg);
+        try {
+          fact.factor = std::stoi(*factor_iter);
+        } catch (std::invalid_argument& ia) {
+          throw std::invalid_argument(std::string("Invalid factor in chunk ") + std::to_string(smpi_factor.size() + 1) +
+                                      ": " + *factor_iter);
+        }
       } else {
-        errmsg = bprintf("Invalid factor value %d in chunk #%zu: %%s", iteration, smpi_factor.size()+1);
-        fact.values.push_back(xbt_str_parse_double(factor_iter->c_str(), errmsg));
+        try {
+          fact.values.push_back(std::stod(*factor_iter));
+        } catch (std::invalid_argument& ia) {
+          throw std::invalid_argument(std::string("Invalid factor value ") + std::to_string(iteration) + " in chunk " +
+                                      std::to_string(smpi_factor.size() + 1) + ": " + *factor_iter);
+        }
       }
-      xbt_free(errmsg);
     }
 
     smpi_factor.push_back(fact);
index 0436ec2..bc636d3 100644 (file)
 
 /** @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:
@@ -61,10 +59,9 @@ This is enough to compute the consumption as a function of the amount of loaded
 
 ### 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?
 
@@ -81,8 +78,7 @@ If you insist on passing 3 parameters in this case, then you must have the same
 
 ### 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">
@@ -104,14 +100,11 @@ To change the pstate of a given CPU, use the following functions:
 
 ### 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");
@@ -147,9 +140,8 @@ private:
   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;
@@ -162,7 +154,7 @@ public:
 
 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;
@@ -229,9 +221,12 @@ HostEnergy::HostEnergy(simgrid::s4u::Host* ptr) : host(ptr), last_updated(surf_g
 
   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 */
 }