diff options
Diffstat (limited to 'src/trace_processor/importers/json/json_utils.cc')
-rw-r--r-- | src/trace_processor/importers/json/json_utils.cc | 40 |
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; |