• 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/flow_tracker.h"
20 #include "src/trace_processor/importers/common/slice_tracker.h"
21 #include "src/trace_processor/importers/common/slice_translation_table.h"
22 #include "src/trace_processor/storage/trace_storage.h"
23 #include "src/trace_processor/types/trace_processor_context.h"
24 #include "test/gtest_and_gmock.h"
25 
26 namespace perfetto {
27 namespace trace_processor {
28 namespace {
29 
30 using ::testing::Eq;
31 
TEST(FlowTrackerTest,SingleFlowEventExplicitInSliceBinding)32 TEST(FlowTrackerTest, SingleFlowEventExplicitInSliceBinding) {
33   TraceProcessorContext context;
34   context.storage.reset(new TraceStorage());
35   context.slice_tracker.reset(new SliceTracker(&context));
36   context.slice_translation_table.reset(
37       new SliceTranslationTable(context.storage.get()));
38   auto& slice_tracker = context.slice_tracker;
39   FlowTracker tracker(&context);
40   slice_tracker->SetOnSliceBeginCallback(
41       [&tracker](TrackId track_id, SliceId slice_id) {
42         tracker.ClosePendingEventsOnTrack(track_id, slice_id);
43       });
44 
45   FlowId flow_id = 1;
46   TrackId track_1(1);
47   TrackId track_2(2);
48 
49   slice_tracker->Begin(100, track_1, StringId::Raw(1), StringId::Raw(1));
50   SliceId out_slice_id = slice_tracker->GetTopmostSliceOnTrack(track_1).value();
51   tracker.Begin(track_1, flow_id);
52   slice_tracker->End(120, track_1, StringId::Raw(1), StringId::Raw(1));
53 
54   slice_tracker->Begin(140, track_2, StringId::Raw(2), StringId::Raw(2));
55   SliceId in_slice_id = slice_tracker->GetTopmostSliceOnTrack(track_2).value();
56   tracker.End(track_2, flow_id, /* bind_enclosing = */ true,
57               /* close_flow = */ false);
58   slice_tracker->End(160, track_2, StringId::Raw(2), StringId::Raw(2));
59 
60   const auto& flows = context.storage->flow_table();
61   EXPECT_EQ(flows.row_count(), 1u);
62   EXPECT_EQ(flows.slice_out()[0], out_slice_id);
63   EXPECT_EQ(flows.slice_in()[0], in_slice_id);
64 }
65 
TEST(FlowTrackerTest,SingleFlowEventWaitForNextSlice)66 TEST(FlowTrackerTest, SingleFlowEventWaitForNextSlice) {
67   TraceProcessorContext context;
68   context.storage.reset(new TraceStorage());
69   context.slice_tracker.reset(new SliceTracker(&context));
70   context.slice_translation_table.reset(
71       new SliceTranslationTable(context.storage.get()));
72   auto& slice_tracker = context.slice_tracker;
73   FlowTracker tracker(&context);
74   slice_tracker->SetOnSliceBeginCallback(
75       [&tracker](TrackId track_id, SliceId slice_id) {
76         tracker.ClosePendingEventsOnTrack(track_id, slice_id);
77       });
78 
79   FlowId flow_id = 1;
80   TrackId track_1(1);
81   TrackId track_2(2);
82 
83   slice_tracker->Begin(100, track_1, StringId::Raw(1), StringId::Raw(1));
84   SliceId out_slice_id = slice_tracker->GetTopmostSliceOnTrack(track_1).value();
85   tracker.Begin(track_1, flow_id);
86   slice_tracker->End(120, track_1, StringId::Raw(1), StringId::Raw(1));
87 
88   tracker.End(track_2, flow_id, /* bind_enclosing = */ false,
89               /* close_flow = */ false);
90 
91   const auto& flows = context.storage->flow_table();
92 
93   EXPECT_EQ(flows.row_count(), 0u);
94 
95   slice_tracker->Begin(140, track_2, StringId::Raw(2), StringId::Raw(2));
96   SliceId in_slice_id = slice_tracker->GetTopmostSliceOnTrack(track_2).value();
97   slice_tracker->End(160, track_2, StringId::Raw(2), StringId::Raw(2));
98 
99   EXPECT_EQ(flows.row_count(), 1u);
100   EXPECT_EQ(flows.slice_out()[0], out_slice_id);
101   EXPECT_EQ(flows.slice_in()[0], in_slice_id);
102 }
103 
TEST(FlowTrackerTest,SingleFlowEventWaitForNextSliceScoped)104 TEST(FlowTrackerTest, SingleFlowEventWaitForNextSliceScoped) {
105   TraceProcessorContext context;
106   context.storage.reset(new TraceStorage());
107   context.slice_tracker.reset(new SliceTracker(&context));
108   context.slice_translation_table.reset(
109       new SliceTranslationTable(context.storage.get()));
110   auto& slice_tracker = context.slice_tracker;
111   FlowTracker tracker(&context);
112   slice_tracker->SetOnSliceBeginCallback(
113       [&tracker](TrackId track_id, SliceId slice_id) {
114         tracker.ClosePendingEventsOnTrack(track_id, slice_id);
115       });
116 
117   FlowId flow_id = 1;
118   TrackId track_1(1);
119   TrackId track_2(2);
120 
121   slice_tracker->Begin(100, track_1, StringId::Raw(1), StringId::Raw(1));
122   SliceId out_slice_id = slice_tracker->GetTopmostSliceOnTrack(track_1).value();
123   tracker.Begin(track_1, flow_id);
124   slice_tracker->End(120, track_1, StringId::Raw(1), StringId::Raw(1));
125 
126   tracker.End(track_2, flow_id, /* bind_enclosing = */ false,
127               /* close_flow = */ false);
128 
129   const auto& flows = context.storage->flow_table();
130 
131   EXPECT_EQ(flows.row_count(), 0u);
132 
133   slice_tracker->Scoped(140, track_2, StringId::Raw(2), StringId::Raw(2), 100);
134   SliceId in_slice_id = slice_tracker->GetTopmostSliceOnTrack(track_2).value();
135 
136   EXPECT_EQ(flows.row_count(), 1u);
137   EXPECT_EQ(flows.slice_out()[0], out_slice_id);
138   EXPECT_EQ(flows.slice_in()[0], in_slice_id);
139 }
140 
TEST(FlowTrackerTest,TwoFlowEventsWaitForNextSlice)141 TEST(FlowTrackerTest, TwoFlowEventsWaitForNextSlice) {
142   TraceProcessorContext context;
143   context.storage.reset(new TraceStorage());
144   context.slice_tracker.reset(new SliceTracker(&context));
145   context.slice_translation_table.reset(
146       new SliceTranslationTable(context.storage.get()));
147   auto& slice_tracker = context.slice_tracker;
148   FlowTracker tracker(&context);
149   slice_tracker->SetOnSliceBeginCallback(
150       [&tracker](TrackId track_id, SliceId slice_id) {
151         tracker.ClosePendingEventsOnTrack(track_id, slice_id);
152       });
153 
154   FlowId flow1_id = 1;
155   FlowId flow2_id = 2;
156   TrackId track_1(1);
157   TrackId track_2(2);
158 
159   // begin flow1 in enclosing slice1
160   slice_tracker->Begin(100, track_1, StringId::Raw(1), StringId::Raw(1));
161   SliceId out_slice1_id =
162       slice_tracker->GetTopmostSliceOnTrack(track_1).value();
163   tracker.Begin(track_1, flow1_id);
164   tracker.End(track_2, flow1_id, /* bind_enclosing = */ false,
165               /* close_flow = */ false);
166   slice_tracker->End(120, track_1, StringId::Raw(1), StringId::Raw(1));
167 
168   // begin flow2 in enclosing slice2
169   slice_tracker->Begin(130, track_1, StringId::Raw(2), StringId::Raw(2));
170   SliceId out_slice2_id =
171       slice_tracker->GetTopmostSliceOnTrack(track_1).value();
172   tracker.Begin(track_1, flow2_id);
173   tracker.End(track_2, flow2_id, /* bind_enclosing = */ false,
174               /* close_flow = */ false);
175   slice_tracker->End(140, track_1, StringId::Raw(2), StringId::Raw(2));
176 
177   const auto& flows = context.storage->flow_table();
178 
179   EXPECT_EQ(flows.row_count(), 0u);
180 
181   // close all pending flows
182   slice_tracker->Begin(160, track_2, StringId::Raw(3), StringId::Raw(3));
183   SliceId in_slice_id = slice_tracker->GetTopmostSliceOnTrack(track_2).value();
184   slice_tracker->End(170, track_2, StringId::Raw(3), StringId::Raw(3));
185 
186   EXPECT_EQ(flows.row_count(), 2u);
187   EXPECT_EQ(flows.slice_out()[0], out_slice1_id);
188   EXPECT_EQ(flows.slice_in()[0], in_slice_id);
189   EXPECT_EQ(flows.slice_out()[1], out_slice2_id);
190   EXPECT_EQ(flows.slice_in()[1], in_slice_id);
191 }
192 
TEST(FlowTrackerTest,TwoFlowEventsSliceInSlice)193 TEST(FlowTrackerTest, TwoFlowEventsSliceInSlice) {
194   TraceProcessorContext context;
195   context.storage.reset(new TraceStorage());
196   context.slice_tracker.reset(new SliceTracker(&context));
197   context.slice_translation_table.reset(
198       new SliceTranslationTable(context.storage.get()));
199   auto& slice_tracker = context.slice_tracker;
200   FlowTracker tracker(&context);
201   slice_tracker->SetOnSliceBeginCallback(
202       [&tracker](TrackId track_id, SliceId slice_id) {
203         tracker.ClosePendingEventsOnTrack(track_id, slice_id);
204       });
205 
206   FlowId flow1_id = 1;
207   FlowId flow2_id = 2;
208   TrackId track_1(1);
209   TrackId track_2(2);
210 
211   // start two nested slices
212   slice_tracker->Begin(100, track_1, StringId::Raw(1), StringId::Raw(1));
213   SliceId out_slice1_id =
214       slice_tracker->GetTopmostSliceOnTrack(track_1).value();
215   slice_tracker->Begin(120, track_1, StringId::Raw(2), StringId::Raw(2));
216   SliceId out_slice2_id =
217       slice_tracker->GetTopmostSliceOnTrack(track_1).value();
218 
219   tracker.Begin(track_1, flow1_id);
220 
221   slice_tracker->End(140, track_1, StringId::Raw(2), StringId::Raw(2));
222 
223   tracker.Begin(track_1, flow2_id);
224 
225   slice_tracker->End(150, track_1, StringId::Raw(1), StringId::Raw(1));
226 
227   slice_tracker->Begin(160, track_2, StringId::Raw(3), StringId::Raw(3));
228   SliceId in_slice_id = slice_tracker->GetTopmostSliceOnTrack(track_2).value();
229 
230   tracker.End(track_2, flow1_id, /* bind_enclosing = */ true,
231               /* close_flow = */ false);
232   tracker.End(track_2, flow2_id, /* bind_enclosing = */ true,
233               /* close_flow = */ false);
234 
235   slice_tracker->End(170, track_2, StringId::Raw(3), StringId::Raw(3));
236 
237   const auto& flows = context.storage->flow_table();
238   EXPECT_EQ(flows.row_count(), 2u);
239   EXPECT_EQ(flows.slice_out()[0], out_slice2_id);
240   EXPECT_EQ(flows.slice_in()[0], in_slice_id);
241   EXPECT_EQ(flows.slice_out()[1], out_slice1_id);
242   EXPECT_EQ(flows.slice_in()[1], in_slice_id);
243 }
244 
TEST(FlowTrackerTest,FlowEventsWithStep)245 TEST(FlowTrackerTest, FlowEventsWithStep) {
246   TraceProcessorContext context;
247   context.storage.reset(new TraceStorage());
248   context.slice_tracker.reset(new SliceTracker(&context));
249   context.slice_translation_table.reset(
250       new SliceTranslationTable(context.storage.get()));
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   EXPECT_EQ(flows.slice_out()[0], out_slice1_id);
286   EXPECT_EQ(flows.slice_in()[0], inout_slice2_id);
287   EXPECT_EQ(flows.slice_out()[1], inout_slice2_id);
288   EXPECT_EQ(flows.slice_in()[1], in_slice_id);
289 }
290 
291 }  // namespace
292 }  // namespace trace_processor
293 }  // namespace perfetto
294