1 /*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "src/trace_processor/clock_tracker.h"
18
19 #include <algorithm>
20
21 #include "perfetto/base/logging.h"
22 #include "src/trace_processor/trace_processor_context.h"
23 #include "src/trace_processor/trace_storage.h"
24
25 namespace perfetto {
26 namespace trace_processor {
27
ClockTracker(TraceProcessorContext * ctx)28 ClockTracker::ClockTracker(TraceProcessorContext* ctx) : context_(ctx) {}
29 ClockTracker::~ClockTracker() = default;
30
SyncClocks(ClockDomain domain,int64_t clock_time_ns,int64_t trace_time_ns)31 void ClockTracker::SyncClocks(ClockDomain domain,
32 int64_t clock_time_ns,
33 int64_t trace_time_ns) {
34 ClockSnapshotVector& snapshots = clocks_[domain];
35 if (!snapshots.empty()) {
36 // The trace clock (typically CLOCK_BOOTTIME) must be monotonic.
37 if (trace_time_ns <= snapshots.back().trace_time_ns) {
38 PERFETTO_ELOG("Trace time in clock snapshot is moving backwards");
39 context_->storage->IncrementStats(stats::clock_snapshot_not_monotonic);
40 return;
41 }
42 if (clock_time_ns <= snapshots.back().clock_time_ns) {
43 if (domain == ClockDomain::kMonotonic) {
44 PERFETTO_ELOG("CLOCK_MONOTONIC in clock snapshot is moving backwards");
45 context_->storage->IncrementStats(stats::clock_snapshot_not_monotonic);
46 return;
47 }
48 // This can happen in other clocks, for instance CLOCK_REALTIME if
49 // adjusting the timezone or during daylight saving. In this case the most
50 // reasonable thing we can do is obliterating all the past snapshots.
51 while (!snapshots.empty() &&
52 snapshots.back().clock_time_ns >= clock_time_ns) {
53 snapshots.pop_back();
54 }
55 }
56 }
57 snapshots.emplace_back(ClockSnapshot{clock_time_ns, trace_time_ns});
58 }
59
ToTraceTime(ClockDomain domain,int64_t clock_time_ns)60 base::Optional<int64_t> ClockTracker::ToTraceTime(ClockDomain domain,
61 int64_t clock_time_ns) {
62 ClockSnapshotVector& snapshots = clocks_[domain];
63 if (snapshots.empty()) {
64 context_->storage->IncrementStats(stats::clock_sync_failure);
65 return base::nullopt;
66 }
67 static auto comparator = [](int64_t lhs, const ClockSnapshot& rhs) {
68 return lhs < rhs.clock_time_ns;
69 };
70 auto it = std::upper_bound(snapshots.begin(), snapshots.end(), clock_time_ns,
71 comparator);
72 if (it != snapshots.begin())
73 it--;
74 return it->trace_time_ns + (clock_time_ns - it->clock_time_ns);
75 }
76
77 } // namespace trace_processor
78 } // namespace perfetto
79