Logo AND Algorithmique Numérique Distribuée

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