• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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 #include "src/trace_processor/importers/proto/proto_trace_parser.h"
17 
18 #include <map>
19 #include <random>
20 #include <vector>
21 
22 #include "perfetto/trace_processor/basic_types.h"
23 #include "src/trace_processor/timestamped_trace_piece.h"
24 #include "src/trace_processor/trace_sorter.h"
25 #include "src/trace_processor/types/trace_processor_context.h"
26 #include "test/gtest_and_gmock.h"
27 
28 namespace perfetto {
29 namespace trace_processor {
30 namespace {
31 
32 using ::testing::_;
33 using ::testing::InSequence;
34 using ::testing::Invoke;
35 using ::testing::MockFunction;
36 using ::testing::NiceMock;
37 
38 class MockTraceParser : public ProtoTraceParser {
39  public:
MockTraceParser(TraceProcessorContext * context)40   MockTraceParser(TraceProcessorContext* context) : ProtoTraceParser(context) {}
41 
42   MOCK_METHOD4(MOCK_ParseFtracePacket,
43                void(uint32_t cpu,
44                     int64_t timestamp,
45                     const uint8_t* data,
46                     size_t length));
47 
ParseFtracePacket(uint32_t cpu,int64_t timestamp,TimestampedTracePiece ttp)48   void ParseFtracePacket(uint32_t cpu,
49                          int64_t timestamp,
50                          TimestampedTracePiece ttp) override {
51     bool isNonCompact = ttp.type == TimestampedTracePiece::Type::kFtraceEvent;
52     MOCK_ParseFtracePacket(cpu, timestamp,
53                            isNonCompact ? ttp.ftrace_event.data() : nullptr,
54                            isNonCompact ? ttp.ftrace_event.length() : 0);
55   }
56 
57   MOCK_METHOD3(MOCK_ParseTracePacket,
58                void(int64_t ts, const uint8_t* data, size_t length));
59 
ParseTracePacket(int64_t ts,TimestampedTracePiece ttp)60   void ParseTracePacket(int64_t ts, TimestampedTracePiece ttp) override {
61     TraceBlobView& tbv = ttp.packet_data.packet;
62     MOCK_ParseTracePacket(ts, tbv.data(), tbv.length());
63   }
64 };
65 
66 class MockTraceStorage : public TraceStorage {
67  public:
MockTraceStorage()68   MockTraceStorage() : TraceStorage() {}
69 
70   MOCK_METHOD1(InternString, StringId(base::StringView view));
71 };
72 
73 class TraceSorterTest : public ::testing::Test {
74  public:
TraceSorterTest()75   TraceSorterTest()
76       : test_buffer_(std::unique_ptr<uint8_t[]>(new uint8_t[8]), 0, 8) {
77     storage_ = new NiceMock<MockTraceStorage>();
78     context_.storage.reset(storage_);
79 
80     std::unique_ptr<MockTraceParser> parser(new MockTraceParser(&context_));
81     parser_ = parser.get();
82 
83     context_.sorter.reset(
84         new TraceSorter(std::move(parser),
85                         std::numeric_limits<int64_t>::max() /*window_size*/));
86   }
87 
88  protected:
89   TraceProcessorContext context_;
90   MockTraceParser* parser_;
91   NiceMock<MockTraceStorage>* storage_;
92   TraceBlobView test_buffer_;
93 };
94 
TEST_F(TraceSorterTest,TestFtrace)95 TEST_F(TraceSorterTest, TestFtrace) {
96   TraceBlobView view = test_buffer_.slice(0, 1);
97   EXPECT_CALL(*parser_, MOCK_ParseFtracePacket(0, 1000, view.data(), 1));
98   context_.sorter->PushFtraceEvent(0 /*cpu*/, 1000 /*timestamp*/,
99                                    std::move(view));
100   context_.sorter->FinalizeFtraceEventBatch(0);
101   context_.sorter->ExtractEventsForced();
102 }
103 
TEST_F(TraceSorterTest,TestTracePacket)104 TEST_F(TraceSorterTest, TestTracePacket) {
105   PacketSequenceState state(&context_);
106   TraceBlobView view = test_buffer_.slice(0, 1);
107   EXPECT_CALL(*parser_, MOCK_ParseTracePacket(1000, view.data(), 1));
108   context_.sorter->PushTracePacket(1000, &state, std::move(view));
109   context_.sorter->FinalizeFtraceEventBatch(1000);
110   context_.sorter->ExtractEventsForced();
111 }
112 
TEST_F(TraceSorterTest,Ordering)113 TEST_F(TraceSorterTest, Ordering) {
114   PacketSequenceState state(&context_);
115   TraceBlobView view_1 = test_buffer_.slice(0, 1);
116   TraceBlobView view_2 = test_buffer_.slice(0, 2);
117   TraceBlobView view_3 = test_buffer_.slice(0, 3);
118   TraceBlobView view_4 = test_buffer_.slice(0, 4);
119 
120   InSequence s;
121 
122   EXPECT_CALL(*parser_, MOCK_ParseFtracePacket(0, 1000, view_1.data(), 1));
123   EXPECT_CALL(*parser_, MOCK_ParseTracePacket(1001, view_2.data(), 2));
124   EXPECT_CALL(*parser_, MOCK_ParseTracePacket(1100, view_3.data(), 3));
125   EXPECT_CALL(*parser_, MOCK_ParseFtracePacket(2, 1200, view_4.data(), 4));
126 
127   context_.sorter->SetWindowSizeNs(200);
128   context_.sorter->PushFtraceEvent(2 /*cpu*/, 1200 /*timestamp*/,
129                                    std::move(view_4));
130   context_.sorter->FinalizeFtraceEventBatch(2);
131   context_.sorter->PushTracePacket(1001, &state, std::move(view_2));
132   context_.sorter->PushTracePacket(1100, &state, std::move(view_3));
133   context_.sorter->PushFtraceEvent(0 /*cpu*/, 1000 /*timestamp*/,
134                                    std::move(view_1));
135 
136   context_.sorter->FinalizeFtraceEventBatch(0);
137   context_.sorter->ExtractEventsForced();
138 }
139 
TEST_F(TraceSorterTest,SetWindowSize)140 TEST_F(TraceSorterTest, SetWindowSize) {
141   PacketSequenceState state(&context_);
142   TraceBlobView view_1 = test_buffer_.slice(0, 1);
143   TraceBlobView view_2 = test_buffer_.slice(0, 2);
144   TraceBlobView view_3 = test_buffer_.slice(0, 3);
145   TraceBlobView view_4 = test_buffer_.slice(0, 4);
146 
147   MockFunction<void(std::string check_point_name)> check;
148 
149   {
150     InSequence s;
151 
152     EXPECT_CALL(*parser_, MOCK_ParseFtracePacket(0, 1000, view_1.data(), 1));
153     EXPECT_CALL(*parser_, MOCK_ParseTracePacket(1001, view_2.data(), 2));
154     EXPECT_CALL(check, Call("1"));
155     EXPECT_CALL(*parser_, MOCK_ParseTracePacket(1100, view_3.data(), 3));
156     EXPECT_CALL(check, Call("2"));
157     EXPECT_CALL(*parser_, MOCK_ParseFtracePacket(2, 1200, view_4.data(), 4));
158   }
159 
160   context_.sorter->SetWindowSizeNs(200);
161   context_.sorter->PushFtraceEvent(2 /*cpu*/, 1200 /*timestamp*/,
162                                    std::move(view_4));
163   context_.sorter->FinalizeFtraceEventBatch(2);
164   context_.sorter->PushTracePacket(1001, &state, std::move(view_2));
165   context_.sorter->PushTracePacket(1100, &state, std::move(view_3));
166 
167   context_.sorter->PushFtraceEvent(0 /*cpu*/, 1000 /*timestamp*/,
168                                    std::move(view_1));
169   context_.sorter->FinalizeFtraceEventBatch(0);
170 
171   // At this point, we should just flush the 1000 and 1001 packets.
172   context_.sorter->SetWindowSizeNs(101);
173 
174   // Inform the mock about where we are.
175   check.Call("1");
176 
177   // Now we should flush the 1100 packet.
178   context_.sorter->SetWindowSizeNs(99);
179 
180   // Inform the mock about where we are.
181   check.Call("2");
182 
183   // Now we should flush the 1200 packet.
184   context_.sorter->ExtractEventsForced();
185 }
186 
187 // Simulates a random stream of ftrace events happening on random CPUs.
188 // Tests that the output of the TraceSorter matches the timestamp order
189 // (% events happening at the same time on different CPUs).
TEST_F(TraceSorterTest,MultiQueueSorting)190 TEST_F(TraceSorterTest, MultiQueueSorting) {
191   std::minstd_rand0 rnd_engine(0);
192   std::map<int64_t /*ts*/, std::vector<uint32_t /*cpu*/>> expectations;
193 
194   EXPECT_CALL(*parser_, MOCK_ParseFtracePacket(_, _, _, _))
195       .WillRepeatedly(Invoke([&expectations](uint32_t cpu, int64_t timestamp,
196                                              const uint8_t*, size_t) {
197         EXPECT_EQ(expectations.begin()->first, timestamp);
198         auto& cpus = expectations.begin()->second;
199         bool cpu_found = false;
200         for (auto it = cpus.begin(); it < cpus.end(); it++) {
201           if (*it != cpu)
202             continue;
203           cpu_found = true;
204           cpus.erase(it);
205           break;
206         }
207         if (cpus.empty())
208           expectations.erase(expectations.begin());
209         EXPECT_TRUE(cpu_found);
210       }));
211 
212   for (int i = 0; i < 1000; i++) {
213     int64_t ts = abs(static_cast<int64_t>(rnd_engine()));
214     int num_cpus = rnd_engine() % 3;
215     for (int j = 0; j < num_cpus; j++) {
216       uint32_t cpu = static_cast<uint32_t>(rnd_engine() % 32);
217       expectations[ts].push_back(cpu);
218       context_.sorter->PushFtraceEvent(cpu, ts, TraceBlobView(nullptr, 0, 0));
219       context_.sorter->FinalizeFtraceEventBatch(cpu);
220     }
221   }
222 
223   context_.sorter->ExtractEventsForced();
224   EXPECT_TRUE(expectations.empty());
225 }
226 
227 }  // namespace
228 }  // namespace trace_processor
229 }  // namespace perfetto
230