Logo AND Algorithmique Numérique Distribuée

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