1 /* Copyright (c) 2007-2021. The SimGrid Team. All rights reserved. */
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. */
6 #include "simgrid/Exception.hpp"
10 #include "xbt/parse_units.hpp"
12 #include <boost/algorithm/string.hpp>
13 #include <boost/algorithm/string/classification.hpp>
14 #include <boost/algorithm/string/split.hpp>
16 #include <unordered_map>
19 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(parse, xbt, "Parsing functions");
21 class unit_scale : public std::unordered_map<std::string, double> {
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);
28 unit_scale::unit_scale(std::initializer_list<std::tuple<const std::string, double, int, bool>> generators)
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);
36 std::vector<std::string> prefixes;
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"};
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"};
52 for (const auto& prefix : prefixes) {
54 emplace(prefix + unit, value);
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)
66 double res = strtod(string.c_str(), &endptr);
67 const char* ptr = endptr; // for const-correctness
69 throw simgrid::ParseError(filename, lineno, std::string("value out of range: ") + string);
71 throw simgrid::ParseError(filename, lineno, std::string("cannot parse number:") + string);
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);
78 auto u = units.find(ptr);
80 throw simgrid::ParseError(filename, lineno, std::string("unknown unit: ") + ptr);
81 return res * u->second;
84 double xbt_parse_get_time(const std::string& filename, int lineno, const std::string& string,
85 const std::string& entity_kind)
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");
100 double xbt_parse_get_size(const std::string& filename, int lineno, const std::string& string,
101 const std::string& entity_kind)
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");
109 double xbt_parse_get_bandwidth(const std::string& filename, int lineno, const std::string& string,
110 const std::string& entity_kind)
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)",
119 std::vector<double> xbt_parse_get_bandwidths(const std::string& filename, int lineno, const std::string& string,
120 const std::string& entity_kind)
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)};
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"));
137 double xbt_parse_get_speed(const std::string& filename, int lineno, const std::string& string,
138 const std::string& entity_kind)
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");
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)
148 std::vector<double> speed_per_pstate;
149 std::vector<std::string> pstate_list;
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);
159 return speed_per_pstate;