Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
split surf_parse into a separate file to make it reusable from elsewhere
authorMartin Quinson <martin.quinson@ens-rennes.fr>
Wed, 10 Jun 2020 21:35:42 +0000 (23:35 +0200)
committerMartin Quinson <martin.quinson@ens-rennes.fr>
Wed, 10 Jun 2020 21:57:56 +0000 (23:57 +0200)
Also rename surf_parse_* functions into xbt_parse_*

Also, make the file name and line number explicit, as parameters to
functions that need it (less hidden global state is better). But I was
too lazy to clean smpi::parse_factor() tonight: the pandora box
remains closed for tonight.

14 files changed:
include/simgrid/Exception.hpp
include/xbt/parse_units.hpp [new file with mode: 0644]
src/bindings/lua/lua_platf.cpp
src/plugins/file_system/s4u_FileSystem.cpp
src/smpi/internals/smpi_utils.cpp
src/surf/StorageImpl.hpp
src/surf/sg_platf.cpp
src/surf/storage_n11.cpp
src/surf/storage_n11.hpp
src/surf/xml/platf.hpp
src/surf/xml/platf_private.hpp
src/surf/xml/surfxml_sax_cb.cpp
src/xbt/xbt_parse_units.cpp [new file with mode: 0644]
tools/cmake/DefinePackages.cmake

index b7ab71f..f09b566 100644 (file)
@@ -194,6 +194,7 @@ public:
       : Exception(XBT_THROW_POINT, xbt::string_printf("Parse error at %s:%d: %s", file.c_str(), line, msg.c_str()))
   {
   }
+  ParseError(const std::string& msg) : Exception(XBT_THROW_POINT, xbt::string_printf("Parse error: %s", msg.c_str())) {}
   ParseError(const ParseError&)     = default;
   ParseError(ParseError&&) noexcept = default;
   ~ParseError();
diff --git a/include/xbt/parse_units.hpp b/include/xbt/parse_units.hpp
new file mode 100644 (file)
index 0000000..7350c24
--- /dev/null
@@ -0,0 +1,23 @@
+/* Copyright (c) 2007-2020. 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. */
+
+#ifndef SIMGRID_XBT_PARSE_UNITS_HPP
+#define SIMGRID_XBT_PARSE_UNITS_HPP
+
+double xbt_parse_get_time(const std::string& filename, int lineno, const char* string, const char* entity_kind,
+                          const std::string& name);
+double surf_parse_get_size(const std::string& filename, int lineno, const char* string, const char* entity_kind,
+                           const std::string& name);
+double xbt_parse_get_bandwidth(const std::string& filename, int lineno, const char* string, const char* entity_kind,
+                               const std::string& name);
+std::vector<double> xbt_parse_get_bandwidths(const std::string& filename, int lineno, const char* string,
+                                             const char* entity_kind, const std::string& name);
+double xbt_parse_get_speed(const std::string& filename, int lineno, const char* string, const char* entity_kind,
+                           const std::string& name);
+std::vector<double> xbt_parse_get_all_speeds(const std::string& filename, int lineno, char* speeds,
+                                             const char* entity_kind, const std::string& id);
+
+#endif
index 239ea85..9b47ad0 100644 (file)
@@ -11,6 +11,7 @@
 #include "src/surf/network_interface.hpp"
 #include "src/surf/surf_private.hpp"
 #include "src/surf/xml/platf_private.hpp"
+#include "xbt/parse_units.hpp"
 
 #include <boost/algorithm/string/classification.hpp>
 #include <boost/algorithm/string/split.hpp>
@@ -79,6 +80,9 @@ int console_close(lua_State*)
 
 int console_add_backbone(lua_State *L) {
   simgrid::kernel::routing::LinkCreationArgs link;
+  lua_Debug ar;
+  lua_getstack(L, 1, &ar);
+  lua_getinfo(L, "Sl", &ar);
 
   link.properties = nullptr;
 
@@ -94,14 +98,16 @@ int console_add_backbone(lua_State *L) {
   type = lua_gettable(L, -2);
   lua_ensure(type == LUA_TSTRING || type == LUA_TNUMBER,
       "Attribute 'bandwidth' must be specified for backbone and must either be a string (in the right format; see docs) or a number.");
-  link.bandwidths.push_back(surf_parse_get_bandwidth(lua_tostring(L, -1), "bandwidth of backbone", link.id.c_str()));
+  link.bandwidths.push_back(xbt_parse_get_bandwidth(ar.short_src, ar.currentline, lua_tostring(L, -1),
+                                                    "bandwidth of backbone", link.id.c_str()));
   lua_pop(L, 1);
 
   lua_pushstring(L, "lat");
   type = lua_gettable(L, -2);
   lua_ensure(type == LUA_TSTRING || type == LUA_TNUMBER,
       "Attribute 'lat' must be specified for backbone and must either be a string (in the right format; see docs) or a number.");
-  link.latency = surf_parse_get_time(lua_tostring(L, -1), "latency of backbone", link.id.c_str());
+  link.latency =
+      xbt_parse_get_time(ar.short_src, ar.currentline, lua_tostring(L, -1), "latency of backbone", link.id.c_str());
   lua_pop(L, 1);
 
   lua_pushstring(L, "sharing_policy");
@@ -151,6 +157,9 @@ int console_add_host___link(lua_State *L) {
 int console_add_host(lua_State *L) {
   simgrid::kernel::routing::HostCreationArgs host;
   int type;
+  lua_Debug ar;
+  lua_getstack(L, 1, &ar);
+  lua_getinfo(L, "Sl", &ar);
 
   // we get values from the table passed as argument
   lua_ensure(lua_istable(L, -1),
@@ -172,7 +181,8 @@ int console_add_host(lua_State *L) {
   if (type == LUA_TNUMBER)
     host.speed_per_pstate.push_back(lua_tointeger(L, -1));
   else // LUA_TSTRING
-    host.speed_per_pstate.push_back(surf_parse_get_speed(lua_tostring(L, -1), "speed of host", host.id));
+    host.speed_per_pstate.push_back(
+        xbt_parse_get_speed(ar.short_src, ar.currentline, lua_tostring(L, -1), "speed of host", host.id));
   lua_pop(L, 1);
 
   // get core
@@ -209,6 +219,9 @@ int console_add_host(lua_State *L) {
 
 int  console_add_link(lua_State *L) {
   simgrid::kernel::routing::LinkCreationArgs link;
+  lua_Debug ar;
+  lua_getstack(L, 1, &ar);
+  lua_getinfo(L, "Sl", &ar);
 
   const char* policy;
 
@@ -230,7 +243,8 @@ int  console_add_link(lua_State *L) {
   if (type == LUA_TNUMBER)
     link.bandwidths.push_back(lua_tonumber(L, -1));
   else // LUA_TSTRING
-    link.bandwidths.push_back(surf_parse_get_bandwidth(lua_tostring(L, -1), "bandwidth of link", link.id.c_str()));
+    link.bandwidths.push_back(xbt_parse_get_bandwidth(ar.short_src, ar.currentline, lua_tostring(L, -1),
+                                                      "bandwidth of link", link.id.c_str()));
   lua_pop(L, 1);
 
   //get latency value
@@ -241,7 +255,8 @@ int  console_add_link(lua_State *L) {
   if (type == LUA_TNUMBER)
     link.latency = lua_tonumber(L, -1);
   else // LUA_TSTRING
-    link.latency = surf_parse_get_time(lua_tostring(L, -1), "latency of link", link.id.c_str());
+    link.latency =
+        xbt_parse_get_time(ar.short_src, ar.currentline, lua_tostring(L, -1), "latency of link", link.id.c_str());
   lua_pop(L, 1);
 
   /*Optional Arguments  */
index 88478db..d291a32 100644 (file)
@@ -9,6 +9,7 @@
 #include "src/surf/HostImpl.hpp"
 #include "src/surf/xml/platf_private.hpp"
 #include "xbt/config.hpp"
+#include "xbt/parse_units.hpp"
 
 #include <algorithm>
 #include <boost/algorithm/string.hpp>
@@ -483,8 +484,9 @@ int File::remote_move(sg_host_t host, const char* fullpath)
 FileSystemDiskExt::FileSystemDiskExt(const Disk* ptr)
 {
   const char* size_str    = ptr->get_property("size");
+  std::string dummyfile;
   if (size_str)
-    size_ = surf_parse_get_size(size_str, "disk size", ptr->get_name());
+    size_ = surf_parse_get_size(dummyfile, -1, size_str, "disk size", ptr->get_name());
 
   const char* current_mount_str = ptr->get_property("mount");
   if (current_mount_str)
index 23a1736..66e4ca0 100644 (file)
@@ -5,13 +5,18 @@
  * under the terms of the license (GNU LGPL) which comes with this package. */
 
 #include "smpi_utils.hpp"
+
+#include "src/surf/xml/platf_private.hpp"
 #include "xbt/log.h"
+#include "xbt/parse_units.hpp"
 #include "xbt/sysdep.h"
 #include <boost/tokenizer.hpp>
-#include "src/surf/xml/platf_private.hpp"
 
 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(smpi_utils, smpi, "Logging specific to SMPI (utils)");
 
+extern std::string& surf_parsed_filename;
+extern int surf_parse_lineno;
+
 std::vector<s_smpi_factor_t> parse_factor(const std::string& smpi_coef_string)
 {
   std::vector<s_smpi_factor_t> smpi_factor;
@@ -49,7 +54,8 @@ std::vector<s_smpi_factor_t> parse_factor(const std::string& smpi_coef_string)
         }
       } else {
         try {
-          fact.values.push_back(surf_parse_get_time((*factor_iter).c_str(), "smpi factor", ""));
+          fact.values.push_back(
+              xbt_parse_get_time(surf_parsed_filename, surf_parse_lineno, (*factor_iter).c_str(), "smpi factor", ""));
         } catch (const std::invalid_argument&) {
           throw std::invalid_argument(std::string("Invalid factor value ") + std::to_string(iteration) + " in chunk " +
                                       std::to_string(smpi_factor.size() + 1) + ": " + *factor_iter);
index b1c6047..955fb3f 100644 (file)
@@ -48,7 +48,8 @@ public:
   StorageModel& operator=(const StorageModel&) = delete;
   ~StorageModel();
 
-  virtual StorageImpl* createStorage(const std::string& id, const std::string& type_id, const std::string& content_name,
+  virtual StorageImpl* createStorage(std::string& filename, int lineno, const std::string& id,
+                                     const std::string& type_id, const std::string& content_name,
                                      const std::string& attach) = 0;
 };
 
index 01cbb71..291b2a1 100644 (file)
@@ -383,7 +383,8 @@ void sg_platf_new_storage(simgrid::kernel::routing::StorageCreationArgs* storage
             storage->id.c_str(), stype->model.c_str(), stype->id.c_str(), storage->content.c_str(),
             storage->properties);
 
-  auto s = surf_storage_model->createStorage(storage->id, stype->id, storage->content, storage->attach);
+  auto s = surf_storage_model->createStorage(storage->filename, storage->lineno, storage->id, stype->id,
+                                             storage->content, storage->attach);
 
   if (storage->properties) {
     s->set_properties(*storage->properties);
index 50439d8..cc116c5 100644 (file)
@@ -10,6 +10,7 @@
 #include "src/kernel/lmm/maxmin.hpp"
 #include "src/surf/xml/platf.hpp"
 #include "surf/surf.hpp"
+#include "xbt/parse_units.hpp"
 
 XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(surf_storage);
 
@@ -49,15 +50,16 @@ StorageN11Model::StorageN11Model()
   all_existing_models.push_back(this);
 }
 
-StorageImpl* StorageN11Model::createStorage(const std::string& id, const std::string& type_id,
-                                            const std::string& content_name, const std::string& attach)
+StorageImpl* StorageN11Model::createStorage(std::string& filename, int lineno, const std::string& id,
+                                            const std::string& type_id, const std::string& content_name,
+                                            const std::string& attach)
 {
   const StorageType* storage_type = storage_types.at(type_id);
 
-  double Bread =
-      surf_parse_get_bandwidth(storage_type->model_properties->at("Bread").c_str(), "property Bread, storage", type_id);
-  double Bwrite = surf_parse_get_bandwidth(storage_type->model_properties->at("Bwrite").c_str(),
-                                           "property Bwrite, storage", type_id);
+  double Bread  = xbt_parse_get_bandwidth(filename, lineno, storage_type->model_properties->at("Bread").c_str(),
+                                         "property Bread, storage", type_id);
+  double Bwrite = xbt_parse_get_bandwidth(filename, lineno, storage_type->model_properties->at("Bwrite").c_str(),
+                                          "property Bwrite, storage", type_id);
 
   XBT_DEBUG("SURF storage create resource\n\t\tid '%s'\n\t\ttype '%s'\n\t\tBread '%f'\n", id.c_str(), type_id.c_str(),
             Bread);
index cad3774..3fcd75c 100644 (file)
@@ -29,8 +29,8 @@ class XBT_PRIVATE StorageN11Action;
 class StorageN11Model : public StorageModel {
 public:
   StorageN11Model();
-  StorageImpl* createStorage(const std::string& id, const std::string& type_id, const std::string& content_name,
-                             const std::string& attach) override;
+  StorageImpl* createStorage(std::string& filename, int lineno, const std::string& id, const std::string& type_id,
+                             const std::string& content_name, const std::string& attach) override;
   double next_occurring_event(double now) override;
   void update_actions_state(double now, double delta) override;
 };
index 070894d..1ea9f32 100644 (file)
@@ -23,12 +23,6 @@ XBT_PUBLIC void surf_parse_assert_netpoint(const std::string& hostname, const st
 
 XBT_PUBLIC double surf_parse_get_double(const std::string& s);
 XBT_PUBLIC int surf_parse_get_int(const std::string& s);
-XBT_PUBLIC double surf_parse_get_time(const char* string, const char* entity_kind, const std::string& name);
-XBT_PUBLIC double surf_parse_get_size(const char* string, const char* entity_kind, const std::string& name);
-XBT_PUBLIC double surf_parse_get_bandwidth(const char* string, const char* entity_kind, const std::string& name);
-XBT_PUBLIC std::vector<double> surf_parse_get_bandwidths(const char* string, const char* entity_kind,
-                                                         const std::string& name);
-XBT_PUBLIC double surf_parse_get_speed(const char* string, const char* entity_kind, const std::string& name);
 
 XBT_PUBLIC void surf_parse(); /* Entry-point to the parser */
 
index 71a6398..5b7a510 100644 (file)
@@ -123,6 +123,8 @@ public:
 
 class StorageCreationArgs {
 public:
+  std::string filename;
+  int lineno;
   std::string id;
   std::string type_id;
   std::string content;
index 06db516..43d1dbe 100644 (file)
@@ -14,8 +14,8 @@
 #include "src/surf/xml/platf_private.hpp"
 #include "surf/surf.hpp"
 #include "xbt/file.hpp"
+#include "xbt/parse_units.hpp"
 
-#include <boost/algorithm/string.hpp>
 #include <boost/algorithm/string/classification.hpp>
 #include <boost/algorithm/string/split.hpp>
 #include <string>
@@ -27,7 +27,7 @@
 
 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(surf_parse, surf, "Logging specific to the SURF parsing module");
 
-static std::string surf_parsed_filename; // Currently parsed file (for the error messages)
+std::string surf_parsed_filename; // Currently parsed file (for the error messages)
 std::vector<simgrid::kernel::resource::LinkImpl*>
     parsed_link_list; /* temporary store of current link list of a route */
 std::vector<simgrid::kernel::resource::DiskImpl*> parsed_disk_list; /* temporary store of current disk list of a host */
@@ -94,10 +94,8 @@ int surf_parse_get_int(const std::string& s)
   }
 }
 
-namespace {
-
 /* Turn something like "1-4,6,9-11" into the vector {1,2,3,4,6,9,10,11} */
-std::vector<int>* explodesRadical(const std::string& radicals)
+static std::vector<int>* explodesRadical(const std::string& radicals)
 {
   std::vector<int>* exploded = new std::vector<int>();
 
@@ -127,143 +125,6 @@ std::vector<int>* explodesRadical(const std::string& radicals)
   return exploded;
 }
 
-class unit_scale : public std::unordered_map<std::string, double> {
-public:
-  using std::unordered_map<std::string, double>::unordered_map;
-  // tuples are : <unit, value for unit, base (2 or 10), true if abbreviated>
-  explicit unit_scale(std::initializer_list<std::tuple<const std::string, double, int, bool>> generators);
-};
-
-unit_scale::unit_scale(std::initializer_list<std::tuple<const std::string, double, int, bool>> generators)
-{
-  for (const auto& gen : generators) {
-    const std::string& unit = std::get<0>(gen);
-    double value            = std::get<1>(gen);
-    const int base          = std::get<2>(gen);
-    const bool abbrev       = std::get<3>(gen);
-    double mult;
-    std::vector<std::string> prefixes;
-    switch (base) {
-      case 2:
-        mult     = 1024.0;
-        prefixes = abbrev ? std::vector<std::string>{"Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi", "Yi"}
-                          : std::vector<std::string>{"kibi", "mebi", "gibi", "tebi", "pebi", "exbi", "zebi", "yobi"};
-        break;
-      case 10:
-        mult     = 1000.0;
-        prefixes = abbrev ? std::vector<std::string>{"k", "M", "G", "T", "P", "E", "Z", "Y"}
-                          : std::vector<std::string>{"kilo", "mega", "giga", "tera", "peta", "exa", "zeta", "yotta"};
-        break;
-      default:
-        THROW_IMPOSSIBLE;
-    }
-    emplace(unit, value);
-    for (const auto& prefix : prefixes) {
-      value *= mult;
-      emplace(prefix + unit, value);
-    }
-  }
-}
-
-/* Note: no warning is issued for unit-less values when `name' is empty. */
-double surf_parse_get_value_with_unit(const char* string, const unit_scale& units, const char* entity_kind,
-                                      const std::string& name, const char* error_msg, const char* default_unit)
-{
-  char* endptr;
-  errno = 0;
-  double res      = strtod(string, &endptr);
-  const char* ptr = endptr; // for const-correctness
-  if (errno == ERANGE)
-    surf_parse_error(std::string("value out of range: ") + string);
-  if (ptr == string)
-    surf_parse_error(std::string("cannot parse number:") + string);
-  if (ptr[0] == '\0') {
-    // Ok, 0 can be unit-less
-    if (res != 0 && not name.empty())
-      XBT_WARN("Deprecated unit-less value '%s' for %s %s. %s", string, entity_kind, name.c_str(), error_msg);
-    ptr = default_unit;
-  }
-  auto u = units.find(ptr);
-  if (u == units.end())
-    surf_parse_error(std::string("unknown unit: ") + ptr);
-  return res * u->second;
-}
-}
-
-double surf_parse_get_time(const char* string, const char* entity_kind, const std::string& name)
-{
-  static const unit_scale units{std::make_pair("w", 7 * 24 * 60 * 60),
-                                std::make_pair("d", 24 * 60 * 60),
-                                std::make_pair("h", 60 * 60),
-                                std::make_pair("m", 60),
-                                std::make_pair("s", 1.0),
-                                std::make_pair("ms", 1e-3),
-                                std::make_pair("us", 1e-6),
-                                std::make_pair("ns", 1e-9),
-                                std::make_pair("ps", 1e-12)};
-  return surf_parse_get_value_with_unit(string, units, entity_kind, name,
-      "Append 's' to your time to get seconds", "s");
-}
-
-double surf_parse_get_size(const char* string, const char* entity_kind, const std::string& name)
-{
-  static const unit_scale units{std::make_tuple("b", 0.125, 2, true), std::make_tuple("b", 0.125, 10, true),
-                                std::make_tuple("B", 1.0, 2, true), std::make_tuple("B", 1.0, 10, true)};
-  return surf_parse_get_value_with_unit(string, units, entity_kind, name,
-      "Append 'B' to get bytes (or 'b' for bits but 1B = 8b).", "B");
-}
-
-double surf_parse_get_bandwidth(const char* string, const char* entity_kind, const std::string& name)
-{
-  static const unit_scale units{std::make_tuple("bps", 0.125, 2, true), std::make_tuple("bps", 0.125, 10, true),
-                                std::make_tuple("Bps", 1.0, 2, true), std::make_tuple("Bps", 1.0, 10, true)};
-  return surf_parse_get_value_with_unit(string, units, entity_kind, name,
-      "Append 'Bps' to get bytes per second (or 'bps' for bits but 1Bps = 8bps)", "Bps");
-}
-
-std::vector<double> surf_parse_get_bandwidths(const char* string, const char* entity_kind, const std::string& name)
-{
-  static const unit_scale units{std::make_tuple("bps", 0.125, 2, true), std::make_tuple("bps", 0.125, 10, true),
-                                std::make_tuple("Bps", 1.0, 2, true), std::make_tuple("Bps", 1.0, 10, true)};
-
-  std::vector<double> bandwidths;
-  std::vector<std::string> tokens;
-  boost::split(tokens, string, boost::is_any_of(";"));
-  for (auto token : tokens) {
-    bandwidths.push_back(surf_parse_get_value_with_unit(
-        token.c_str(), units, entity_kind, name,
-        "Append 'Bps' to get bytes per second (or 'bps' for bits but 1Bps = 8bps)", "Bps"));
-  }
-
-  return bandwidths;
-}
-
-double surf_parse_get_speed(const char* string, const char* entity_kind, const std::string& name)
-{
-  static const unit_scale units{std::make_tuple("f", 1.0, 10, true), std::make_tuple("flops", 1.0, 10, false)};
-  return surf_parse_get_value_with_unit(string, units, entity_kind, name,
-      "Append 'f' or 'flops' to your speed to get flop per second", "f");
-}
-
-static std::vector<double> surf_parse_get_all_speeds(char* speeds, const char* entity_kind, const std::string& id)
-{
-  std::vector<double> speed_per_pstate;
-
-  if (strchr(speeds, ',') == nullptr){
-    double speed = surf_parse_get_speed(speeds, entity_kind, id);
-    speed_per_pstate.push_back(speed);
-  } else {
-    std::vector<std::string> pstate_list;
-    boost::split(pstate_list, speeds, boost::is_any_of(","));
-    for (auto speed_str : pstate_list) {
-      boost::trim(speed_str);
-      double speed = surf_parse_get_speed(speed_str.c_str(), entity_kind, id);
-      speed_per_pstate.push_back(speed);
-      XBT_DEBUG("Speed value: %f", speed);
-    }
-  }
-  return speed_per_pstate;
-}
 
 /*
  * All the callback lists that can be overridden anywhere.
@@ -293,6 +154,8 @@ void ETag_surfxml_storage()
   storage.properties = property_sets.back();
   property_sets.pop_back();
 
+  storage.filename     = surf_parsed_filename;
+  storage.lineno       = surf_parse_lineno;
   storage.id           = A_surfxml_storage_id;
   storage.type_id      = A_surfxml_storage_typeId;
   storage.content      = A_surfxml_storage_content;
@@ -319,8 +182,8 @@ void ETag_surfxml_storage___type()
   storage_type.content = A_surfxml_storage___type_content;
   storage_type.id      = A_surfxml_storage___type_id;
   storage_type.model   = A_surfxml_storage___type_model;
-  storage_type.size =
-      surf_parse_get_size(A_surfxml_storage___type_size, "size of storage type", storage_type.id.c_str());
+  storage_type.size    = surf_parse_get_size(surf_parsed_filename, surf_parse_lineno, A_surfxml_storage___type_size,
+                                          "size of storage type", storage_type.id.c_str());
   sg_platf_new_storage_type(&storage_type);
 }
 
@@ -418,7 +281,8 @@ void ETag_surfxml_host()    {
 
   host.id = A_surfxml_host_id;
 
-  host.speed_per_pstate = surf_parse_get_all_speeds(A_surfxml_host_speed, "speed of host", host.id);
+  host.speed_per_pstate =
+      xbt_parse_get_all_speeds(surf_parsed_filename, surf_parse_lineno, A_surfxml_host_speed, "speed of host", host.id);
 
   XBT_DEBUG("pstate: %s", A_surfxml_host_pstate);
   host.core_amount = surf_parse_get_int(A_surfxml_host_core);
@@ -450,8 +314,10 @@ void ETag_surfxml_disk() {
   property_sets.pop_back();
 
   disk.id       = A_surfxml_disk_id;
-  disk.read_bw  = surf_parse_get_bandwidth(A_surfxml_disk_read___bw, "read_bw of disk ", disk.id);
-  disk.write_bw = surf_parse_get_bandwidth(A_surfxml_disk_write___bw, "write_bw of disk ", disk.id);
+  disk.read_bw  = xbt_parse_get_bandwidth(surf_parsed_filename, surf_parse_lineno, A_surfxml_disk_read___bw,
+                                         "read_bw of disk ", disk.id);
+  disk.write_bw = xbt_parse_get_bandwidth(surf_parsed_filename, surf_parse_lineno, A_surfxml_disk_write___bw,
+                                          "write_bw of disk ", disk.id);
 
   parsed_disk_list.push_back(sg_platf_new_disk(&disk));
 }
@@ -479,20 +345,29 @@ void ETag_surfxml_cluster(){
   cluster.prefix      = A_surfxml_cluster_prefix;
   cluster.suffix      = A_surfxml_cluster_suffix;
   cluster.radicals    = explodesRadical(A_surfxml_cluster_radical);
-  cluster.speeds      = surf_parse_get_all_speeds(A_surfxml_cluster_speed, "speed of cluster", cluster.id);
+  cluster.speeds      = xbt_parse_get_all_speeds(surf_parsed_filename, surf_parse_lineno, A_surfxml_cluster_speed,
+                                            "speed of cluster", cluster.id);
   cluster.core_amount = surf_parse_get_int(A_surfxml_cluster_core);
-  cluster.bw          = surf_parse_get_bandwidth(A_surfxml_cluster_bw, "bw of cluster", cluster.id);
-  cluster.lat         = surf_parse_get_time(A_surfxml_cluster_lat, "lat of cluster", cluster.id);
+  cluster.bw = xbt_parse_get_bandwidth(surf_parsed_filename, surf_parse_lineno, A_surfxml_cluster_bw, "bw of cluster",
+                                       cluster.id);
+  cluster.lat =
+      xbt_parse_get_time(surf_parsed_filename, surf_parse_lineno, A_surfxml_cluster_lat, "lat of cluster", cluster.id);
   if(strcmp(A_surfxml_cluster_bb___bw,""))
-    cluster.bb_bw = surf_parse_get_bandwidth(A_surfxml_cluster_bb___bw, "bb_bw of cluster", cluster.id);
+    cluster.bb_bw = xbt_parse_get_bandwidth(surf_parsed_filename, surf_parse_lineno, A_surfxml_cluster_bb___bw,
+                                            "bb_bw of cluster", cluster.id);
   if(strcmp(A_surfxml_cluster_bb___lat,""))
-    cluster.bb_lat = surf_parse_get_time(A_surfxml_cluster_bb___lat, "bb_lat of cluster", cluster.id);
+    cluster.bb_lat = xbt_parse_get_time(surf_parsed_filename, surf_parse_lineno, A_surfxml_cluster_bb___lat,
+                                        "bb_lat of cluster", cluster.id);
   if(strcmp(A_surfxml_cluster_limiter___link,""))
-    cluster.limiter_link = surf_parse_get_bandwidth(A_surfxml_cluster_limiter___link, "limiter_link of cluster", cluster.id);
+    cluster.limiter_link =
+        xbt_parse_get_bandwidth(surf_parsed_filename, surf_parse_lineno, A_surfxml_cluster_limiter___link,
+                                "limiter_link of cluster", cluster.id);
   if(strcmp(A_surfxml_cluster_loopback___bw,""))
-    cluster.loopback_bw = surf_parse_get_bandwidth(A_surfxml_cluster_loopback___bw, "loopback_bw of cluster", cluster.id);
+    cluster.loopback_bw = xbt_parse_get_bandwidth(
+        surf_parsed_filename, surf_parse_lineno, A_surfxml_cluster_loopback___bw, "loopback_bw of cluster", cluster.id);
   if(strcmp(A_surfxml_cluster_loopback___lat,""))
-    cluster.loopback_lat = surf_parse_get_time(A_surfxml_cluster_loopback___lat, "loopback_lat of cluster", cluster.id);
+    cluster.loopback_lat = xbt_parse_get_time(surf_parsed_filename, surf_parse_lineno, A_surfxml_cluster_loopback___lat,
+                                              "loopback_lat of cluster", cluster.id);
 
   switch(AX_surfxml_cluster_topology){
   case A_surfxml_cluster_topology_FLAT:
@@ -553,9 +428,12 @@ void STag_surfxml_cabinet(){
   cabinet.id      = A_surfxml_cabinet_id;
   cabinet.prefix  = A_surfxml_cabinet_prefix;
   cabinet.suffix  = A_surfxml_cabinet_suffix;
-  cabinet.speed    = surf_parse_get_speed(A_surfxml_cabinet_speed, "speed of cabinet", cabinet.id.c_str());
-  cabinet.bw       = surf_parse_get_bandwidth(A_surfxml_cabinet_bw, "bw of cabinet", cabinet.id.c_str());
-  cabinet.lat      = surf_parse_get_time(A_surfxml_cabinet_lat, "lat of cabinet", cabinet.id.c_str());
+  cabinet.speed   = xbt_parse_get_speed(surf_parsed_filename, surf_parse_lineno, A_surfxml_cabinet_speed,
+                                      "speed of cabinet", cabinet.id.c_str());
+  cabinet.bw  = xbt_parse_get_bandwidth(surf_parsed_filename, surf_parse_lineno, A_surfxml_cabinet_bw, "bw of cabinet",
+                                       cabinet.id.c_str());
+  cabinet.lat = xbt_parse_get_time(surf_parsed_filename, surf_parse_lineno, A_surfxml_cabinet_lat, "lat of cabinet",
+                                   cabinet.id.c_str());
   cabinet.radicals = explodesRadical(A_surfxml_cabinet_radical);
 
   sg_platf_new_cabinet(&cabinet);
@@ -565,9 +443,12 @@ void STag_surfxml_peer(){
   simgrid::kernel::routing::PeerCreationArgs peer;
 
   peer.id          = std::string(A_surfxml_peer_id);
-  peer.speed       = surf_parse_get_speed(A_surfxml_peer_speed, "speed of peer", peer.id.c_str());
-  peer.bw_in       = surf_parse_get_bandwidth(A_surfxml_peer_bw___in, "bw_in of peer", peer.id.c_str());
-  peer.bw_out      = surf_parse_get_bandwidth(A_surfxml_peer_bw___out, "bw_out of peer", peer.id.c_str());
+  peer.speed       = xbt_parse_get_speed(surf_parsed_filename, surf_parse_lineno, A_surfxml_peer_speed, "speed of peer",
+                                   peer.id.c_str());
+  peer.bw_in = xbt_parse_get_bandwidth(surf_parsed_filename, surf_parse_lineno, A_surfxml_peer_bw___in, "bw_in of peer",
+                                       peer.id.c_str());
+  peer.bw_out      = xbt_parse_get_bandwidth(surf_parsed_filename, surf_parse_lineno, A_surfxml_peer_bw___out,
+                                        "bw_out of peer", peer.id.c_str());
   peer.coord       = A_surfxml_peer_coordinates;
   peer.speed_trace = nullptr;
   if (A_surfxml_peer_availability___file[0] != '\0') {
@@ -598,11 +479,13 @@ void ETag_surfxml_link(){
   property_sets.pop_back();
 
   link.id                  = std::string(A_surfxml_link_id);
-  link.bandwidths          = surf_parse_get_bandwidths(A_surfxml_link_bandwidth, "bandwidth of link", link.id.c_str());
+  link.bandwidths          = xbt_parse_get_bandwidths(surf_parsed_filename, surf_parse_lineno, A_surfxml_link_bandwidth,
+                                             "bandwidth of link", link.id.c_str());
   link.bandwidth_trace     = A_surfxml_link_bandwidth___file[0]
                              ? simgrid::kernel::profile::Profile::from_file(A_surfxml_link_bandwidth___file)
                              : nullptr;
-  link.latency             = surf_parse_get_time(A_surfxml_link_latency, "latency of link", link.id.c_str());
+  link.latency = xbt_parse_get_time(surf_parsed_filename, surf_parse_lineno, A_surfxml_link_latency, "latency of link",
+                                    link.id.c_str());
   link.latency_trace       = A_surfxml_link_latency___file[0]
                            ? simgrid::kernel::profile::Profile::from_file(A_surfxml_link_latency___file)
                            : nullptr;
@@ -672,9 +555,10 @@ void ETag_surfxml_backbone(){
 
   link.properties = nullptr;
   link.id = std::string(A_surfxml_backbone_id);
-  link.bandwidths.push_back(
-      surf_parse_get_bandwidth(A_surfxml_backbone_bandwidth, "bandwidth of backbone", link.id.c_str()));
-  link.latency = surf_parse_get_time(A_surfxml_backbone_latency, "latency of backbone", link.id.c_str());
+  link.bandwidths.push_back(xbt_parse_get_bandwidth(
+      surf_parsed_filename, surf_parse_lineno, A_surfxml_backbone_bandwidth, "bandwidth of backbone", link.id.c_str()));
+  link.latency    = xbt_parse_get_time(surf_parsed_filename, surf_parse_lineno, A_surfxml_backbone_latency,
+                                    "latency of backbone", link.id.c_str());
   link.policy     = simgrid::s4u::Link::SharingPolicy::SHARED;
 
   sg_platf_new_link(&link);
diff --git a/src/xbt/xbt_parse_units.cpp b/src/xbt/xbt_parse_units.cpp
new file mode 100644 (file)
index 0000000..a77b852
--- /dev/null
@@ -0,0 +1,159 @@
+#include "simgrid/Exception.hpp"
+#include "xbt/ex.h"
+#include "xbt/log.h"
+
+#include "xbt/parse_units.hpp"
+
+#include <boost/algorithm/string.hpp>
+#include <boost/algorithm/string/classification.hpp>
+#include <boost/algorithm/string/split.hpp>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+XBT_LOG_NEW_DEFAULT_SUBCATEGORY(parse, xbt, "Parsing functions");
+
+class unit_scale : public std::unordered_map<std::string, double> {
+public:
+  using std::unordered_map<std::string, double>::unordered_map;
+  // tuples are : <unit, value for unit, base (2 or 10), true if abbreviated>
+  explicit unit_scale(std::initializer_list<std::tuple<const std::string, double, int, bool>> generators);
+};
+
+unit_scale::unit_scale(std::initializer_list<std::tuple<const std::string, double, int, bool>> generators)
+{
+  for (const auto& gen : generators) {
+    const std::string& unit = std::get<0>(gen);
+    double value            = std::get<1>(gen);
+    const int base          = std::get<2>(gen);
+    const bool abbrev       = std::get<3>(gen);
+    double mult;
+    std::vector<std::string> prefixes;
+    switch (base) {
+      case 2:
+        mult     = 1024.0;
+        prefixes = abbrev ? std::vector<std::string>{"Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi", "Yi"}
+                          : std::vector<std::string>{"kibi", "mebi", "gibi", "tebi", "pebi", "exbi", "zebi", "yobi"};
+        break;
+      case 10:
+        mult     = 1000.0;
+        prefixes = abbrev ? std::vector<std::string>{"k", "M", "G", "T", "P", "E", "Z", "Y"}
+                          : std::vector<std::string>{"kilo", "mega", "giga", "tera", "peta", "exa", "zeta", "yotta"};
+        break;
+      default:
+        THROW_IMPOSSIBLE;
+    }
+    emplace(unit, value);
+    for (const auto& prefix : prefixes) {
+      value *= mult;
+      emplace(prefix + unit, value);
+    }
+  }
+}
+
+/* Note: no warning is issued for unit-less values when `name' is empty. */
+static double surf_parse_get_value_with_unit(const std::string& filename, int lineno, const char* string,
+                                             const unit_scale& units, const char* entity_kind, const std::string& name,
+                                             const char* error_msg, const char* default_unit)
+{
+  char* endptr;
+  errno           = 0;
+  double res      = strtod(string, &endptr);
+  const char* ptr = endptr; // for const-correctness
+  if (errno == ERANGE)
+    throw simgrid::ParseError(filename, lineno, std::string("value out of range: ") + string);
+  if (ptr == string)
+    throw simgrid::ParseError(filename, lineno, std::string("cannot parse number:") + string);
+  if (ptr[0] == '\0') {
+    // Ok, 0 can be unit-less
+    if (res != 0 && not name.empty())
+      XBT_WARN("Deprecated unit-less value '%s' for %s %s. %s", string, entity_kind, name.c_str(), error_msg);
+    ptr = default_unit;
+  }
+  auto u = units.find(ptr);
+  if (u == units.end())
+    throw simgrid::ParseError(filename, lineno, std::string("unknown unit: ") + ptr);
+  return res * u->second;
+}
+
+double xbt_parse_get_time(const std::string& filename, int lineno, const char* string, const char* entity_kind,
+                          const std::string& name)
+{
+  static const unit_scale units{std::make_pair("w", 7 * 24 * 60 * 60),
+                                std::make_pair("d", 24 * 60 * 60),
+                                std::make_pair("h", 60 * 60),
+                                std::make_pair("m", 60),
+                                std::make_pair("s", 1.0),
+                                std::make_pair("ms", 1e-3),
+                                std::make_pair("us", 1e-6),
+                                std::make_pair("ns", 1e-9),
+                                std::make_pair("ps", 1e-12)};
+  return surf_parse_get_value_with_unit(filename, lineno, string, units, entity_kind, name,
+                                        "Append 's' to your time to get seconds", "s");
+}
+
+double surf_parse_get_size(const std::string& filename, int lineno, const char* string, const char* entity_kind,
+                           const std::string& name)
+{
+  static const unit_scale units{std::make_tuple("b", 0.125, 2, true), std::make_tuple("b", 0.125, 10, true),
+                                std::make_tuple("B", 1.0, 2, true), std::make_tuple("B", 1.0, 10, true)};
+  return surf_parse_get_value_with_unit(filename, lineno, string, units, entity_kind, name,
+                                        "Append 'B' to get bytes (or 'b' for bits but 1B = 8b).", "B");
+}
+
+double xbt_parse_get_bandwidth(const std::string& filename, int lineno, const char* string, const char* entity_kind,
+                               const std::string& name)
+{
+  static const unit_scale units{std::make_tuple("bps", 0.125, 2, true), std::make_tuple("bps", 0.125, 10, true),
+                                std::make_tuple("Bps", 1.0, 2, true), std::make_tuple("Bps", 1.0, 10, true)};
+  return surf_parse_get_value_with_unit(filename, lineno, string, units, entity_kind, name,
+                                        "Append 'Bps' to get bytes per second (or 'bps' for bits but 1Bps = 8bps)",
+                                        "Bps");
+}
+
+std::vector<double> xbt_parse_get_bandwidths(const std::string& filename, int lineno, const char* string,
+                                             const char* entity_kind, const std::string& name)
+{
+  static const unit_scale units{std::make_tuple("bps", 0.125, 2, true), std::make_tuple("bps", 0.125, 10, true),
+                                std::make_tuple("Bps", 1.0, 2, true), std::make_tuple("Bps", 1.0, 10, true)};
+
+  std::vector<double> bandwidths;
+  std::vector<std::string> tokens;
+  boost::split(tokens, string, boost::is_any_of(";"));
+  for (auto token : tokens) {
+    bandwidths.push_back(surf_parse_get_value_with_unit(
+        filename, lineno, token.c_str(), units, entity_kind, name,
+        "Append 'Bps' to get bytes per second (or 'bps' for bits but 1Bps = 8bps)", "Bps"));
+  }
+
+  return bandwidths;
+}
+
+double xbt_parse_get_speed(const std::string& filename, int lineno, const char* string, const char* entity_kind,
+                           const std::string& name)
+{
+  static const unit_scale units{std::make_tuple("f", 1.0, 10, true), std::make_tuple("flops", 1.0, 10, false)};
+  return surf_parse_get_value_with_unit(filename, lineno, string, units, entity_kind, name,
+                                        "Append 'f' or 'flops' to your speed to get flop per second", "f");
+}
+
+std::vector<double> xbt_parse_get_all_speeds(const std::string& filename, int lineno, char* speeds,
+                                             const char* entity_kind, const std::string& id)
+{
+  std::vector<double> speed_per_pstate;
+
+  if (strchr(speeds, ',') == nullptr) {
+    double speed = xbt_parse_get_speed(filename, lineno, speeds, entity_kind, id);
+    speed_per_pstate.push_back(speed);
+  } else {
+    std::vector<std::string> pstate_list;
+    boost::split(pstate_list, speeds, boost::is_any_of(","));
+    for (auto speed_str : pstate_list) {
+      boost::trim(speed_str);
+      double speed = xbt_parse_get_speed(filename, lineno, speed_str.c_str(), entity_kind, id);
+      speed_per_pstate.push_back(speed);
+      XBT_DEBUG("Speed value: %f", speed);
+    }
+  }
+  return speed_per_pstate;
+}
index ecfb07e..8faa9a6 100644 (file)
@@ -295,6 +295,7 @@ set(XBT_SRC
   src/xbt/xbt_main.cpp
   src/xbt/xbt_os_file.cpp
   src/xbt/xbt_os_time.c
+  src/xbt/xbt_parse_units.cpp
   src/xbt/xbt_replay.cpp
   src/xbt/xbt_str.cpp
   src/xbt/xbt_virtu.cpp
@@ -778,6 +779,7 @@ set(headers_to_install
   include/xbt/module.h
   include/xbt/PropertyHolder.hpp
   include/xbt/parmap.h
+  include/xbt/parse_units.hpp
   include/xbt/range.hpp
   include/xbt/random.hpp
   include/xbt/replay.hpp