• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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   EXPECT_EQ(flows.slice_out()[0], out_slice_id);
74   EXPECT_EQ(flows.slice_in()[0], in_slice_id);
75 }
76 
TEST_F(FlowTrackerTest,SingleFlowEventWaitForNextSlice)77 TEST_F(FlowTrackerTest, SingleFlowEventWaitForNextSlice) {
78   auto& slice_tracker = context_.slice_tracker;
79   FlowTracker tracker(&context_);
80   slice_tracker->SetOnSliceBeginCallback(
81       [&tracker](TrackId track_id, SliceId slice_id) {
82         tracker.ClosePendingEventsOnTrack(track_id, slice_id);
83       });
84 
85   FlowId flow_id = 1;
86   TrackId track_1(1);
87   TrackId track_2(2);
88 
89   slice_tracker->Begin(100, track_1, StringId::Raw(1), StringId::Raw(1));
90   SliceId out_slice_id = slice_tracker->GetTopmostSliceOnTrack(track_1).value();
91   tracker.Begin(track_1, flow_id);
92   slice_tracker->End(120, track_1, StringId::Raw(1), StringId::Raw(1));
93 
94   tracker.End(track_2, flow_id, /* bind_enclosing = */ false,
95               /* close_flow = */ false);
96 
97   const auto& flows = context_.storage->flow_table();
98 
99   EXPECT_EQ(flows.row_count(), 0u);
100 
101   slice_tracker->Begin(140, track_2, StringId::Raw(2), StringId::Raw(2));
102   SliceId in_slice_id = slice_tracker->GetTopmostSliceOnTrack(track_2).value();
103   slice_tracker->End(160, track_2, StringId::Raw(2), StringId::Raw(2));
104 
105   EXPECT_EQ(flows.row_count(), 1u);
106   EXPECT_EQ(flows.slice_out()[0], out_slice_id);
107   EXPECT_EQ(flows.slice_in()[0], in_slice_id);
108 }
109 
TEST_F(FlowTrackerTest,SingleFlowEventWaitForNextSliceScoped)110 TEST_F(FlowTrackerTest, SingleFlowEventWaitForNextSliceScoped) {
111   auto& slice_tracker = context_.slice_tracker;
112   FlowTracker tracker(&context_);
113   slice_tracker->SetOnSliceBeginCallback(
114       [&tracker](TrackId track_id, SliceId slice_id) {
115         tracker.ClosePendingEventsOnTrack(track_id, slice_id);
116       });
117 
118   FlowId flow_id = 1;
119   TrackId track_1(1);
120   TrackId track_2(2);
121 
122   slice_tracker->Begin(100, track_1, StringId::Raw(1), StringId::Raw(1));
123   SliceId out_slice_id = slice_tracker->GetTopmostSliceOnTrack(track_1).value();
124   tracker.Begin(track_1, flow_id);
125   slice_tracker->End(120, track_1, StringId::Raw(1), StringId::Raw(1));
126 
127   tracker.End(track_2, flow_id, /* bind_enclosing = */ false,
128               /* close_flow = */ false);
129 
130   const auto& flows = context_.storage->flow_table();
131 
132   EXPECT_EQ(flows.row_count(), 0u);
133 
134   slice_tracker->Scoped(140, track_2, StringId::Raw(2), StringId::Raw(2), 100);
135   SliceId in_slice_id = slice_tracker->GetTopmostSliceOnTrack(track_2).value();
136 
137   EXPECT_EQ(flows.row_count(), 1u);
138   EXPECT_EQ(flows.slice_out()[0], out_slice_id);
139   EXPECT_EQ(flows.slice_in()[0], in_slice_id);
140 }
141 
TEST_F(FlowTrackerTest,TwoFlowEventsWaitForNextSlice)142 TEST_F(FlowTrackerTest, TwoFlowEventsWaitForNextSlice) {
143   auto& slice_tracker = context_.slice_tracker;
144   FlowTracker tracker(&context_);
145   slice_tracker->SetOnSliceBeginCallback(
146       [&tracker](TrackId track_id, SliceId slice_id) {
147         tracker.ClosePendingEventsOnTrack(track_id, slice_id);
148       });
149 
150   FlowId flow1_id = 1;
151   FlowId flow2_id = 2;
152   TrackId track_1(1);
153   TrackId track_2(2);
154 
155   // begin flow1 in enclosing slice1
156   slice_tracker->Begin(100, track_1, StringId::Raw(1), StringId::Raw(1));
157   SliceId out_slice1_id =
158       slice_tracker->GetTopmostSliceOnTrack(track_1).value();
159   tracker.Begin(track_1, flow1_id);
160   tracker.End(track_2, flow1_id, /* bind_enclosing = */ false,
161               /* close_flow = */ false);
162   slice_tracker->End(120, track_1, StringId::Raw(1), StringId::Raw(1));
163 
164   // begin flow2 in enclosing slice2
165   slice_tracker->Begin(130, track_1, StringId::Raw(2), StringId::Raw(2));
166   SliceId out_slice2_id =
167       slice_tracker->GetTopmostSliceOnTrack(track_1).value();
168   tracker.Begin(track_1, flow2_id);
169   tracker.End(track_2, flow2_id, /* bind_enclosing = */ false,
170               /* close_flow = */ false);
171   slice_tracker->End(140, track_1, StringId::Raw(2), StringId::Raw(2));
172 
173   const auto& flows = context_.storage->flow_table();
174 
175   EXPECT_EQ(flows.row_count(), 0u);
176 
177   // close all pending flows
178   slice_tracker->Begin(160, track_2, StringId::Raw(3), StringId::Raw(3));
179   SliceId in_slice_id = slice_tracker->GetTopmostSliceOnTrack(track_2).value();
180   slice_tracker->End(170, track_2, StringId::Raw(3), StringId::Raw(3));
181 
182   EXPECT_EQ(flows.row_count(), 2u);
183   EXPECT_EQ(flows.slice_out()[0], out_slice1_id);
184   EXPECT_EQ(flows.slice_in()[0], in_slice_id);
185   EXPECT_EQ(flows.slice_out()[1], out_slice2_id);
186   EXPECT_EQ(flows.slice_in()[1], in_slice_id);
187 }
188 
TEST_F(FlowTrackerTest,TwoFlowEventsSliceInSlice)189 TEST_F(FlowTrackerTest, TwoFlowEventsSliceInSlice) {
190   auto& slice_tracker = context_.slice_tracker;
191   FlowTracker tracker(&context_);
192   slice_tracker->SetOnSliceBeginCallback(
193       [&tracker](TrackId track_id, SliceId slice_id) {
194         tracker.ClosePendingEventsOnTrack(track_id, slice_id);
195       });
196 
197   FlowId flow1_id = 1;
198   FlowId flow2_id = 2;
199   TrackId track_1(1);
200   TrackId track_2(2);
201 
202   // start two nested slices
203   slice_tracker->Begin(100, track_1, StringId::Raw(1), StringId::Raw(1));
204   SliceId out_slice1_id =
205       slice_tracker->GetTopmostSliceOnTrack(track_1).value();
206   slice_tracker->Begin(120, track_1, StringId::Raw(2), StringId::Raw(2));
207   SliceId out_slice2_id =
208       slice_tracker->GetTopmostSliceOnTrack(track_1).value();
209 
210   tracker.Begin(track_1, flow1_id);
211 
212   slice_tracker->End(140, track_1, StringId::Raw(2), StringId::Raw(2));
213 
214   tracker.Begin(track_1, flow2_id);
215 
216   slice_tracker->End(150, track_1, StringId::Raw(1), StringId::Raw(1));
217 
218   slice_tracker->Begin(160, track_2, StringId::Raw(3), StringId::Raw(3));
219   SliceId in_slice_id = slice_tracker->GetTopmostSliceOnTrack(track_2).value();
220 
221   tracker.End(track_2, flow1_id, /* bind_enclosing = */ true,
222               /* close_flow = */ false);
223   tracker.End(track_2, flow2_id, /* bind_enclosing = */ true,
224               /* close_flow = */ false);
225 
226   slice_tracker->End(170, track_2, StringId::Raw(3), StringId::Raw(3));
227 
228   const auto& flows = context_.storage->flow_table();
229   EXPECT_EQ(flows.row_count(), 2u);
230   EXPECT_EQ(flows.slice_out()[0], out_slice2_id);
231   EXPECT_EQ(flows.slice_in()[0], in_slice_id);
232   EXPECT_EQ(flows.slice_out()[1], out_slice1_id);
233   EXPECT_EQ(flows.slice_in()[1], in_slice_id);
234 }
235 
TEST_F(FlowTrackerTest,FlowEventsWithStep)236 TEST_F(FlowTrackerTest, FlowEventsWithStep) {
237   auto& slice_tracker = context_.slice_tracker;
238   FlowTracker tracker(&context_);
239   slice_tracker->SetOnSliceBeginCallback(
240       [&tracker](TrackId track_id, SliceId slice_id) {
241         tracker.ClosePendingEventsOnTrack(track_id, slice_id);
242       });
243 
244   FlowId flow_id = 1;
245   TrackId track_1(1);
246   TrackId track_2(2);
247 
248   // flow begin inside slice1 on track1
249   slice_tracker->Begin(100, track_1, StringId::Raw(1), StringId::Raw(1));
250   SliceId out_slice1_id =
251       slice_tracker->GetTopmostSliceOnTrack(track_1).value();
252   tracker.Begin(track_1, flow_id);
253   slice_tracker->End(140, track_1, StringId::Raw(1), StringId::Raw(1));
254 
255   // flow step inside slice2 on track2
256   slice_tracker->Begin(160, track_2, StringId::Raw(2), StringId::Raw(2));
257   SliceId inout_slice2_id =
258       slice_tracker->GetTopmostSliceOnTrack(track_2).value();
259   tracker.Step(track_2, flow_id);
260   slice_tracker->End(170, track_2, StringId::Raw(2), StringId::Raw(2));
261 
262   // flow end inside slice3 on track3
263   slice_tracker->Begin(180, track_1, StringId::Raw(3), StringId::Raw(3));
264   SliceId in_slice_id = slice_tracker->GetTopmostSliceOnTrack(track_1).value();
265   tracker.End(track_1, flow_id, /* bind_enclosing = */ true,
266               /* close_flow = */ false);
267   slice_tracker->End(190, track_1, StringId::Raw(3), StringId::Raw(3));
268 
269   const auto& flows = context_.storage->flow_table();
270   EXPECT_EQ(flows.row_count(), 2u);
271   EXPECT_EQ(flows.slice_out()[0], out_slice1_id);
272   EXPECT_EQ(flows.slice_in()[0], inout_slice2_id);
273   EXPECT_EQ(flows.slice_out()[1], inout_slice2_id);
274   EXPECT_EQ(flows.slice_in()[1], in_slice_id);
275 }
276 
277 }  // namespace
278 }  // namespace trace_processor
279 }  // namespace perfetto
280