1 /*
2 * Copyright (C) 2023 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/perf/aux_stream_manager.h"
18 #include <cstdint>
19 #include <memory>
20
21 #include "perfetto/base/status.h"
22 #include "perfetto/trace_processor/trace_blob.h"
23 #include "perfetto/trace_processor/trace_blob_view.h"
24 #include "src/trace_processor/importers/perf/aux_record.h"
25 #include "src/trace_processor/importers/perf/auxtrace_info_record.h"
26 #include "src/trace_processor/storage/stats.h"
27 #include "src/trace_processor/storage/trace_storage.h"
28 #include "src/trace_processor/types/trace_processor_context.h"
29 #include "test/gtest_and_gmock.h"
30
31 namespace perfetto::trace_processor::perf_importer {
32 namespace {
33
CreateTraceProcessorContext()34 std::unique_ptr<TraceProcessorContext> CreateTraceProcessorContext() {
35 auto ctx = std::make_unique<TraceProcessorContext>();
36 ctx->storage = std::make_shared<TraceStorage>();
37 return ctx;
38 }
39
CreateAuxtraceInfoRecord()40 AuxtraceInfoRecord CreateAuxtraceInfoRecord() {
41 AuxtraceInfoRecord info;
42 info.type = 0;
43 return info;
44 }
45
CreateAuxRecord(uint64_t offset,uint64_t size,uint32_t cpu)46 AuxRecord CreateAuxRecord(uint64_t offset, uint64_t size, uint32_t cpu) {
47 AuxRecord aux;
48 aux.offset = offset;
49 aux.size = size;
50 aux.flags = 0;
51 aux.sample_id.emplace();
52 aux.sample_id->set_cpu(cpu);
53 return aux;
54 }
55
CreateAuxtraceRecord(uint64_t offset,uint64_t size,uint32_t cpu)56 AuxtraceRecord CreateAuxtraceRecord(uint64_t offset,
57 uint64_t size,
58 uint32_t cpu) {
59 AuxtraceRecord auxtrace;
60 auxtrace.offset = offset;
61 auxtrace.size = size;
62 auxtrace.cpu = cpu;
63 auxtrace.tid = 0;
64 return auxtrace;
65 }
66
TEST(AuxStreamManagerTest,NoAuxStreamsCanFinalize)67 TEST(AuxStreamManagerTest, NoAuxStreamsCanFinalize) {
68 auto ctx = CreateTraceProcessorContext();
69 AuxStreamManager manager(ctx.get());
70 EXPECT_TRUE(manager.FinalizeStreams().ok());
71 }
72
TEST(AuxStreamManagerTest,NoAuxTraceInfoFailsMethods)73 TEST(AuxStreamManagerTest, NoAuxTraceInfoFailsMethods) {
74 auto ctx = CreateTraceProcessorContext();
75 AuxStreamManager manager(ctx.get());
76
77 EXPECT_FALSE(manager
78 .OnAuxtraceRecord(CreateAuxtraceRecord(0, 10, 0),
79 TraceBlobView(TraceBlob::Allocate(10)))
80 .ok());
81 EXPECT_FALSE(manager.OnAuxRecord(CreateAuxRecord(0, 10, 0)).ok());
82 }
83
TEST(AuxStreamManagerTest,MultipleAuxTraceInfoFails)84 TEST(AuxStreamManagerTest, MultipleAuxTraceInfoFails) {
85 auto ctx = CreateTraceProcessorContext();
86 AuxStreamManager manager(ctx.get());
87
88 AuxtraceInfoRecord info_0;
89 info_0.type = 0;
90 EXPECT_TRUE(manager.OnAuxtraceInfoRecord(std::move(info_0)).ok());
91
92 AuxtraceInfoRecord info_1;
93 info_1.type = 1;
94 EXPECT_FALSE(manager.OnAuxtraceInfoRecord(std::move(info_1)).ok());
95 }
96
TEST(AuxStreamManagerTest,ReconstructsStream)97 TEST(AuxStreamManagerTest, ReconstructsStream) {
98 constexpr uint64_t kSize = 10;
99 constexpr uint32_t kCpu = 0;
100 TraceBlobView data(TraceBlob::Allocate(kSize));
101 TraceBlobView double_data(TraceBlob::Allocate(2 * kSize));
102 auto ctx = CreateTraceProcessorContext();
103 AuxStreamManager manager(ctx.get());
104 ASSERT_TRUE(manager.OnAuxtraceInfoRecord(CreateAuxtraceInfoRecord()).ok());
105
106 manager.OnAuxRecord(CreateAuxRecord(0, kSize, kCpu));
107 EXPECT_EQ(ctx->storage->stats()[stats::perf_aux_ignored].value, 0);
108
109 manager.OnAuxRecord(CreateAuxRecord(10, kSize, kCpu));
110 EXPECT_EQ(ctx->storage->stats()[stats::perf_aux_ignored].value, 0);
111
112 manager.OnAuxtraceRecord(CreateAuxtraceRecord(0, 2 * kSize, kCpu),
113 double_data.copy());
114 EXPECT_EQ(ctx->storage->stats()[stats::perf_aux_ignored].value, 20);
115
116 manager.OnAuxtraceRecord(CreateAuxtraceRecord(20, kSize, kCpu), data.copy());
117 EXPECT_EQ(ctx->storage->stats()[stats::perf_aux_ignored].value, 20);
118
119 manager.OnAuxtraceRecord(CreateAuxtraceRecord(30, kSize, kCpu), data.copy());
120 EXPECT_EQ(ctx->storage->stats()[stats::perf_aux_ignored].value, 20);
121
122 manager.OnAuxRecord(CreateAuxRecord(20, 2 * kSize, kCpu));
123 EXPECT_EQ(ctx->storage->stats()[stats::perf_aux_ignored].value, 40);
124 }
125
TEST(AuxStreamManagerTest,AuxLoss)126 TEST(AuxStreamManagerTest, AuxLoss) {
127 constexpr uint64_t kSize = 10;
128 constexpr uint32_t kCpu = 0;
129 TraceBlobView data(TraceBlob::Allocate(kSize));
130 TraceBlobView triple_data(TraceBlob::Allocate(3 * kSize));
131 auto ctx = CreateTraceProcessorContext();
132 AuxStreamManager manager(ctx.get());
133 ASSERT_TRUE(manager.OnAuxtraceInfoRecord(CreateAuxtraceInfoRecord()).ok());
134
135 manager.OnAuxRecord(CreateAuxRecord(10, kSize, kCpu));
136 EXPECT_EQ(ctx->storage->stats()[stats::perf_aux_missing].value, 10);
137 EXPECT_EQ(ctx->storage->stats()[stats::perf_auxtrace_missing].value, 0);
138 EXPECT_EQ(ctx->storage->stats()[stats::perf_aux_ignored].value, 0);
139 EXPECT_EQ(ctx->storage->stats()[stats::perf_aux_lost].value, 0);
140
141 manager.OnAuxtraceRecord(CreateAuxtraceRecord(0, 3 * kSize, kCpu),
142 triple_data.copy());
143 EXPECT_EQ(ctx->storage->stats()[stats::perf_aux_missing].value, 10);
144 EXPECT_EQ(ctx->storage->stats()[stats::perf_auxtrace_missing].value, 0);
145 EXPECT_EQ(ctx->storage->stats()[stats::perf_aux_ignored].value, 10);
146 EXPECT_EQ(ctx->storage->stats()[stats::perf_aux_lost].value, 10);
147
148 manager.FinalizeStreams();
149 EXPECT_EQ(ctx->storage->stats()[stats::perf_aux_missing].value, 20);
150 EXPECT_EQ(ctx->storage->stats()[stats::perf_auxtrace_missing].value, 0);
151 EXPECT_EQ(ctx->storage->stats()[stats::perf_aux_ignored].value, 10);
152 EXPECT_EQ(ctx->storage->stats()[stats::perf_aux_lost].value, 20);
153 }
154
TEST(AuxStreamManagerTest,AuxtraceLoss)155 TEST(AuxStreamManagerTest, AuxtraceLoss) {
156 constexpr uint64_t kSize = 10;
157 constexpr uint32_t kCpu = 0;
158 TraceBlobView data(TraceBlob::Allocate(kSize));
159 auto ctx = CreateTraceProcessorContext();
160 AuxStreamManager manager(ctx.get());
161 ASSERT_TRUE(manager.OnAuxtraceInfoRecord(CreateAuxtraceInfoRecord()).ok());
162
163 manager.OnAuxtraceRecord(CreateAuxtraceRecord(10, kSize, kCpu), data.copy());
164 EXPECT_EQ(ctx->storage->stats()[stats::perf_aux_missing].value, 0);
165 EXPECT_EQ(ctx->storage->stats()[stats::perf_auxtrace_missing].value, 10);
166 EXPECT_EQ(ctx->storage->stats()[stats::perf_aux_ignored].value, 0);
167 EXPECT_EQ(ctx->storage->stats()[stats::perf_aux_lost].value, 0);
168
169 manager.OnAuxRecord(CreateAuxRecord(0, 3 * kSize, kCpu));
170 EXPECT_EQ(ctx->storage->stats()[stats::perf_aux_missing].value, 0);
171 EXPECT_EQ(ctx->storage->stats()[stats::perf_auxtrace_missing].value, 10);
172 EXPECT_EQ(ctx->storage->stats()[stats::perf_aux_ignored].value, 10);
173 EXPECT_EQ(ctx->storage->stats()[stats::perf_aux_lost].value, 10);
174
175 manager.FinalizeStreams();
176 EXPECT_EQ(ctx->storage->stats()[stats::perf_aux_missing].value, 0);
177 EXPECT_EQ(ctx->storage->stats()[stats::perf_auxtrace_missing].value, 20);
178 EXPECT_EQ(ctx->storage->stats()[stats::perf_aux_ignored].value, 10);
179 EXPECT_EQ(ctx->storage->stats()[stats::perf_aux_lost].value, 20);
180 }
181
TEST(AuxStreamManagerTest,ComplexStream)182 TEST(AuxStreamManagerTest, ComplexStream) {
183 constexpr uint32_t kCpu = 0;
184 TraceBlobView data_5(TraceBlob::Allocate(5));
185 TraceBlobView data_10(TraceBlob::Allocate(10));
186 TraceBlobView data_15(TraceBlob::Allocate(15));
187
188 auto ctx = CreateTraceProcessorContext();
189 AuxStreamManager manager(ctx.get());
190 ASSERT_TRUE(manager.OnAuxtraceInfoRecord(CreateAuxtraceInfoRecord()).ok());
191
192 uint64_t aux_offset = 0;
193 uint64_t auxtrace_offset = 0;
194
195 auto aux = [&](uint64_t size) {
196 manager.OnAuxRecord(CreateAuxRecord(aux_offset, size, kCpu));
197 aux_offset += size;
198 };
199 auto aux_hole = [&](uint64_t size) { aux_offset += size; };
200
201 auto auxtrace = [&](uint64_t size) {
202 manager.OnAuxtraceRecord(CreateAuxtraceRecord(auxtrace_offset, size, kCpu),
203 TraceBlobView(TraceBlob::Allocate(size)));
204 auxtrace_offset += size;
205 };
206 auto auxtrace_hole = [&](uint64_t size) { auxtrace_offset += size; };
207
208 // . . . . . . . . . . . . . . . . . . . . . .
209 // |105 |
210 // Aux |---|30 |10 |30 |-|20 |
211 // Auxtrace |5|10 |50 |5|-|5|---|5|---|
212 // Result |---|60 |-|5|---|5|---|
213 // . . . . . . . . . . . . . . . . . . . . . .
214 aux_hole(10);
215 aux(30);
216 aux(10);
217 aux(30);
218 aux_hole(5);
219 aux(20);
220 auxtrace(5);
221 auxtrace(10);
222 auxtrace(50);
223 auxtrace(5);
224 auxtrace_hole(5);
225 auxtrace(5);
226 auxtrace_hole(10);
227 auxtrace(5);
228
229 manager.FinalizeStreams();
230
231 EXPECT_EQ(ctx->storage->stats()[stats::perf_aux_missing].value, 15);
232 EXPECT_EQ(ctx->storage->stats()[stats::perf_auxtrace_missing].value, 25);
233 EXPECT_EQ(ctx->storage->stats()[stats::perf_aux_ignored].value, 70);
234 EXPECT_EQ(ctx->storage->stats()[stats::perf_aux_lost].value, 35);
235 }
236
TEST(AuxStreamManagerTest,StreamOverlapFails)237 TEST(AuxStreamManagerTest, StreamOverlapFails) {
238 constexpr uint64_t kSize = 10;
239 constexpr uint32_t kCpu = 0;
240 TraceBlobView data(TraceBlob::Allocate(kSize));
241 auto ctx = CreateTraceProcessorContext();
242 AuxStreamManager manager(ctx.get());
243 ASSERT_TRUE(manager.OnAuxtraceInfoRecord(CreateAuxtraceInfoRecord()).ok());
244
245 EXPECT_TRUE(manager.OnAuxRecord(CreateAuxRecord(0, kSize, kCpu)).ok());
246 EXPECT_FALSE(manager.OnAuxRecord(CreateAuxRecord(0, kSize, kCpu)).ok());
247
248 EXPECT_TRUE(
249 manager
250 .OnAuxtraceRecord(CreateAuxtraceRecord(0, kSize, kCpu), data.copy())
251 .ok());
252 EXPECT_FALSE(
253 manager
254 .OnAuxtraceRecord(CreateAuxtraceRecord(0, kSize, kCpu), data.copy())
255 .ok());
256 }
257
TEST(AuxStreamManagerTest,MultipleStreams)258 TEST(AuxStreamManagerTest, MultipleStreams) {
259 constexpr uint64_t kSize = 10;
260 constexpr uint32_t kCpu_0 = 0;
261 constexpr uint32_t kCpu_1 = 1;
262 TraceBlobView data(TraceBlob::Allocate(kSize));
263 auto ctx = CreateTraceProcessorContext();
264 AuxStreamManager manager(ctx.get());
265 ASSERT_TRUE(manager.OnAuxtraceInfoRecord(CreateAuxtraceInfoRecord()).ok());
266
267 EXPECT_TRUE(manager.OnAuxRecord(CreateAuxRecord(0, kSize, kCpu_0)).ok());
268 EXPECT_TRUE(manager.OnAuxRecord(CreateAuxRecord(0, kSize, kCpu_1)).ok());
269
270 EXPECT_TRUE(
271 manager
272 .OnAuxtraceRecord(CreateAuxtraceRecord(0, kSize, kCpu_0), data.copy())
273 .ok());
274 EXPECT_TRUE(
275 manager
276 .OnAuxtraceRecord(CreateAuxtraceRecord(0, kSize, kCpu_1), data.copy())
277 .ok());
278
279 manager.FinalizeStreams();
280
281 EXPECT_EQ(ctx->storage->stats()[stats::perf_aux_ignored].value, 20);
282 }
283
284 } // namespace
285 } // namespace perfetto::trace_processor::perf_importer
286