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
17 #include "RecordReadThread.h"
18
19 #include <gmock/gmock.h>
20 #include <gtest/gtest.h>
21
22 #include "event_type.h"
23 #include "get_test_data.h"
24 #include "record.h"
25 #include "record_equal_test.h"
26 #include "record_file.h"
27
28 using ::testing::_;
29 using ::testing::Eq;
30 using ::testing::Return;
31 using ::testing::Truly;
32
33 using namespace simpleperf;
34
35 class RecordBufferTest : public ::testing::Test {
36 protected:
PushRecord(uint32_t type,size_t size)37 void PushRecord(uint32_t type, size_t size) {
38 char* p = buffer_->AllocWriteSpace(size);
39 ASSERT_NE(p, nullptr);
40 perf_event_header header;
41 header.type = type;
42 header.size = size;
43 memcpy(p, &header, sizeof(header));
44 buffer_->FinishWrite();
45 }
46
PopRecord(uint32_t type,uint32_t size)47 void PopRecord(uint32_t type, uint32_t size) {
48 char* p = buffer_->GetCurrentRecord();
49 ASSERT_NE(p, nullptr);
50 perf_event_header header;
51 memcpy(&header, p, sizeof(header));
52 ASSERT_EQ(header.type, type);
53 ASSERT_EQ(header.size, size);
54 buffer_->MoveToNextRecord();
55 }
56
57 std::unique_ptr<RecordBuffer> buffer_;
58 };
59
TEST_F(RecordBufferTest,fifo)60 TEST_F(RecordBufferTest, fifo) {
61 for (size_t loop = 0; loop < 10; ++loop) {
62 buffer_.reset(new RecordBuffer(sizeof(perf_event_header) * 10));
63 size_t record_size = sizeof(perf_event_header) + loop;
64 size_t max_records_in_buffer = (buffer_->size() - 2 * record_size + 1) / record_size;
65 uint32_t write_id = 0;
66 uint32_t read_id = 0;
67 while (read_id < 100) {
68 while (write_id < 100 && write_id - read_id < max_records_in_buffer) {
69 ASSERT_NO_FATAL_FAILURE(PushRecord(write_id++, record_size));
70 }
71 ASSERT_NO_FATAL_FAILURE(PopRecord(read_id++, record_size));
72 }
73 }
74 }
75
TEST(RecordParser,smoke)76 TEST(RecordParser, smoke) {
77 std::unique_ptr<RecordFileReader> reader =
78 RecordFileReader::CreateInstance(GetTestData(PERF_DATA_NO_UNWIND));
79 ASSERT_TRUE(reader);
80 RecordParser parser(*reader->AttrSection()[0].attr);
81 auto process_record = [&](std::unique_ptr<Record> record) {
82 if (record->type() == PERF_RECORD_MMAP || record->type() == PERF_RECORD_COMM ||
83 record->type() == PERF_RECORD_FORK || record->type() == PERF_RECORD_SAMPLE) {
84 perf_event_header header;
85 memcpy(&header, record->Binary(), sizeof(header));
86 auto read_record_fn = [&](size_t pos, size_t size, void* dest) {
87 memcpy(dest, record->Binary() + pos, size);
88 };
89 size_t pos = parser.GetTimePos(header);
90 ASSERT_NE(0u, pos);
91 uint64_t time;
92 read_record_fn(pos, sizeof(time), &time);
93 ASSERT_EQ(record->Timestamp(), time);
94 if (record->type() == PERF_RECORD_SAMPLE) {
95 auto sr = static_cast<SampleRecord*>(record.get());
96 pos = parser.GetStackSizePos(read_record_fn);
97 ASSERT_NE(0u, pos);
98 uint64_t stack_size;
99 read_record_fn(pos, sizeof(stack_size), &stack_size);
100 ASSERT_EQ(sr->stack_user_data.size, stack_size);
101
102 // Test pid pos in sample records.
103 pos = parser.GetPidPosInSampleRecord();
104 uint32_t pid;
105 read_record_fn(pos, sizeof(pid), &pid);
106 ASSERT_EQ(sr->tid_data.pid, pid);
107 }
108 }
109 };
110 ASSERT_TRUE(reader->ReadDataSection([&](std::unique_ptr<Record> record) {
111 process_record(std::move(record));
112 return !HasFatalFailure();
113 }));
114 }
115
116 struct MockEventFd : public EventFd {
MockEventFdMockEventFd117 MockEventFd(const perf_event_attr& attr, int cpu, char* buffer, size_t buffer_size,
118 bool mock_aux_buffer)
119 : EventFd(attr, -1, "", 0, cpu) {
120 mmap_data_buffer_ = buffer;
121 mmap_data_buffer_size_ = buffer_size;
122 if (mock_aux_buffer) {
123 aux_buffer_size_ = 1; // Make HasAuxBuffer() return true.
124 }
125 }
126
127 MOCK_METHOD2(CreateMappedBuffer, bool(size_t, bool));
128 MOCK_METHOD0(DestroyMappedBuffer, void());
129 MOCK_METHOD2(StartPolling, bool(IOEventLoop&, const std::function<bool()>&));
130 MOCK_METHOD0(StopPolling, bool());
131 MOCK_METHOD1(GetAvailableMmapDataSize, size_t(size_t&));
132 MOCK_METHOD1(DiscardMmapData, void(size_t));
133
134 MOCK_METHOD2(CreateAuxBuffer, bool(size_t, bool));
135 MOCK_METHOD0(DestroyAuxBuffer, void());
136 MOCK_METHOD4(GetAvailableAuxData, uint64_t(char**, size_t*, char**, size_t*));
137 MOCK_METHOD1(DiscardAuxData, void(size_t));
138 };
139
CreateFakeEventAttr()140 static perf_event_attr CreateFakeEventAttr() {
141 const EventType* type = FindEventTypeByName("cpu-clock");
142 CHECK(type != nullptr);
143 return CreateDefaultPerfEventAttr(*type);
144 }
145
CreateFakeRecords(const perf_event_attr & attr,size_t record_count,size_t stack_size,size_t dyn_stack_size)146 static std::vector<std::unique_ptr<Record>> CreateFakeRecords(const perf_event_attr& attr,
147 size_t record_count,
148 size_t stack_size,
149 size_t dyn_stack_size) {
150 std::vector<std::unique_ptr<Record>> records;
151 for (size_t i = 0; i < record_count; ++i) {
152 SampleRecord* r = new SampleRecord(attr, i, i + 1, i + 2, i + 3, i + 4, i + 5, i + 6, {},
153 std::vector<char>(stack_size), dyn_stack_size);
154 records.emplace_back(r);
155 }
156 return records;
157 }
158
AlignToPowerOfTwo(size_t value)159 static size_t AlignToPowerOfTwo(size_t value) {
160 size_t result = 1;
161 while (result < value) {
162 result <<= 1;
163 }
164 return result;
165 }
166
SetArg(size_t value)167 static inline std::function<bool(size_t&)> SetArg(size_t value) {
168 return [value](size_t& arg) {
169 arg = value;
170 return true;
171 };
172 }
173
TEST(KernelRecordReader,smoke)174 TEST(KernelRecordReader, smoke) {
175 // 1. Create fake records.
176 perf_event_attr attr = CreateFakeEventAttr();
177 std::vector<std::unique_ptr<Record>> records = CreateFakeRecords(attr, 10, 0, 0);
178 // 2. Create a buffer whose size is power of two.
179 size_t data_size = records.size() * records[0]->size();
180 std::vector<char> buffer(AlignToPowerOfTwo(data_size));
181 // 3. Copy record data into the buffer. Since a record in a kernel buffer can be wrapped around
182 // to the beginning of the buffer, create the case in the first record.
183 size_t data_pos = buffer.size() - 4;
184 memcpy(&buffer[data_pos], records[0]->Binary(), 4);
185 memcpy(&buffer[0], records[0]->Binary() + 4, records[0]->size() - 4);
186 size_t pos = records[0]->size() - 4;
187 for (size_t i = 1; i < records.size(); ++i) {
188 memcpy(&buffer[pos], records[i]->Binary(), records[i]->size());
189 pos += records[i]->size();
190 }
191 // Read records using KernelRecordReader.
192 MockEventFd event_fd(attr, 0, buffer.data(), buffer.size(), false);
193
194 EXPECT_CALL(event_fd, GetAvailableMmapDataSize(Truly(SetArg(data_pos))))
195 .Times(1)
196 .WillOnce(Return(data_size));
197 EXPECT_CALL(event_fd, DiscardMmapData(Eq(data_size))).Times(1);
198 KernelRecordReader reader(&event_fd);
199 RecordParser parser(attr);
200 ASSERT_TRUE(reader.GetDataFromKernelBuffer());
201 for (size_t i = 0; i < records.size(); ++i) {
202 ASSERT_TRUE(reader.MoveToNextRecord(parser));
203 ASSERT_EQ(reader.RecordHeader().type, records[i]->type());
204 ASSERT_EQ(reader.RecordHeader().size, records[i]->size());
205 ASSERT_EQ(reader.RecordTime(), records[i]->Timestamp());
206 std::vector<char> data(reader.RecordHeader().size);
207 reader.ReadRecord(0, data.size(), &data[0]);
208 ASSERT_EQ(0, memcmp(&data[0], records[i]->Binary(), records[i]->size()));
209 }
210 ASSERT_FALSE(reader.MoveToNextRecord(parser));
211 }
212
213 class RecordReadThreadTest : public ::testing::Test {
214 protected:
CreateFakeEventFds(const perf_event_attr & attr,size_t event_fd_count)215 std::vector<EventFd*> CreateFakeEventFds(const perf_event_attr& attr, size_t event_fd_count) {
216 size_t records_per_fd = records_.size() / event_fd_count;
217 buffers_.clear();
218 buffers_.resize(event_fd_count);
219 for (size_t i = 0; i < records_.size(); ++i) {
220 std::vector<char>& buffer = buffers_[i % event_fd_count];
221 buffer.insert(buffer.end(), records_[i]->Binary(),
222 records_[i]->Binary() + records_[i]->size());
223 }
224 size_t data_size = records_per_fd * records_[0]->size();
225 size_t buffer_size = AlignToPowerOfTwo(data_size);
226 for (auto& buffer : buffers_) {
227 buffer.resize(buffer_size);
228 }
229 event_fds_.resize(event_fd_count);
230 for (size_t i = 0; i < event_fd_count; ++i) {
231 event_fds_[i].reset(new MockEventFd(attr, i, buffers_[i].data(), buffer_size, false));
232 EXPECT_CALL(*event_fds_[i], CreateMappedBuffer(_, _)).Times(1).WillOnce(Return(true));
233 EXPECT_CALL(*event_fds_[i], StartPolling(_, _)).Times(1).WillOnce(Return(true));
234 EXPECT_CALL(*event_fds_[i], GetAvailableMmapDataSize(Truly(SetArg(0))))
235 .Times(1)
236 .WillOnce(Return(data_size));
237 EXPECT_CALL(*event_fds_[i], DiscardMmapData(Eq(data_size))).Times(1);
238 EXPECT_CALL(*event_fds_[i], StopPolling()).Times(1).WillOnce(Return(true));
239 EXPECT_CALL(*event_fds_[i], DestroyMappedBuffer()).Times(1);
240 EXPECT_CALL(*event_fds_[i], DestroyAuxBuffer()).Times(1);
241 }
242 std::vector<EventFd*> result;
243 for (auto& fd : event_fds_) {
244 result.push_back(fd.get());
245 }
246 return result;
247 }
248
249 std::vector<std::unique_ptr<Record>> records_;
250 std::vector<std::vector<char>> buffers_;
251 std::vector<std::unique_ptr<MockEventFd>> event_fds_;
252 };
253
TEST_F(RecordReadThreadTest,handle_cmds)254 TEST_F(RecordReadThreadTest, handle_cmds) {
255 perf_event_attr attr = CreateFakeEventAttr();
256 records_ = CreateFakeRecords(attr, 2, 0, 0);
257 std::vector<EventFd*> event_fds = CreateFakeEventFds(attr, 2);
258 RecordReadThread thread(128 * 1024, event_fds[0]->attr(), 1, 1, 0);
259 IOEventLoop loop;
260 bool has_notify = false;
261 auto callback = [&]() {
262 has_notify = true;
263 return loop.ExitLoop();
264 };
265 ASSERT_TRUE(thread.RegisterDataCallback(loop, callback));
266 ASSERT_TRUE(thread.AddEventFds(event_fds));
267 ASSERT_TRUE(thread.SyncKernelBuffer());
268 ASSERT_TRUE(loop.RunLoop());
269 ASSERT_TRUE(has_notify);
270 ASSERT_TRUE(thread.GetRecord());
271 ASSERT_TRUE(thread.RemoveEventFds(event_fds));
272 ASSERT_TRUE(thread.StopReadThread());
273 }
274
TEST_F(RecordReadThreadTest,read_records)275 TEST_F(RecordReadThreadTest, read_records) {
276 perf_event_attr attr = CreateFakeEventAttr();
277 RecordReadThread thread(128 * 1024, attr, 1, 1, 0);
278 IOEventLoop loop;
279 size_t record_index;
280 auto callback = [&]() {
281 while (true) {
282 std::unique_ptr<Record> r = thread.GetRecord();
283 if (!r) {
284 break;
285 }
286 std::unique_ptr<Record>& expected = records_[record_index++];
287 if (r->size() != expected->size() ||
288 memcmp(r->Binary(), expected->Binary(), r->size()) != 0) {
289 return false;
290 }
291 }
292 return loop.ExitLoop();
293 };
294 ASSERT_TRUE(thread.RegisterDataCallback(loop, callback));
295 for (size_t event_fd_count = 1; event_fd_count < 10; ++event_fd_count) {
296 records_ = CreateFakeRecords(attr, event_fd_count * 10, 0, 0);
297 std::vector<EventFd*> event_fds = CreateFakeEventFds(attr, event_fd_count);
298 record_index = 0;
299 ASSERT_TRUE(thread.AddEventFds(event_fds));
300 ASSERT_TRUE(thread.SyncKernelBuffer());
301 ASSERT_TRUE(loop.RunLoop());
302 ASSERT_EQ(record_index, records_.size());
303 ASSERT_TRUE(thread.RemoveEventFds(event_fds));
304 }
305 }
306
TEST_F(RecordReadThreadTest,process_sample_record)307 TEST_F(RecordReadThreadTest, process_sample_record) {
308 perf_event_attr attr = CreateFakeEventAttr();
309 attr.sample_type |= PERF_SAMPLE_STACK_USER;
310 attr.sample_stack_user = 64 * 1024;
311 size_t record_buffer_size = 128 * 1024;
312 RecordReadThread thread(record_buffer_size, attr, 1, 1, 0);
313 IOEventLoop loop;
314 ASSERT_TRUE(thread.RegisterDataCallback(loop, []() { return true; }));
315
316 auto read_record = [&](std::unique_ptr<Record>& r) {
317 std::vector<EventFd*> event_fds = CreateFakeEventFds(attr, 1);
318 ASSERT_TRUE(thread.AddEventFds(event_fds));
319 ASSERT_TRUE(thread.SyncKernelBuffer());
320 ASSERT_TRUE(thread.RemoveEventFds(event_fds));
321 r = thread.GetRecord();
322 };
323
324 // When the free space in record buffer is above low level, only invalid stack data in sample
325 // records is removed.
326 thread.SetBufferLevels(0, 0);
327 records_ = CreateFakeRecords(attr, 1, 8192, 8192);
328 std::unique_ptr<Record> r;
329 read_record(r);
330 ASSERT_TRUE(r);
331 SampleRecord* sr = static_cast<SampleRecord*>(r.get());
332 ASSERT_EQ(sr->stack_user_data.size, 8192u);
333 ASSERT_EQ(sr->stack_user_data.dyn_size, 8192u);
334 records_ = CreateFakeRecords(attr, 1, 8192, 4096);
335 read_record(r);
336 ASSERT_TRUE(r);
337 sr = static_cast<SampleRecord*>(r.get());
338 ASSERT_EQ(sr->stack_user_data.size, 4096u);
339 ASSERT_EQ(sr->stack_user_data.dyn_size, 4096u);
340
341 // When the free space in record buffer is below low level but above critical level, only
342 // 1K stack data in sample records is left.
343 thread.SetBufferLevels(record_buffer_size, 0);
344 read_record(r);
345 ASSERT_TRUE(r);
346 sr = static_cast<SampleRecord*>(r.get());
347 ASSERT_EQ(sr->stack_user_data.size, 1024u);
348 ASSERT_EQ(sr->stack_user_data.dyn_size, 1024u);
349
350 // When the free space in record buffer is below critical level, sample records are dropped.
351 thread.SetBufferLevels(record_buffer_size, record_buffer_size);
352 read_record(r);
353 ASSERT_FALSE(r);
354 ASSERT_EQ(thread.GetStat().lost_samples, 1u);
355 ASSERT_EQ(thread.GetStat().lost_non_samples, 0u);
356 ASSERT_EQ(thread.GetStat().cut_stack_samples, 1u);
357 }
358
359 // Test that the data notification exists until the RecordBuffer is empty. So we can read all
360 // records even if reading one record at a time.
TEST_F(RecordReadThreadTest,has_data_notification_until_buffer_empty)361 TEST_F(RecordReadThreadTest, has_data_notification_until_buffer_empty) {
362 perf_event_attr attr = CreateFakeEventAttr();
363 RecordReadThread thread(128 * 1024, attr, 1, 1, 0);
364 IOEventLoop loop;
365 size_t record_index = 0;
366 auto read_one_record = [&]() {
367 std::unique_ptr<Record> r = thread.GetRecord();
368 if (!r) {
369 return loop.ExitLoop();
370 }
371 std::unique_ptr<Record>& expected = records_[record_index++];
372 if (r->size() != expected->size() || memcmp(r->Binary(), expected->Binary(), r->size()) != 0) {
373 return false;
374 }
375 return true;
376 };
377 ASSERT_TRUE(thread.RegisterDataCallback(loop, read_one_record));
378 records_ = CreateFakeRecords(attr, 2, 0, 0);
379 std::vector<EventFd*> event_fds = CreateFakeEventFds(attr, 1);
380 ASSERT_TRUE(thread.AddEventFds(event_fds));
381 ASSERT_TRUE(thread.SyncKernelBuffer());
382 ASSERT_TRUE(loop.RunLoop());
383 ASSERT_EQ(record_index, records_.size());
384 ASSERT_TRUE(thread.RemoveEventFds(event_fds));
385 }
386
TEST_F(RecordReadThreadTest,no_cut_samples)387 TEST_F(RecordReadThreadTest, no_cut_samples) {
388 perf_event_attr attr = CreateFakeEventAttr();
389 attr.sample_type |= PERF_SAMPLE_STACK_USER;
390 attr.sample_stack_user = 64 * 1024;
391 RecordReadThread thread(128 * 1024, attr, 1, 1, 0, false);
392 IOEventLoop loop;
393 ASSERT_TRUE(thread.RegisterDataCallback(loop, []() { return true; }));
394 const size_t total_samples = 100;
395 records_ = CreateFakeRecords(attr, total_samples, 8 * 1024, 8 * 1024);
396 std::vector<EventFd*> event_fds = CreateFakeEventFds(attr, 1);
397 ASSERT_TRUE(thread.AddEventFds(event_fds));
398 ASSERT_TRUE(thread.SyncKernelBuffer());
399 ASSERT_TRUE(thread.RemoveEventFds(event_fds));
400 size_t received_samples = 0;
401 while (thread.GetRecord()) {
402 received_samples++;
403 }
404 ASSERT_GT(received_samples, 0u);
405 ASSERT_GT(thread.GetStat().lost_samples, 0u);
406 ASSERT_EQ(thread.GetStat().lost_samples, total_samples - received_samples);
407 ASSERT_EQ(thread.GetStat().cut_stack_samples, 0u);
408 }
409
TEST_F(RecordReadThreadTest,exclude_perf)410 TEST_F(RecordReadThreadTest, exclude_perf) {
411 perf_event_attr attr = CreateFakeEventAttr();
412 attr.sample_type |= PERF_SAMPLE_STACK_USER;
413 size_t stack_size = 1024;
414 attr.sample_stack_user = stack_size;
415 records_.emplace_back(new SampleRecord(attr, 0, 1, getpid(), 3, 4, 5, 6, {},
416 std::vector<char>(stack_size), stack_size));
417 records_.emplace_back(new SampleRecord(attr, 0, 1, getpid() + 1, 3, 4, 5, 6, {},
418 std::vector<char>(stack_size), stack_size));
419
420 auto read_records = [&](RecordReadThread& thread, std::vector<std::unique_ptr<Record>>& records) {
421 records.clear();
422 std::vector<EventFd*> event_fds = CreateFakeEventFds(attr, 1);
423 ASSERT_TRUE(thread.AddEventFds(event_fds));
424 ASSERT_TRUE(thread.SyncKernelBuffer());
425 ASSERT_TRUE(thread.RemoveEventFds(event_fds));
426 while (auto r = thread.GetRecord()) {
427 records.emplace_back(std::move(r));
428 }
429 };
430
431 // By default, no samples are excluded.
432 RecordReadThread thread(128 * 1024, attr, 1, 1, 0);
433 IOEventLoop loop;
434 ASSERT_TRUE(thread.RegisterDataCallback(loop, []() { return true; }));
435 std::vector<std::unique_ptr<Record>> received_records;
436 read_records(thread, received_records);
437 ASSERT_EQ(received_records.size(), 2);
438 CheckRecordEqual(*received_records[0], *records_[0]);
439 CheckRecordEqual(*received_records[1], *records_[1]);
440
441 // With exclude_perf, the first sample is excluded.
442 RecordReadThread thread2(128 * 1024, attr, 1, 1, 0, true, true);
443 ASSERT_TRUE(thread2.RegisterDataCallback(loop, []() { return true; }));
444 read_records(thread2, received_records);
445 ASSERT_EQ(received_records.size(), 1);
446 CheckRecordEqual(*received_records[0], *records_[1]);
447 }
448
449 struct FakeAuxData {
450 std::vector<char> buf1;
451 std::vector<char> buf2;
452 std::vector<char> pad;
453 bool lost;
454
FakeAuxDataFakeAuxData455 FakeAuxData(size_t buf1_size, size_t buf2_size, char c, size_t pad_size, bool lost)
456 : buf1(buf1_size, c), buf2(buf2_size, c), pad(pad_size, 0), lost(lost) {}
457 };
458
TEST_F(RecordReadThreadTest,read_aux_data)459 TEST_F(RecordReadThreadTest, read_aux_data) {
460 const EventType* type = FindEventTypeByName("cs-etm");
461 if (type == nullptr) {
462 GTEST_LOG_(INFO) << "Omit this test as cs-etm event type isn't available";
463 return;
464 }
465 std::vector<FakeAuxData> aux_data;
466 aux_data.emplace_back(40, 0, '0', 0, false); // one buffer
467 aux_data.emplace_back(40, 40, '1', 0, false); // two buffers
468 aux_data.emplace_back(36, 0, '2', 4, false); // one buffer needs padding to 8 bytes alignment
469 aux_data.emplace_back(1024, 0, '3', 0, true); // one buffer too big to fit into RecordReadThread
470 size_t test_index = 0;
471
472 auto SetBuf1 = [&](char** buf1) {
473 *buf1 = aux_data[test_index].buf1.data();
474 return true;
475 };
476 auto SetSize1 = [&](size_t* size1) {
477 *size1 = aux_data[test_index].buf1.size();
478 return true;
479 };
480 auto SetBuf2 = [&](char** buf2) {
481 *buf2 = aux_data[test_index].buf2.data();
482 return true;
483 };
484 auto SetSize2 = [&](size_t* size2) {
485 *size2 = aux_data[test_index].buf2.size();
486 return true;
487 };
488 auto CheckDiscardSize = [&](size_t size) {
489 return size == aux_data[test_index].buf1.size() + aux_data[test_index].buf2.size();
490 };
491
492 const size_t AUX_BUFFER_SIZE = 4096;
493
494 perf_event_attr attr = CreateDefaultPerfEventAttr(*type);
495 MockEventFd fd(attr, 0, nullptr, 1, true);
496 EXPECT_CALL(fd, CreateMappedBuffer(_, _)).Times(1).WillOnce(Return(true));
497 EXPECT_CALL(fd, CreateAuxBuffer(Eq(AUX_BUFFER_SIZE), _)).Times(1).WillOnce(Return(true));
498 EXPECT_CALL(fd, StartPolling(_, _)).Times(1).WillOnce(Return(true));
499 EXPECT_CALL(fd, GetAvailableMmapDataSize(_)).Times(aux_data.size()).WillRepeatedly(Return(0));
500 EXPECT_CALL(fd,
501 GetAvailableAuxData(Truly(SetBuf1), Truly(SetSize1), Truly(SetBuf2), Truly(SetSize2)))
502 .Times(aux_data.size());
503 EXPECT_CALL(fd, DiscardAuxData(Truly(CheckDiscardSize))).Times(aux_data.size());
504 EXPECT_CALL(fd, StopPolling()).Times(1).WillOnce(Return(true));
505 EXPECT_CALL(fd, DestroyMappedBuffer()).Times(1);
506 EXPECT_CALL(fd, DestroyAuxBuffer()).Times(1);
507
508 RecordReadThread thread(1024, attr, 1, 1, AUX_BUFFER_SIZE);
509 IOEventLoop loop;
510 ASSERT_TRUE(thread.RegisterDataCallback(loop, []() { return true; }));
511 ASSERT_TRUE(thread.AddEventFds({&fd}));
512 for (; test_index < aux_data.size(); ++test_index) {
513 ASSERT_TRUE(thread.SyncKernelBuffer());
514 std::unique_ptr<Record> r = thread.GetRecord();
515 if (aux_data[test_index].lost) {
516 ASSERT_TRUE(r == nullptr);
517 continue;
518 }
519 ASSERT_TRUE(r);
520 ASSERT_EQ(r->type(), PERF_RECORD_AUXTRACE);
521 auto auxtrace = static_cast<AuxTraceRecord*>(r.get());
522 auto& expected = aux_data[test_index];
523 ASSERT_EQ(auxtrace->data->aux_size,
524 expected.buf1.size() + expected.buf2.size() + expected.pad.size());
525 const char* p = auxtrace->location.addr;
526 ASSERT_TRUE(p != nullptr);
527 if (!expected.buf1.empty()) {
528 ASSERT_EQ(memcmp(p, expected.buf1.data(), expected.buf1.size()), 0);
529 p += expected.buf1.size();
530 }
531 if (!expected.buf2.empty()) {
532 ASSERT_EQ(memcmp(p, expected.buf2.data(), expected.buf2.size()), 0);
533 p += expected.buf2.size();
534 }
535 if (!expected.pad.empty()) {
536 ASSERT_EQ(memcmp(p, expected.pad.data(), expected.pad.size()), 0);
537 }
538 }
539 ASSERT_TRUE(thread.GetRecord() == nullptr);
540 ASSERT_TRUE(thread.RemoveEventFds({&fd}));
541 size_t aux_data_size = 0;
542 size_t lost_aux_data_size = 0;
543 for (auto& aux : aux_data) {
544 if (aux.lost) {
545 lost_aux_data_size += aux.buf1.size() + aux.buf2.size();
546 } else {
547 aux_data_size += aux.buf1.size() + aux.buf2.size();
548 }
549 }
550 ASSERT_EQ(aux_data_size, thread.GetStat().aux_data_size);
551 ASSERT_EQ(lost_aux_data_size, thread.GetStat().lost_aux_data_size);
552 }