/* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "src/trace_processor/importers/common/clock_converter.h" #include #include #include #include #include #include "perfetto/base/logging.h" #include "perfetto/ext/base/hash.h" #include "src/trace_processor/storage/trace_storage.h" #include "src/trace_processor/types/trace_processor_context.h" #include "protos/perfetto/common/builtin_clock.pbzero.h" #include "protos/perfetto/trace/clock_snapshot.pbzero.h" namespace perfetto { namespace trace_processor { ClockConverter::ClockConverter(TraceProcessorContext* context) : context_(context) {} void ClockConverter::MaybeInitialize() { if (is_initialized) return; is_initialized = true; timelines_.Insert(kRealClock, {}); timelines_.Insert(kMonoClock, {}); for (auto it = context_->storage->clock_snapshot_table().IterateRows(); it; ++it) { if (it.clock_id() == kRealClock || it.clock_id() == kMonoClock) timelines_.Find(it.clock_id())->emplace(it.ts(), it.clock_value()); } } base::StatusOr ClockConverter::FromTraceTime( ClockId clock_id, Timestamp ts) { MaybeInitialize(); Timeline* timeline = timelines_.Find(clock_id); if (!timeline) { return base::ErrStatus( "Provided clock has not been found in the converter " "clocks."); } if (timeline->empty()) { return base::ErrStatus("Target clock is not in the trace."); } auto next_snapshot = timeline->lower_bound(ts); // If lower bound was not found, it means that the ts was higher then the last // one. If that's the case we look for thhe last element and return clock // value for this + offset. if (next_snapshot == timeline->end()) { next_snapshot--; return next_snapshot->second + ts - next_snapshot->first; } // If there is a snapshot with this ts or lower bound is the first snapshot, // we have no other option then to return the clock value for this snapshot. if (next_snapshot == timeline->begin() || next_snapshot->first == ts) return next_snapshot->second; auto prev_snapshot = next_snapshot; prev_snapshot--; // The most truthful way to calculate the clock value is to use this formula, // as there is no reason to assume that the clock is monotonistic. This // prevents us from going back in time. return std::min(prev_snapshot->second + ts - prev_snapshot->first, next_snapshot->second); } std::string ClockConverter::TimeToStr(Timestamp ts) { constexpr int64_t one_second_in_ns = 1LL * 1000LL * 1000LL * 1000LL; int64_t s = ts / one_second_in_ns; int64_t ns = ts % one_second_in_ns; time_t time_s = static_cast(s); struct tm* time_tm = gmtime(&time_s); int seconds = time_tm->tm_sec; int minutes = time_tm->tm_min; int hours = time_tm->tm_hour; int day = time_tm->tm_mday; int month = time_tm->tm_mon + 1; int year = time_tm->tm_year + 1900; base::StackString<64> buf("%04d-%02d-%02dT%02d:%02d:%02d.%09" PRId64, year, month, day, hours, minutes, seconds, ns); return buf.ToStdString(); } } // namespace trace_processor } // namespace perfetto