aboutsummaryrefslogtreecommitdiff
path: root/src/trace_processor/importers/json/json_utils.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/trace_processor/importers/json/json_utils.cc')
-rw-r--r--src/trace_processor/importers/json/json_utils.cc40
1 files changed, 30 insertions, 10 deletions
diff --git a/src/trace_processor/importers/json/json_utils.cc b/src/trace_processor/importers/json/json_utils.cc
index be9492b61..d2e1c1850 100644
--- a/src/trace_processor/importers/json/json_utils.cc
+++ b/src/trace_processor/importers/json/json_utils.cc
@@ -62,17 +62,37 @@ std::optional<int64_t> CoerceToTs(const std::string& s) {
PERFETTO_DCHECK(IsJsonSupported());
#if PERFETTO_BUILDFLAG(PERFETTO_TP_JSON)
- size_t lhs_end = std::min<size_t>(s.find('.'), s.size());
- size_t rhs_start = std::min<size_t>(lhs_end + 1, s.size());
- std::optional<int64_t> lhs = base::StringToInt64(s.substr(0, lhs_end));
- std::optional<double> rhs =
- base::StringToDouble("0." + s.substr(rhs_start, std::string::npos));
- if ((!lhs.has_value() && lhs_end > 0) ||
- (!rhs.has_value() && rhs_start < s.size())) {
- return std::nullopt;
+ // 's' is formatted as a JSON Number, in microseconds
+ // goal: reformat 's' to be as an int, in nanoseconds
+ std::string s_as_ns = s;
+
+ // detect and remove scientific notation's exponents
+ int32_t exp_shift = 0;
+ if (size_t exp_start = s.find_first_of("eE");
+ exp_start != std::string::npos) {
+ const std::string exp_s = s.substr(exp_start + 1, s.size());
+ const std::optional<int32_t> exp = base::StringToInt32(exp_s);
+ if (!exp.has_value()) {
+ return std::nullopt;
+ }
+ s_as_ns.erase(exp_start);
+ exp_shift = *exp;
}
- return lhs.value_or(0) * 1000 +
- static_cast<int64_t>(rhs.value_or(0) * 1000.0);
+
+ // detect and remove decimal separator
+ size_t int_size = s_as_ns.size();
+ if (size_t frac_start = s.find('.'); frac_start != std::string::npos) {
+ s_as_ns.erase(frac_start, 1);
+ int_size = frac_start;
+ }
+
+ // expand or shrink to the new size
+ constexpr int us_to_ns_shift = 3;
+ const size_t s_as_ns_size = size_t(
+ std::max<ptrdiff_t>(1, ptrdiff_t(int_size) + exp_shift + us_to_ns_shift));
+ s_as_ns.resize(s_as_ns_size, '0'); // pads or truncates
+
+ return base::StringToInt64(s_as_ns);
#else
perfetto::base::ignore_result(s);
return std::nullopt;