xref: /aosp_15_r20/external/perfetto/src/trace_processor/importers/common/flow_tracker_unittest.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1 /*
2  * Copyright (C) 2020 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 <vector>
18 
19 #include "src/trace_processor/importers/common/args_translation_table.h"
20 #include "src/trace_processor/importers/common/flow_tracker.h"
21 #include "src/trace_processor/importers/common/slice_tracker.h"
22 #include "src/trace_processor/importers/common/slice_translation_table.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 namespace perfetto {
28 namespace trace_processor {
29 namespace {
30 
31 using ::testing::Eq;
32 
33 class FlowTrackerTest : public ::testing::Test {
34  public:
FlowTrackerTest()35   FlowTrackerTest() {
36     context_.storage = std::make_unique<TraceStorage>();
37     context_.args_translation_table =
38         std::make_unique<ArgsTranslationTable>(context_.storage.get());
39     context_.slice_translation_table =
40         std::make_unique<SliceTranslationTable>(context_.storage.get());
41     context_.slice_tracker = std::make_unique<SliceTracker>(&context_);
42   }
43 
44  protected:
45   TraceProcessorContext context_;
46 };
47 
TEST_F(FlowTrackerTest,SingleFlowEventExplicitInSliceBinding)48 TEST_F(FlowTrackerTest, SingleFlowEventExplicitInSliceBinding) {
49   auto& slice_tracker = context_.slice_tracker;
50   FlowTracker tracker(&context_);
51   slice_tracker->SetOnSliceBeginCallback(
52       [&tracker](TrackId track_id, SliceId slice_id) {
53         tracker.ClosePendingEventsOnTrack(track_id, slice_id);
54       });
55 
56   FlowId flow_id = 1;
57   TrackId track_1(1);
58   TrackId track_2(2);
59 
60   slice_tracker->Begin(100, track_1, StringId::Raw(1), StringId::Raw(1));
61   SliceId out_slice_id = slice_tracker->GetTopmostSliceOnTrack(track_1).value();
62   tracker.Begin(track_1, flow_id);
63   slice_tracker->End(120, track_1, StringId::Raw(1), StringId::Raw(1));
64 
65   slice_tracker->Begin(140, track_2, StringId::Raw(2), StringId::Raw(2));
66   SliceId in_slice_id = slice_tracker->GetTopmostSliceOnTrack(track_2).value();
67   tracker.End(track_2, flow_id, /* bind_enclosing = */ true,
68               /* close_flow = */ false);
69   slice_tracker->End(160, track_2, StringId::Raw(2), StringId::Raw(2));
70 
71   const auto& flows = context_.storage->flow_table();
72   EXPECT_EQ(flows.row_count(), 1u);
73 
74   auto f = flows[0];
75   EXPECT_EQ(f.slice_out(), out_slice_id);
76   EXPECT_EQ(f.slice_in(), in_slice_id);
77 }
78 
TEST_F(FlowTrackerTest,SingleFlowEventWaitForNextSlice)79 TEST_F(FlowTrackerTest, SingleFlowEventWaitForNextSlice) {
80   auto& slice_tracker = context_.slice_tracker;
81   FlowTracker tracker(&context_);
82   slice_tracker->SetOnSliceBeginCallback(
83       [&tracker](TrackId track_id, SliceId slice_id) {
84         tracker.ClosePendingEventsOnTrack(track_id, slice_id);
85       });
86 
87   FlowId flow_id = 1;
88   TrackId track_1(1);
89   TrackId track_2(2);
90 
91   slice_tracker->Begin(100, track_1, StringId::Raw(1), StringId::Raw(1));
92   SliceId out_slice_id = slice_tracker->GetTopmostSliceOnTrack(track_1).value();
93   tracker.Begin(track_1, flow_id);
94   slice_tracker->End(120, track_1, StringId::Raw(1), StringId::Raw(1));
95 
96   tracker.End(track_2, flow_id, /* bind_enclosing = */ false,
97               /* close_flow = */ false);
98 
99   const auto& flows = context_.storage->flow_table();
100 
101   EXPECT_EQ(flows.row_count(), 0u);
102 
103   slice_tracker->Begin(140, track_2, StringId::Raw(2), StringId::Raw(2));
104   SliceId in_slice_id = slice_tracker->GetTopmostSliceOnTrack(track_2).value();
105   slice_tracker->End(160, track_2, StringId::Raw(2), StringId::Raw(2));
106 
107   EXPECT_EQ(flows.row_count(), 1u);
108 
109   auto f = flows[0];
110   EXPECT_EQ(f.slice_out(), out_slice_id);
111   EXPECT_EQ(f.slice_in(), in_slice_id);
112 }
113 
TEST_F(FlowTrackerTest,SingleFlowEventWaitForNextSliceScoped)114 TEST_F(FlowTrackerTest, SingleFlowEventWaitForNextSliceScoped) {
115   auto& slice_tracker = context_.slice_tracker;
116   FlowTracker tracker(&context_);
117   slice_tracker->SetOnSliceBeginCallback(
118       [&tracker](TrackId track_id, SliceId slice_id) {
119         tracker.ClosePendingEventsOnTrack(track_id, slice_id);
120       });
121 
122   FlowId flow_id = 1;
123   TrackId track_1(1);
124   TrackId track_2(2);
125 
126   slice_tracker->Begin(100, track_1, StringId::Raw(1), StringId::Raw(1));
127   SliceId out_slice_id = slice_tracker->GetTopmostSliceOnTrack(track_1).value();
128   tracker.Begin(track_1, flow_id);
129   slice_tracker->End(120, track_1, StringId::Raw(1), StringId::Raw(1));
130 
131   tracker.End(track_2, flow_id, /* bind_enclosing = */ false,
132               /* close_flow = */ false);
133 
134   const auto& flows = context_.storage->flow_table();
135 
136   EXPECT_EQ(flows.row_count(), 0u);
137 
138   slice_tracker->Scoped(140, track_2, StringId::Raw(2), StringId::Raw(2), 100);
139   SliceId in_slice_id = slice_tracker->GetTopmostSliceOnTrack(track_2).value();
140 
141   EXPECT_EQ(flows.row_count(), 1u);
142 
143   auto f = flows[0];
144   EXPECT_EQ(f.slice_out(), out_slice_id);
145   EXPECT_EQ(f.slice_in(), in_slice_id);
146 }
147 
TEST_F(FlowTrackerTest,TwoFlowEventsWaitForNextSlice)148 TEST_F(FlowTrackerTest, TwoFlowEventsWaitForNextSlice) {
149   auto& slice_tracker = context_.slice_tracker;
150   FlowTracker tracker(&context_);
151   slice_tracker->SetOnSliceBeginCallback(
152       [&tracker](TrackId track_id, SliceId slice_id) {
153         tracker.ClosePendingEventsOnTrack(track_id, slice_id);
154       });
155 
156   FlowId flow1_id = 1;
157   FlowId flow2_id = 2;
158   TrackId track_1(1);
159   TrackId track_2(2);
160 
161   // begin flow1 in enclosing slice1
162   slice_tracker->Begin(100, track_1, StringId::Raw(1), StringId::Raw(1));
163   SliceId out_slice1_id =
164       slice_tracker->GetTopmostSliceOnTrack(track_1).value();
165   tracker.Begin(track_1, flow1_id);
166   tracker.End(track_2, flow1_id, /* bind_enclosing = */ false,
167               /* close_flow = */ false);
168   slice_tracker->End(120, track_1, StringId::Raw(1), StringId::Raw(1));
169 
170   // begin flow2 in enclosing slice2
171   slice_tracker->Begin(130, track_1, StringId::Raw(2), StringId::Raw(2));
172   SliceId out_slice2_id =
173       slice_tracker->GetTopmostSliceOnTrack(track_1).value();
174   tracker.Begin(track_1, flow2_id);
175   tracker.End(track_2, flow2_id, /* bind_enclosing = */ false,
176               /* close_flow = */ false);
177   slice_tracker->End(140, track_1, StringId::Raw(2), StringId::Raw(2));
178 
179   const auto& flows = context_.storage->flow_table();
180 
181   EXPECT_EQ(flows.row_count(), 0u);
182 
183   // close all pending flows
184   slice_tracker->Begin(160, track_2, StringId::Raw(3), StringId::Raw(3));
185   SliceId in_slice_id = slice_tracker->GetTopmostSliceOnTrack(track_2).value();
186   slice_tracker->End(170, track_2, StringId::Raw(3), StringId::Raw(3));
187 
188   EXPECT_EQ(flows.row_count(), 2u);
189 
190   auto f = flows[0];
191   EXPECT_EQ(f.slice_out(), out_slice1_id);
192   EXPECT_EQ(f.slice_in(), in_slice_id);
193 
194   f = flows[1];
195   EXPECT_EQ(f.slice_out(), out_slice2_id);
196   EXPECT_EQ(f.slice_in(), in_slice_id);
197 }
198 
TEST_F(FlowTrackerTest,TwoFlowEventsSliceInSlice)199 TEST_F(FlowTrackerTest, TwoFlowEventsSliceInSlice) {
200   auto& slice_tracker = context_.slice_tracker;
201   FlowTracker tracker(&context_);
202   slice_tracker->SetOnSliceBeginCallback(
203       [&tracker](TrackId track_id, SliceId slice_id) {
204         tracker.ClosePendingEventsOnTrack(track_id, slice_id);
205       });
206 
207   FlowId flow1_id = 1;
208   FlowId flow2_id = 2;
209   TrackId track_1(1);
210   TrackId track_2(2);
211 
212   // start two nested slices
213   slice_tracker->Begin(100, track_1, StringId::Raw(1), StringId::Raw(1));
214   SliceId out_slice1_id =
215       slice_tracker->GetTopmostSliceOnTrack(track_1).value();
216   slice_tracker->Begin(120, track_1, StringId::Raw(2), StringId::Raw(2));
217   SliceId out_slice2_id =
218       slice_tracker->GetTopmostSliceOnTrack(track_1).value();
219 
220   tracker.Begin(track_1, flow1_id);
221 
222   slice_tracker->End(140, track_1, StringId::Raw(2), StringId::Raw(2));
223 
224   tracker.Begin(track_1, flow2_id);
225 
226   slice_tracker->End(150, track_1, StringId::Raw(1), StringId::Raw(1));
227 
228   slice_tracker->Begin(160, track_2, StringId::Raw(3), StringId::Raw(3));
229   SliceId in_slice_id = slice_tracker->GetTopmostSliceOnTrack(track_2).value();
230 
231   tracker.End(track_2, flow1_id, /* bind_enclosing = */ true,
232               /* close_flow = */ false);
233   tracker.End(track_2, flow2_id, /* bind_enclosing = */ true,
234               /* close_flow = */ false);
235 
236   slice_tracker->End(170, track_2, StringId::Raw(3), StringId::Raw(3));
237 
238   const auto& flows = context_.storage->flow_table();
239   EXPECT_EQ(flows.row_count(), 2u);
240 
241   auto f = flows[0];
242   EXPECT_EQ(f.slice_out(), out_slice2_id);
243   EXPECT_EQ(f.slice_in(), in_slice_id);
244 
245   f = flows[1];
246   EXPECT_EQ(f.slice_out(), out_slice1_id);
247   EXPECT_EQ(f.slice_in(), in_slice_id);
248 }
249 
TEST_F(FlowTrackerTest,FlowEventsWithStep)250 TEST_F(FlowTrackerTest, FlowEventsWithStep) {
251   auto& slice_tracker = context_.slice_tracker;
252   FlowTracker tracker(&context_);
253   slice_tracker->SetOnSliceBeginCallback(
254       [&tracker](TrackId track_id, SliceId slice_id) {
255         tracker.ClosePendingEventsOnTrack(track_id, slice_id);
256       });
257 
258   FlowId flow_id = 1;
259   TrackId track_1(1);
260   TrackId track_2(2);
261 
262   // flow begin inside slice1 on track1
263   slice_tracker->Begin(100, track_1, StringId::Raw(1), StringId::Raw(1));
264   SliceId out_slice1_id =
265       slice_tracker->GetTopmostSliceOnTrack(track_1).value();
266   tracker.Begin(track_1, flow_id);
267   slice_tracker->End(140, track_1, StringId::Raw(1), StringId::Raw(1));
268 
269   // flow step inside slice2 on track2
270   slice_tracker->Begin(160, track_2, StringId::Raw(2), StringId::Raw(2));
271   SliceId inout_slice2_id =
272       slice_tracker->GetTopmostSliceOnTrack(track_2).value();
273   tracker.Step(track_2, flow_id);
274   slice_tracker->End(170, track_2, StringId::Raw(2), StringId::Raw(2));
275 
276   // flow end inside slice3 on track3
277   slice_tracker->Begin(180, track_1, StringId::Raw(3), StringId::Raw(3));
278   SliceId in_slice_id = slice_tracker->GetTopmostSliceOnTrack(track_1).value();
279   tracker.End(track_1, flow_id, /* bind_enclosing = */ true,
280               /* close_flow = */ false);
281   slice_tracker->End(190, track_1, StringId::Raw(3), StringId::Raw(3));
282 
283   const auto& flows = context_.storage->flow_table();
284   EXPECT_EQ(flows.row_count(), 2u);
285 
286   auto f = flows[0];
287   EXPECT_EQ(f.slice_out(), out_slice1_id);
288   EXPECT_EQ(f.slice_in(), inout_slice2_id);
289 
290   f = flows[1];
291   EXPECT_EQ(f.slice_out(), inout_slice2_id);
292   EXPECT_EQ(f.slice_in(), in_slice_id);
293 }
294 
295 }  // namespace
296 }  // namespace trace_processor
297 }  // namespace perfetto
298