|  | /* | 
|  | * Copyright (C) 2019 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/clock_tracker.h" | 
|  |  | 
|  | #include <algorithm> | 
|  |  | 
|  | #include "perfetto/base/logging.h" | 
|  | #include "src/trace_processor/trace_processor_context.h" | 
|  | #include "src/trace_processor/trace_storage.h" | 
|  |  | 
|  | namespace perfetto { | 
|  | namespace trace_processor { | 
|  |  | 
|  | ClockTracker::ClockTracker(TraceProcessorContext* ctx) : context_(ctx) {} | 
|  | ClockTracker::~ClockTracker() = default; | 
|  |  | 
|  | void ClockTracker::SyncClocks(ClockDomain domain, | 
|  | int64_t clock_time_ns, | 
|  | int64_t trace_time_ns) { | 
|  | ClockSnapshotVector& snapshots = clocks_[domain]; | 
|  | if (!snapshots.empty()) { | 
|  | // The trace clock (typically CLOCK_BOOTTIME) must be monotonic. | 
|  | if (trace_time_ns <= snapshots.back().trace_time_ns) { | 
|  | PERFETTO_ELOG("Trace time in clock snapshot is moving backwards"); | 
|  | context_->storage->IncrementStats(stats::clock_snapshot_not_monotonic); | 
|  | return; | 
|  | } | 
|  | if (clock_time_ns <= snapshots.back().clock_time_ns) { | 
|  | if (domain == ClockDomain::kMonotonic) { | 
|  | PERFETTO_ELOG("CLOCK_MONOTONIC in clock snapshot is moving backwards"); | 
|  | context_->storage->IncrementStats(stats::clock_snapshot_not_monotonic); | 
|  | return; | 
|  | } | 
|  | // This can happen in other clocks, for instance CLOCK_REALTIME if | 
|  | // adjusting the timezone or during daylight saving. In this case the most | 
|  | // reasonable thing we can do is obliterating all the past snapshots. | 
|  | while (!snapshots.empty() && | 
|  | snapshots.back().clock_time_ns >= clock_time_ns) { | 
|  | snapshots.pop_back(); | 
|  | } | 
|  | } | 
|  | } | 
|  | snapshots.emplace_back(ClockSnapshot{clock_time_ns, trace_time_ns}); | 
|  | } | 
|  |  | 
|  | base::Optional<int64_t> ClockTracker::ToTraceTime(ClockDomain domain, | 
|  | int64_t clock_time_ns) { | 
|  | ClockSnapshotVector& snapshots = clocks_[domain]; | 
|  | if (snapshots.empty()) { | 
|  | context_->storage->IncrementStats(stats::clock_sync_failure); | 
|  | return base::nullopt; | 
|  | } | 
|  | static auto comparator = [](int64_t lhs, const ClockSnapshot& rhs) { | 
|  | return lhs < rhs.clock_time_ns; | 
|  | }; | 
|  | auto it = std::upper_bound(snapshots.begin(), snapshots.end(), clock_time_ns, | 
|  | comparator); | 
|  | if (it != snapshots.begin()) | 
|  | it--; | 
|  | return it->trace_time_ns + (clock_time_ns - it->clock_time_ns); | 
|  | } | 
|  |  | 
|  | }  // namespace trace_processor | 
|  | }  // namespace perfetto |