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/importers/common/clock_tracker.h"
18
19 #include <optional>
20 #include <random>
21
22 #include "src/trace_processor/importers/common/metadata_tracker.h"
23 #include "src/trace_processor/storage/trace_storage.h"
24 #include "src/trace_processor/types/trace_processor_context.h"
25 #include "test/gtest_and_gmock.h"
26
27 #include "protos/perfetto/common/builtin_clock.pbzero.h"
28 #include "protos/perfetto/trace/clock_snapshot.pbzero.h"
29
30 namespace perfetto {
31 namespace trace_processor {
32
33 class ClockTrackerTest : public ::testing::Test {
34 public:
ClockTrackerTest()35 ClockTrackerTest() {
36 context_.storage.reset(new TraceStorage());
37 context_.metadata_tracker.reset(
38 new MetadataTracker(context_.storage.get()));
39 }
40
41 // using ClockId = uint64_t;
42 TraceProcessorContext context_;
43 ClockTracker ct_{&context_};
Convert(ClockTracker::ClockId src_clock_id,int64_t src_timestamp,ClockTracker::ClockId target_clock_id)44 base::StatusOr<int64_t> Convert(ClockTracker::ClockId src_clock_id,
45 int64_t src_timestamp,
46 ClockTracker::ClockId target_clock_id) {
47 return ct_.Convert(src_clock_id, src_timestamp, target_clock_id);
48 }
49 };
50
51 namespace {
52
53 using ::testing::NiceMock;
54 using Clock = protos::pbzero::ClockSnapshot::Clock;
55
56 constexpr auto REALTIME = protos::pbzero::BUILTIN_CLOCK_REALTIME;
57 constexpr auto BOOTTIME = protos::pbzero::BUILTIN_CLOCK_BOOTTIME;
58 constexpr auto MONOTONIC = protos::pbzero::BUILTIN_CLOCK_MONOTONIC;
59 constexpr auto MONOTONIC_COARSE =
60 protos::pbzero::BUILTIN_CLOCK_MONOTONIC_COARSE;
61 constexpr auto MONOTONIC_RAW = protos::pbzero::BUILTIN_CLOCK_MONOTONIC_RAW;
62
TEST_F(ClockTrackerTest,ClockDomainConversions)63 TEST_F(ClockTrackerTest, ClockDomainConversions) {
64 EXPECT_FALSE(ct_.ToTraceTime(REALTIME, 0).ok());
65
66 ct_.AddSnapshot({{REALTIME, 10}, {BOOTTIME, 10010}});
67 ct_.AddSnapshot({{REALTIME, 20}, {BOOTTIME, 20220}});
68 ct_.AddSnapshot({{REALTIME, 30}, {BOOTTIME, 30030}});
69 ct_.AddSnapshot({{MONOTONIC, 1000}, {BOOTTIME, 100000}});
70
71 EXPECT_EQ(*ct_.ToTraceTime(REALTIME, 0), 10000);
72 EXPECT_EQ(*ct_.ToTraceTime(REALTIME, 1), 10001);
73 EXPECT_EQ(*ct_.ToTraceTime(REALTIME, 9), 10009);
74 EXPECT_EQ(*ct_.ToTraceTime(REALTIME, 10), 10010);
75 EXPECT_EQ(*ct_.ToTraceTime(REALTIME, 11), 10011);
76 EXPECT_EQ(*ct_.ToTraceTime(REALTIME, 19), 10019);
77 EXPECT_EQ(*ct_.ToTraceTime(REALTIME, 20), 20220);
78 EXPECT_EQ(*ct_.ToTraceTime(REALTIME, 21), 20221);
79 EXPECT_EQ(*ct_.ToTraceTime(REALTIME, 29), 20229);
80 EXPECT_EQ(*ct_.ToTraceTime(REALTIME, 30), 30030);
81 EXPECT_EQ(*ct_.ToTraceTime(REALTIME, 40), 30040);
82
83 EXPECT_EQ(*ct_.ToTraceTime(MONOTONIC, 0), 100000 - 1000);
84 EXPECT_EQ(*ct_.ToTraceTime(MONOTONIC, 999), 100000 - 1);
85 EXPECT_EQ(*ct_.ToTraceTime(MONOTONIC, 1000), 100000);
86 EXPECT_EQ(*ct_.ToTraceTime(MONOTONIC, 1e6),
87 static_cast<int64_t>(100000 - 1000 + 1e6));
88 }
89
TEST_F(ClockTrackerTest,ToTraceTimeFromSnapshot)90 TEST_F(ClockTrackerTest, ToTraceTimeFromSnapshot) {
91 EXPECT_FALSE(ct_.ToTraceTime(REALTIME, 0).ok());
92
93 EXPECT_EQ(*ct_.ToTraceTimeFromSnapshot({{REALTIME, 10}, {BOOTTIME, 10010}}),
94 10010);
95 EXPECT_EQ(ct_.ToTraceTimeFromSnapshot({{MONOTONIC, 10}, {REALTIME, 10010}}),
96 std::nullopt);
97 }
98
99 // When a clock moves backwards conversions *from* that clock are forbidden
100 // but conversions *to* that clock should still work.
101 // Think to the case of REALTIME going backwards from 3AM to 2AM during DST day.
102 // You can't convert 2.10AM REALTIME to BOOTTIME because there are two possible
103 // answers, but you can still unambiguosly convert BOOTTIME into REALTIME.
TEST_F(ClockTrackerTest,RealTimeClockMovingBackwards)104 TEST_F(ClockTrackerTest, RealTimeClockMovingBackwards) {
105 ct_.AddSnapshot({{BOOTTIME, 10010}, {REALTIME, 10}});
106
107 // At this point conversions are still possible in both ways because we
108 // haven't broken monotonicity yet.
109 EXPECT_EQ(*ct_.ToTraceTime(REALTIME, 11), 10011);
110
111 ct_.AddSnapshot({{BOOTTIME, 10020}, {REALTIME, 20}});
112 ct_.AddSnapshot({{BOOTTIME, 30040}, {REALTIME, 40}});
113 ct_.AddSnapshot({{BOOTTIME, 40030}, {REALTIME, 30}});
114
115 // Now only BOOTIME -> REALTIME conversion should be possible.
116 EXPECT_FALSE(ct_.ToTraceTime(REALTIME, 11).ok());
117 EXPECT_EQ(*Convert(BOOTTIME, 10011, REALTIME), 11);
118 EXPECT_EQ(*Convert(BOOTTIME, 10029, REALTIME), 29);
119 EXPECT_EQ(*Convert(BOOTTIME, 40030, REALTIME), 30);
120 EXPECT_EQ(*Convert(BOOTTIME, 40040, REALTIME), 40);
121
122 ct_.AddSnapshot({{BOOTTIME, 50000}, {REALTIME, 50}});
123 EXPECT_EQ(*Convert(BOOTTIME, 50005, REALTIME), 55);
124
125 ct_.AddSnapshot({{BOOTTIME, 60020}, {REALTIME, 20}});
126 EXPECT_EQ(*Convert(BOOTTIME, 60020, REALTIME), 20);
127 }
128
129 // Simulate the following scenario:
130 // MONOTONIC = MONOTONIC_COARSE + 10
131 // BOOTTIME = MONOTONIC + 1000 (until T=200)
132 // BOOTTIME = MONOTONIC + 2000 (from T=200)
133 // Then resolve MONOTONIC_COARSE. This requires a two-level resolution:
134 // MONOTONIC_COARSE -> MONOTONIC -> BOOTTIME.
TEST_F(ClockTrackerTest,ChainedResolutionSimple)135 TEST_F(ClockTrackerTest, ChainedResolutionSimple) {
136 ct_.AddSnapshot({{MONOTONIC_COARSE, 1}, {MONOTONIC, 11}});
137 ct_.AddSnapshot({{MONOTONIC, 100}, {BOOTTIME, 1100}});
138 ct_.AddSnapshot({{MONOTONIC, 200}, {BOOTTIME, 2200}});
139
140 // MONOTONIC_COARSE@100 == MONOTONIC@110 == BOOTTIME@1100.
141 EXPECT_EQ(*ct_.ToTraceTime(MONOTONIC, 110), 1110);
142 EXPECT_EQ(*ct_.ToTraceTime(MONOTONIC_COARSE, 100), 100 + 10 + 1000);
143 EXPECT_EQ(*ct_.ToTraceTime(MONOTONIC_COARSE, 202), 202 + 10 + 2000);
144 }
145
TEST_F(ClockTrackerTest,ChainedResolutionHard)146 TEST_F(ClockTrackerTest, ChainedResolutionHard) {
147 // MONOTONIC_COARSE = MONOTONIC_RAW - 1.
148 ct_.AddSnapshot({{MONOTONIC_RAW, 10}, {MONOTONIC_COARSE, 9}});
149
150 // MONOTONIC = MONOTONIC_COARSE - 50.
151 ct_.AddSnapshot({{MONOTONIC_COARSE, 100}, {MONOTONIC, 50}});
152
153 // BOOTTIME = MONOTONIC + 1000 until T=100 (see below).
154 ct_.AddSnapshot({{MONOTONIC, 1}, {BOOTTIME, 1001}, {REALTIME, 10001}});
155
156 // BOOTTIME = MONOTONIC + 2000 from T=100.
157 // At the same time, REALTIME goes backwards.
158 ct_.AddSnapshot({{MONOTONIC, 101}, {BOOTTIME, 2101}, {REALTIME, 9101}});
159
160 // 1-hop conversions.
161 EXPECT_EQ(*Convert(MONOTONIC_RAW, 2, MONOTONIC_COARSE), 1);
162 EXPECT_EQ(*Convert(MONOTONIC_COARSE, 1, MONOTONIC_RAW), 2);
163 EXPECT_EQ(*Convert(MONOTONIC_RAW, 100001, MONOTONIC_COARSE), 100000);
164 EXPECT_EQ(*Convert(MONOTONIC_COARSE, 100000, MONOTONIC_RAW), 100001);
165
166 // 2-hop conversions (MONOTONIC_RAW <-> MONOTONIC_COARSE <-> MONOTONIC).
167 // From above, MONOTONIC = (MONOTONIC_RAW - 1) - 50.
168 EXPECT_EQ(*Convert(MONOTONIC_RAW, 53, MONOTONIC), 53 - 1 - 50);
169 EXPECT_EQ(*Convert(MONOTONIC, 2, MONOTONIC_RAW), 2 + 1 + 50);
170
171 // 3-hop conversions (as above + BOOTTIME)
172 EXPECT_EQ(*Convert(MONOTONIC_RAW, 53, BOOTTIME), 53 - 1 - 50 + 1000);
173 EXPECT_EQ(*Convert(BOOTTIME, 1002, MONOTONIC_RAW), 1002 - 1000 + 1 + 50);
174
175 EXPECT_EQ(*Convert(MONOTONIC_RAW, 753, BOOTTIME), 753 - 1 - 50 + 2000);
176 EXPECT_EQ(*Convert(BOOTTIME, 2702, MONOTONIC_RAW), 2702 - 2000 + 1 + 50);
177
178 // 3-hop conversion to REALTIME, one way only (REALTIME goes backwards).
179 EXPECT_EQ(*Convert(MONOTONIC_RAW, 53, REALTIME), 53 - 1 - 50 + 10000);
180 EXPECT_EQ(*Convert(MONOTONIC_RAW, 753, REALTIME), 753 - 1 - 50 + 9000);
181 }
182
183 // Regression test for b/158182858. When taking two snapshots back-to-back,
184 // MONOTONIC_COARSE might be stuck to the last value. We should still be able
185 // to convert both ways in this case.
TEST_F(ClockTrackerTest,NonStrictlyMonotonic)186 TEST_F(ClockTrackerTest, NonStrictlyMonotonic) {
187 ct_.AddSnapshot({{BOOTTIME, 101}, {MONOTONIC, 51}, {MONOTONIC_COARSE, 50}});
188 ct_.AddSnapshot({{BOOTTIME, 105}, {MONOTONIC, 55}, {MONOTONIC_COARSE, 50}});
189
190 // This last snapshot is deliberately identical to the previous one. This
191 // is to simulate the case of taking two snapshots so close to each other
192 // that all clocks are identical.
193 ct_.AddSnapshot({{BOOTTIME, 105}, {MONOTONIC, 55}, {MONOTONIC_COARSE, 50}});
194
195 EXPECT_EQ(*Convert(MONOTONIC_COARSE, 49, MONOTONIC), 50);
196 EXPECT_EQ(*Convert(MONOTONIC_COARSE, 50, MONOTONIC), 55);
197 EXPECT_EQ(*Convert(MONOTONIC_COARSE, 51, MONOTONIC), 56);
198
199 EXPECT_EQ(*Convert(MONOTONIC_COARSE, 40, BOOTTIME), 91);
200 EXPECT_EQ(*Convert(MONOTONIC_COARSE, 50, BOOTTIME), 105);
201 EXPECT_EQ(*Convert(MONOTONIC_COARSE, 55, BOOTTIME), 110);
202
203 EXPECT_EQ(*Convert(BOOTTIME, 91, MONOTONIC_COARSE), 40);
204 EXPECT_EQ(*Convert(BOOTTIME, 105, MONOTONIC_COARSE), 50);
205 EXPECT_EQ(*Convert(BOOTTIME, 110, MONOTONIC_COARSE), 55);
206 }
207
TEST_F(ClockTrackerTest,SequenceScopedClocks)208 TEST_F(ClockTrackerTest, SequenceScopedClocks) {
209 ct_.AddSnapshot({{MONOTONIC, 1000}, {BOOTTIME, 100000}});
210
211 ClockTracker::ClockId c64_1 = ct_.SeqenceToGlobalClock(1, 64);
212 ClockTracker::ClockId c65_1 = ct_.SeqenceToGlobalClock(1, 65);
213 ClockTracker::ClockId c66_1 = ct_.SeqenceToGlobalClock(1, 66);
214 ClockTracker::ClockId c66_2 = ct_.SeqenceToGlobalClock(2, 64);
215
216 ct_.AddSnapshot(
217 {{MONOTONIC, 10000},
218 {c64_1, 100000},
219 {c65_1, 100, /*unit_multiplier_ns=*/1000, /*is_incremental=*/false},
220 {c66_1, 10, /*unit_multiplier_ns=*/1000, /*is_incremental=*/true}});
221
222 // c64_1 is non-incremental and in nanos.
223 EXPECT_EQ(*Convert(c64_1, 150000, MONOTONIC), 60000);
224 EXPECT_EQ(*Convert(c64_1, 150000, BOOTTIME), 159000);
225 EXPECT_EQ(*ct_.ToTraceTime(c64_1, 150000), 159000);
226
227 // c65_1 is non-incremental and in micros.
228 EXPECT_EQ(*Convert(c65_1, 150, MONOTONIC), 60000);
229 EXPECT_EQ(*Convert(c65_1, 150, BOOTTIME), 159000);
230 EXPECT_EQ(*ct_.ToTraceTime(c65_1, 150), 159000);
231
232 // c66_1 is incremental and in micros.
233 EXPECT_EQ(*Convert(c66_1, 1 /* abs 11 */, MONOTONIC), 11000);
234 EXPECT_EQ(*Convert(c66_1, 1 /* abs 12 */, MONOTONIC), 12000);
235 EXPECT_EQ(*Convert(c66_1, 1 /* abs 13 */, BOOTTIME), 112000);
236 EXPECT_EQ(*ct_.ToTraceTime(c66_1, 2 /* abs 15 */), 114000);
237
238 ct_.AddSnapshot(
239 {{MONOTONIC, 20000},
240 {c66_1, 20, /*unit_multiplier_ns=*/1000, /*incremental=*/true}});
241 ct_.AddSnapshot(
242 {{MONOTONIC, 20000},
243 {c66_2, 20, /*unit_multiplier_ns=*/1000, /*incremental=*/true}});
244
245 // c66_1 and c66_2 are both incremental and in micros, but shouldn't affect
246 // each other.
247 EXPECT_EQ(*Convert(c66_1, 1 /* abs 21 */, MONOTONIC), 21000);
248 EXPECT_EQ(*Convert(c66_2, 2 /* abs 22 */, MONOTONIC), 22000);
249 EXPECT_EQ(*Convert(c66_1, 1 /* abs 22 */, MONOTONIC), 22000);
250 EXPECT_EQ(*Convert(c66_2, 2 /* abs 24 */, MONOTONIC), 24000);
251 EXPECT_EQ(*Convert(c66_1, 1 /* abs 23 */, BOOTTIME), 122000);
252 EXPECT_EQ(*Convert(c66_2, 2 /* abs 26 */, BOOTTIME), 125000);
253 EXPECT_EQ(*ct_.ToTraceTime(c66_1, 2 /* abs 25 */), 124000);
254 EXPECT_EQ(*ct_.ToTraceTime(c66_2, 4 /* abs 30 */), 129000);
255 }
256
257 // Tests that the cache doesn't affect the results of Convert() in unexpected
258 // ways.
TEST_F(ClockTrackerTest,CacheDoesntAffectResults)259 TEST_F(ClockTrackerTest, CacheDoesntAffectResults) {
260 std::minstd_rand rnd;
261 int last_mono = 0;
262 int last_boot = 0;
263 int last_raw = 0;
264 static const int increments[] = {1, 2, 10};
265 for (int i = 0; i < 1000; i++) {
266 last_mono += increments[rnd() % base::ArraySize(increments)];
267 last_boot += increments[rnd() % base::ArraySize(increments)];
268 ct_.AddSnapshot({{MONOTONIC, last_mono}, {BOOTTIME, last_boot}});
269
270 last_raw += increments[rnd() % base::ArraySize(increments)];
271 last_boot += increments[rnd() % base::ArraySize(increments)];
272 ct_.AddSnapshot({{MONOTONIC_RAW, last_raw}, {BOOTTIME, last_boot}});
273 }
274
275 for (int i = 0; i < 1000; i++) {
276 int64_t val = static_cast<int64_t>(rnd()) % 10000;
277 for (int j = 0; j < 5; j++) {
278 ClockTracker::ClockId src;
279 ClockTracker::ClockId tgt;
280 if (j == 0) {
281 std::tie(src, tgt) = std::make_tuple(MONOTONIC, BOOTTIME);
282 } else if (j == 1) {
283 std::tie(src, tgt) = std::make_tuple(MONOTONIC_RAW, BOOTTIME);
284 } else if (j == 2) {
285 std::tie(src, tgt) = std::make_tuple(BOOTTIME, MONOTONIC);
286 } else if (j == 3) {
287 std::tie(src, tgt) = std::make_tuple(BOOTTIME, MONOTONIC_RAW);
288 } else if (j == 4) {
289 std::tie(src, tgt) = std::make_tuple(MONOTONIC_RAW, MONOTONIC);
290 } else {
291 PERFETTO_FATAL("j out of bounds");
292 }
293 // It will still write the cache, just not lookup.
294 ct_.set_cache_lookups_disabled_for_testing(true);
295 auto not_cached = Convert(src, val, tgt);
296
297 // This should 100% hit the cache.
298 ct_.set_cache_lookups_disabled_for_testing(false);
299 auto cached = Convert(src, val, tgt);
300
301 ASSERT_EQ(not_cached.value(), cached.value());
302 }
303 }
304 }
305
306 } // namespace
307 } // namespace trace_processor
308 } // namespace perfetto
309