1 /* Copyright (c) 2007-2022. 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 (auto [unit, value, base, abbrev] : generators) {
32 std::vector<std::string> prefixes;
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"};
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"};
48 for (const auto& prefix : prefixes) {
50 emplace(prefix + unit, value);
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)
62 double res = strtod(string.c_str(), &endptr);
63 const char* ptr = endptr; // for const-correctness
65 throw simgrid::ParseError(filename, lineno, std::string("value out of range: ") + string);
67 throw simgrid::ParseError(filename, lineno, std::string("cannot parse number:") + string);
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);
74 auto u = units.find(ptr);
76 throw simgrid::ParseError(filename, lineno, std::string("unknown unit: ") + ptr);
77 return res * u->second;
80 double xbt_parse_get_time(const std::string& filename, int lineno, const std::string& string,
81 const std::string& entity_kind)
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");
96 double xbt_parse_get_size(const std::string& filename, int lineno, const std::string& string,
97 const std::string& entity_kind)
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");
105 double xbt_parse_get_bandwidth(const std::string& filename, int lineno, const std::string& string,
106 const std::string& entity_kind)
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)",
115 std::vector<double> xbt_parse_get_bandwidths(const std::string& filename, int lineno, const std::string& string,
116 const std::string& entity_kind)
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)};
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"));
133 double xbt_parse_get_speed(const std::string& filename, int lineno, const std::string& string,
134 const std::string& entity_kind)
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");
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)
144 std::vector<double> speed_per_pstate;
145 std::vector<std::string> pstate_list;
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);
155 return speed_per_pstate;