1 /*
2 * Copyright (C) 2024 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/proto/proto_trace_reader.h"
18 #include <memory>
19
20 #include "perfetto/protozero/scattered_heap_buffer.h"
21 #include "protos/perfetto/common/builtin_clock.pbzero.h"
22 #include "src/trace_processor/importers/common/clock_tracker.h"
23 #include "src/trace_processor/importers/common/machine_tracker.h"
24 #include "src/trace_processor/storage/trace_storage.h"
25
26 #include "test/gtest_and_gmock.h"
27
28 #include "protos/perfetto/trace/clock_snapshot.pbzero.h"
29 #include "protos/perfetto/trace/remote_clock_sync.pbzero.h"
30
31 namespace perfetto::trace_processor {
32 namespace {
33
34 constexpr auto REALTIME = protos::pbzero::BUILTIN_CLOCK_REALTIME;
35 constexpr auto BOOTTIME = protos::pbzero::BUILTIN_CLOCK_BOOTTIME;
36
37 class ProtoTraceReaderTest : public ::testing::Test {
38 public:
ProtoTraceReaderTest()39 ProtoTraceReaderTest() {
40 context_.storage = std::make_unique<TraceStorage>();
41 context_.machine_tracker =
42 std::make_unique<MachineTracker>(&context_, 0x1001);
43 context_.clock_tracker = std::make_unique<ClockTracker>(&context_);
44 proto_trace_reader_ = std::make_unique<ProtoTraceReader>(&context_);
45 }
46
Tokenize()47 util::Status Tokenize() {
48 trace_->Finalize();
49 std::vector<uint8_t> trace_bytes = trace_.SerializeAsArray();
50 std::unique_ptr<uint8_t[]> raw_trace(new uint8_t[trace_bytes.size()]);
51 memcpy(raw_trace.get(), trace_bytes.data(), trace_bytes.size());
52 auto status = proto_trace_reader_->Parse(TraceBlobView(
53 TraceBlob::TakeOwnership(std::move(raw_trace), trace_bytes.size())));
54
55 trace_.Reset();
56 return status;
57 }
58
59 protected:
60 protozero::HeapBuffered<protos::pbzero::Trace> trace_;
61 TraceProcessorContext context_;
62 std::unique_ptr<ProtoTraceReader> proto_trace_reader_;
63 };
64
TEST_F(ProtoTraceReaderTest,RemoteClockSync_Valid)65 TEST_F(ProtoTraceReaderTest, RemoteClockSync_Valid) {
66 context_.machine_tracker =
67 std::make_unique<MachineTracker>(&context_, 0x1001);
68
69 auto* packet = trace_->add_packet();
70 packet->set_machine_id(0x1001);
71 auto* remote_clock_sync = packet->set_remote_clock_sync();
72 auto* synced_clocks = remote_clock_sync->add_synced_clocks();
73 auto* client_clocks = synced_clocks->set_client_clocks();
74
75 // First synced clock snapshots on both sides.
76 auto* clock = client_clocks->add_clocks();
77 clock->set_clock_id(BOOTTIME);
78 clock->set_timestamp(10000);
79
80 auto* host_clocks = synced_clocks->set_host_clocks();
81 clock = host_clocks->add_clocks();
82 clock->set_clock_id(BOOTTIME);
83 clock->set_timestamp(120000);
84
85 // Second synced clock snapshots on both sides.
86 synced_clocks = remote_clock_sync->add_synced_clocks();
87
88 client_clocks = synced_clocks->set_client_clocks();
89 clock = client_clocks->add_clocks();
90 clock->set_clock_id(BOOTTIME);
91 clock->set_timestamp(25000);
92
93 host_clocks = synced_clocks->set_host_clocks();
94 clock = host_clocks->add_clocks();
95 clock->set_clock_id(BOOTTIME);
96 clock->set_timestamp(135000);
97
98 ASSERT_TRUE(Tokenize().ok());
99 ASSERT_EQ(1u, context_.clock_tracker->clock_offsets_for_testing().size());
100 }
101
TEST_F(ProtoTraceReaderTest,RemoteClockSync_Incomplete)102 TEST_F(ProtoTraceReaderTest, RemoteClockSync_Incomplete) {
103 context_.machine_tracker =
104 std::make_unique<MachineTracker>(&context_, 0x1001);
105
106 auto* packet = trace_->add_packet();
107 packet->set_machine_id(0x1001);
108 auto* remote_clock_sync = packet->set_remote_clock_sync();
109 auto* synced_clocks = remote_clock_sync->add_synced_clocks();
110 auto* client_clocks = synced_clocks->set_client_clocks();
111
112 // First synced clock snapshots on both sides.
113 auto* clock = client_clocks->add_clocks();
114 clock->set_clock_id(BOOTTIME);
115 clock->set_timestamp(10000);
116
117 auto* host_clocks = synced_clocks->set_host_clocks();
118 clock = host_clocks->add_clocks();
119 clock->set_clock_id(BOOTTIME);
120 clock->set_timestamp(120000);
121
122 // Second synced clock snapshots on both sides.
123 synced_clocks = remote_clock_sync->add_synced_clocks();
124
125 client_clocks = synced_clocks->set_client_clocks();
126 clock = client_clocks->add_clocks();
127 clock->set_clock_id(BOOTTIME);
128 clock->set_timestamp(25000);
129
130 // Missing the second host CLOCK_BOOTTIME making it below the minimum
131 // requirement for using the remote_clock_sync for calculating clock offset.
132
133 ASSERT_TRUE(Tokenize().ok());
134 // No valid clock offset.
135 ASSERT_EQ(0u, context_.clock_tracker->clock_offsets_for_testing().size());
136 }
137
TEST_F(ProtoTraceReaderTest,CalculateClockOffset)138 TEST_F(ProtoTraceReaderTest, CalculateClockOffset) {
139 std::vector<ProtoTraceReader::SyncClockSnapshots> sync_clock_snapshots;
140 ProtoTraceReader::SyncClockSnapshots snapshots;
141 snapshots[BOOTTIME] = {120000, 10000};
142 snapshots[REALTIME] = {135000, 25000};
143 sync_clock_snapshots.push_back(std::move(snapshots));
144
145 snapshots[BOOTTIME] = {140000, 20000};
146 snapshots[REALTIME] = {150000, 35000};
147 sync_clock_snapshots.push_back(std::move(snapshots));
148
149 auto clock_offsets = proto_trace_reader_->CalculateClockOffsetsForTesting(
150 sync_clock_snapshots);
151 ASSERT_EQ(2u, clock_offsets.size());
152 // Client 10000 20000
153 // Host 120000 140000
154 // Estimated offsets: (10000 + 20000)/2 - 120000 = -105000,
155 // 20000 - (120000 + 140000) / 2 = -110000.
156 // Average = -107500.
157 ASSERT_EQ(-107500, clock_offsets[BOOTTIME]);
158 // Client 25000 35000
159 // Host 135000 150000
160 // Estimated offsets: (25000 + 35000)/2 - 135000 = -105000,
161 // 35000 - (135000 + 150000) / 2 = -107500.
162 // Average = -106250.
163 ASSERT_EQ(-106250, clock_offsets[REALTIME]);
164 }
165
TEST_F(ProtoTraceReaderTest,CalculateClockOffset_AboveThreshold)166 TEST_F(ProtoTraceReaderTest, CalculateClockOffset_AboveThreshold) {
167 std::vector<ProtoTraceReader::SyncClockSnapshots> sync_clock_snapshots;
168 ProtoTraceReader::SyncClockSnapshots snapshots;
169 snapshots[BOOTTIME] = {120000, 10000};
170 snapshots[REALTIME] = {135000, 25000};
171 sync_clock_snapshots.push_back(std::move(snapshots));
172
173 // 30 sec interval: the 2 clock snapshots will be considered 2 different
174 // rounds of clock synchronization IPC exchange and won't be used.
175 auto interval = 30ull * 1000 * 1000 * 1000;
176 snapshots[BOOTTIME] = {120000 + interval, 10000 + interval};
177 snapshots[REALTIME] = {135000 + interval, 25000 + interval};
178 sync_clock_snapshots.push_back(std::move(snapshots));
179
180 auto clock_offsets = proto_trace_reader_->CalculateClockOffsetsForTesting(
181 sync_clock_snapshots);
182 ASSERT_EQ(0u, clock_offsets.size());
183 }
184
TEST_F(ProtoTraceReaderTest,CalculateClockOffset_MultiRounds)185 TEST_F(ProtoTraceReaderTest, CalculateClockOffset_MultiRounds) {
186 std::vector<ProtoTraceReader::SyncClockSnapshots> sync_clock_snapshots;
187 ProtoTraceReader::SyncClockSnapshots snapshots;
188 // This emits clock offsets -105000, -110000.
189 snapshots[BOOTTIME] = {120000, 10000};
190 sync_clock_snapshots.push_back(std::move(snapshots));
191 snapshots[BOOTTIME] = {140000, 20000};
192 sync_clock_snapshots.push_back(std::move(snapshots));
193
194 // The interval works as a delimeter of IPC exchange.
195 auto interval = 30ull * 1000 * 1000 * 1000;
196
197 // This emits clock offsets: (30000 + 45000) / 2 - 160000 = -122500,
198 // 45000 - (160000 + 170000) / 2 = -120000.
199 snapshots[BOOTTIME] = {160000 + interval, 30000 + interval};
200 sync_clock_snapshots.push_back(std::move(snapshots));
201 snapshots[BOOTTIME] = {170000 + interval, 45000 + interval};
202 sync_clock_snapshots.push_back(std::move(snapshots));
203
204 auto clock_offsets = proto_trace_reader_->CalculateClockOffsetsForTesting(
205 sync_clock_snapshots);
206 ASSERT_EQ(1u, clock_offsets.size());
207 // Average(-105000, -110000, -122500, -120000) = -114375.
208 ASSERT_EQ(-114375, clock_offsets[BOOTTIME]);
209 }
210
211 } // namespace
212 } // namespace perfetto::trace_processor
213