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