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(
53         cpu, timestamp, isNonCompact ? ttp.ftrace_event.event.data() : nullptr,
54         isNonCompact ? ttp.ftrace_event.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   PacketSequenceState state(&context_);
97   TraceBlobView view = test_buffer_.slice(0, 1);
98   EXPECT_CALL(*parser_, MOCK_ParseFtracePacket(0, 1000, view.data(), 1));
99   context_.sorter->PushFtraceEvent(0 /*cpu*/, 1000 /*timestamp*/,
100                                    std::move(view), &state);
101   context_.sorter->FinalizeFtraceEventBatch(0);
102   context_.sorter->ExtractEventsForced();
103 }
104 
TEST_F(TraceSorterTest,TestTracePacket)105 TEST_F(TraceSorterTest, TestTracePacket) {
106   PacketSequenceState state(&context_);
107   TraceBlobView view = test_buffer_.slice(0, 1);
108   EXPECT_CALL(*parser_, MOCK_ParseTracePacket(1000, view.data(), 1));
109   context_.sorter->PushTracePacket(1000, &state, std::move(view));
110   context_.sorter->FinalizeFtraceEventBatch(1000);
111   context_.sorter->ExtractEventsForced();
112 }
113 
TEST_F(TraceSorterTest,Ordering)114 TEST_F(TraceSorterTest, Ordering) {
115   PacketSequenceState state(&context_);
116   TraceBlobView view_1 = test_buffer_.slice(0, 1);
117   TraceBlobView view_2 = test_buffer_.slice(0, 2);
118   TraceBlobView view_3 = test_buffer_.slice(0, 3);
119   TraceBlobView view_4 = test_buffer_.slice(0, 4);
120 
121   InSequence s;
122 
123   EXPECT_CALL(*parser_, MOCK_ParseFtracePacket(0, 1000, view_1.data(), 1));
124   EXPECT_CALL(*parser_, MOCK_ParseTracePacket(1001, view_2.data(), 2));
125   EXPECT_CALL(*parser_, MOCK_ParseTracePacket(1100, view_3.data(), 3));
126   EXPECT_CALL(*parser_, MOCK_ParseFtracePacket(2, 1200, view_4.data(), 4));
127 
128   context_.sorter->SetWindowSizeNs(200);
129   context_.sorter->PushFtraceEvent(2 /*cpu*/, 1200 /*timestamp*/,
130                                    std::move(view_4), &state);
131   context_.sorter->FinalizeFtraceEventBatch(2);
132   context_.sorter->PushTracePacket(1001, &state, std::move(view_2));
133   context_.sorter->PushTracePacket(1100, &state, std::move(view_3));
134   context_.sorter->PushFtraceEvent(0 /*cpu*/, 1000 /*timestamp*/,
135                                    std::move(view_1), &state);
136 
137   context_.sorter->FinalizeFtraceEventBatch(0);
138   context_.sorter->ExtractEventsForced();
139 }
140 
TEST_F(TraceSorterTest,SetWindowSize)141 TEST_F(TraceSorterTest, SetWindowSize) {
142   PacketSequenceState state(&context_);
143   TraceBlobView view_1 = test_buffer_.slice(0, 1);
144   TraceBlobView view_2 = test_buffer_.slice(0, 2);
145   TraceBlobView view_3 = test_buffer_.slice(0, 3);
146   TraceBlobView view_4 = test_buffer_.slice(0, 4);
147 
148   MockFunction<void(std::string check_point_name)> check;
149 
150   {
151     InSequence s;
152 
153     EXPECT_CALL(*parser_, MOCK_ParseFtracePacket(0, 1000, view_1.data(), 1));
154     EXPECT_CALL(*parser_, MOCK_ParseTracePacket(1001, view_2.data(), 2));
155     EXPECT_CALL(check, Call("1"));
156     EXPECT_CALL(*parser_, MOCK_ParseTracePacket(1100, view_3.data(), 3));
157     EXPECT_CALL(check, Call("2"));
158     EXPECT_CALL(*parser_, MOCK_ParseFtracePacket(2, 1200, view_4.data(), 4));
159   }
160 
161   context_.sorter->SetWindowSizeNs(200);
162   context_.sorter->PushFtraceEvent(2 /*cpu*/, 1200 /*timestamp*/,
163                                    std::move(view_4), &state);
164   context_.sorter->FinalizeFtraceEventBatch(2);
165   context_.sorter->PushTracePacket(1001, &state, std::move(view_2));
166   context_.sorter->PushTracePacket(1100, &state, std::move(view_3));
167 
168   context_.sorter->PushFtraceEvent(0 /*cpu*/, 1000 /*timestamp*/,
169                                    std::move(view_1), &state);
170   context_.sorter->FinalizeFtraceEventBatch(0);
171 
172   // At this point, we should just flush the 1000 and 1001 packets.
173   context_.sorter->SetWindowSizeNs(101);
174 
175   // Inform the mock about where we are.
176   check.Call("1");
177 
178   // Now we should flush the 1100 packet.
179   context_.sorter->SetWindowSizeNs(99);
180 
181   // Inform the mock about where we are.
182   check.Call("2");
183 
184   // Now we should flush the 1200 packet.
185   context_.sorter->ExtractEventsForced();
186 }
187 
188 // Simulates a random stream of ftrace events happening on random CPUs.
189 // Tests that the output of the TraceSorter matches the timestamp order
190 // (% events happening at the same time on different CPUs).
TEST_F(TraceSorterTest,MultiQueueSorting)191 TEST_F(TraceSorterTest, MultiQueueSorting) {
192   PacketSequenceState state(&context_);
193   std::minstd_rand0 rnd_engine(0);
194   std::map<int64_t /*ts*/, std::vector<uint32_t /*cpu*/>> expectations;
195 
196   EXPECT_CALL(*parser_, MOCK_ParseFtracePacket(_, _, _, _))
197       .WillRepeatedly(Invoke([&expectations](uint32_t cpu, int64_t timestamp,
198                                              const uint8_t*, size_t) {
199         EXPECT_EQ(expectations.begin()->first, timestamp);
200         auto& cpus = expectations.begin()->second;
201         bool cpu_found = false;
202         for (auto it = cpus.begin(); it < cpus.end(); it++) {
203           if (*it != cpu)
204             continue;
205           cpu_found = true;
206           cpus.erase(it);
207           break;
208         }
209         if (cpus.empty())
210           expectations.erase(expectations.begin());
211         EXPECT_TRUE(cpu_found);
212       }));
213 
214   for (int i = 0; i < 1000; i++) {
215     int64_t ts = abs(static_cast<int64_t>(rnd_engine()));
216     int num_cpus = rnd_engine() % 3;
217     for (int j = 0; j < num_cpus; j++) {
218       uint32_t cpu = static_cast<uint32_t>(rnd_engine() % 32);
219       expectations[ts].push_back(cpu);
220       context_.sorter->PushFtraceEvent(cpu, ts, TraceBlobView(nullptr, 0, 0),
221                                        &state);
222       context_.sorter->FinalizeFtraceEventBatch(cpu);
223     }
224   }
225 
226   context_.sorter->ExtractEventsForced();
227   EXPECT_TRUE(expectations.empty());
228 }
229 
230 }  // namespace
231 }  // namespace trace_processor
232 }  // namespace perfetto
233