Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Merge branch 'master' into adrien
[simgrid.git] / src / xbt / xbt_parse_units.cpp
1 #include "simgrid/Exception.hpp"
2 #include "xbt/ex.h"
3 #include "xbt/log.h"
4
5 #include "xbt/parse_units.hpp"
6
7 #include <boost/algorithm/string.hpp>
8 #include <boost/algorithm/string/classification.hpp>
9 #include <boost/algorithm/string/split.hpp>
10 #include <string>
11 #include <unordered_map>
12 #include <vector>
13
14 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(parse, xbt, "Parsing functions");
15
16 class unit_scale : public std::unordered_map<std::string, double> {
17 public:
18   using std::unordered_map<std::string, double>::unordered_map;
19   // tuples are : <unit, value for unit, base (2 or 10), true if abbreviated>
20   explicit unit_scale(std::initializer_list<std::tuple<const std::string, double, int, bool>> generators);
21 };
22
23 unit_scale::unit_scale(std::initializer_list<std::tuple<const std::string, double, int, bool>> generators)
24 {
25   for (const auto& gen : generators) {
26     const std::string& unit = std::get<0>(gen);
27     double value            = std::get<1>(gen);
28     const int base          = std::get<2>(gen);
29     const bool abbrev       = std::get<3>(gen);
30     double mult;
31     std::vector<std::string> prefixes;
32     switch (base) {
33       case 2:
34         mult     = 1024.0;
35         prefixes = abbrev ? std::vector<std::string>{"Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi", "Yi"}
36                           : std::vector<std::string>{"kibi", "mebi", "gibi", "tebi", "pebi", "exbi", "zebi", "yobi"};
37         break;
38       case 10:
39         mult     = 1000.0;
40         prefixes = abbrev ? std::vector<std::string>{"k", "M", "G", "T", "P", "E", "Z", "Y"}
41                           : std::vector<std::string>{"kilo", "mega", "giga", "tera", "peta", "exa", "zeta", "yotta"};
42         break;
43       default:
44         THROW_IMPOSSIBLE;
45     }
46     emplace(unit, value);
47     for (const auto& prefix : prefixes) {
48       value *= mult;
49       emplace(prefix + unit, value);
50     }
51   }
52 }
53
54 /* Note: no warning is issued for unit-less values when `name' is empty. */
55 static double surf_parse_get_value_with_unit(const std::string& filename, int lineno, const char* string,
56                                              const unit_scale& units, const char* entity_kind, const std::string& name,
57                                              const char* error_msg, const char* default_unit)
58 {
59   char* endptr;
60   errno           = 0;
61   double res      = strtod(string, &endptr);
62   const char* ptr = endptr; // for const-correctness
63   if (errno == ERANGE)
64     throw simgrid::ParseError(filename, lineno, std::string("value out of range: ") + string);
65   if (ptr == string)
66     throw simgrid::ParseError(filename, lineno, std::string("cannot parse number:") + string);
67   if (ptr[0] == '\0') {
68     // Ok, 0 can be unit-less
69     if (res != 0 && not name.empty())
70       XBT_WARN("Deprecated unit-less value '%s' for %s %s. %s", string, entity_kind, name.c_str(), error_msg);
71     ptr = default_unit;
72   }
73   auto u = units.find(ptr);
74   if (u == units.end())
75     throw simgrid::ParseError(filename, lineno, std::string("unknown unit: ") + ptr);
76   return res * u->second;
77 }
78
79 double xbt_parse_get_time(const std::string& filename, int lineno, const char* string, const char* entity_kind,
80                           const std::string& name)
81 {
82   static const unit_scale units{std::make_pair("w", 7 * 24 * 60 * 60),
83                                 std::make_pair("d", 24 * 60 * 60),
84                                 std::make_pair("h", 60 * 60),
85                                 std::make_pair("m", 60),
86                                 std::make_pair("s", 1.0),
87                                 std::make_pair("ms", 1e-3),
88                                 std::make_pair("us", 1e-6),
89                                 std::make_pair("ns", 1e-9),
90                                 std::make_pair("ps", 1e-12)};
91   return surf_parse_get_value_with_unit(filename, lineno, string, units, entity_kind, name,
92                                         "Append 's' to your time to get seconds", "s");
93 }
94
95 double surf_parse_get_size(const std::string& filename, int lineno, const char* string, const char* entity_kind,
96                            const std::string& name)
97 {
98   static const unit_scale units{std::make_tuple("b", 0.125, 2, true), std::make_tuple("b", 0.125, 10, true),
99                                 std::make_tuple("B", 1.0, 2, true), std::make_tuple("B", 1.0, 10, true)};
100   return surf_parse_get_value_with_unit(filename, lineno, string, units, entity_kind, name,
101                                         "Append 'B' to get bytes (or 'b' for bits but 1B = 8b).", "B");
102 }
103
104 double xbt_parse_get_bandwidth(const std::string& filename, int lineno, const char* string, const char* entity_kind,
105                                const std::string& name)
106 {
107   static const unit_scale units{std::make_tuple("bps", 0.125, 2, true), std::make_tuple("bps", 0.125, 10, true),
108                                 std::make_tuple("Bps", 1.0, 2, true), std::make_tuple("Bps", 1.0, 10, true)};
109   return surf_parse_get_value_with_unit(filename, lineno, string, units, entity_kind, name,
110                                         "Append 'Bps' to get bytes per second (or 'bps' for bits but 1Bps = 8bps)",
111                                         "Bps");
112 }
113
114 std::vector<double> xbt_parse_get_bandwidths(const std::string& filename, int lineno, const char* string,
115                                              const char* entity_kind, const std::string& name)
116 {
117   static const unit_scale units{std::make_tuple("bps", 0.125, 2, true), std::make_tuple("bps", 0.125, 10, true),
118                                 std::make_tuple("Bps", 1.0, 2, true), std::make_tuple("Bps", 1.0, 10, true)};
119
120   std::vector<double> bandwidths;
121   std::vector<std::string> tokens;
122   boost::split(tokens, string, boost::is_any_of(";,"));
123   for (auto token : tokens) {
124     bandwidths.push_back(surf_parse_get_value_with_unit(
125         filename, lineno, token.c_str(), units, entity_kind, name,
126         "Append 'Bps' to get bytes per second (or 'bps' for bits but 1Bps = 8bps)", "Bps"));
127   }
128
129   return bandwidths;
130 }
131
132 double xbt_parse_get_speed(const std::string& filename, int lineno, const char* string, const char* entity_kind,
133                            const std::string& name)
134 {
135   static const unit_scale units{std::make_tuple("f", 1.0, 10, true), std::make_tuple("flops", 1.0, 10, false)};
136   return surf_parse_get_value_with_unit(filename, lineno, string, units, entity_kind, name,
137                                         "Append 'f' or 'flops' to your speed to get flop per second", "f");
138 }
139
140 std::vector<double> xbt_parse_get_all_speeds(const std::string& filename, int lineno, char* speeds,
141                                              const char* entity_kind, const std::string& id)
142 {
143   std::vector<double> speed_per_pstate;
144
145   if (strchr(speeds, ',') == nullptr) {
146     double speed = xbt_parse_get_speed(filename, lineno, speeds, entity_kind, id);
147     speed_per_pstate.push_back(speed);
148   } else {
149     std::vector<std::string> pstate_list;
150     boost::split(pstate_list, speeds, boost::is_any_of(","));
151     for (auto speed_str : pstate_list) {
152       boost::trim(speed_str);
153       double speed = xbt_parse_get_speed(filename, lineno, speed_str.c_str(), entity_kind, id);
154       speed_per_pstate.push_back(speed);
155       XBT_DEBUG("Speed value: %f", speed);
156     }
157   }
158   return speed_per_pstate;
159 }