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