• 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 
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 
TEST(RecordParser,GetStackSizePos_with_PerfSampleReadType)116 TEST(RecordParser, GetStackSizePos_with_PerfSampleReadType) {
117   const EventType* type = FindEventTypeByName("cpu-clock");
118   ASSERT_TRUE(type != nullptr);
119   perf_event_attr event_attr = CreateDefaultPerfEventAttr(*type);
120   event_attr.sample_type = PERF_SAMPLE_READ | PERF_SAMPLE_STACK_USER;
121   event_attr.read_format =
122       PERF_FORMAT_ID | PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_TOTAL_TIME_RUNNING;
123   uint64_t nr = 10;
124   RecordParser parser(event_attr);
125   size_t pos =
126       parser.GetStackSizePos([&](size_t, size_t size, void* dest) { memcpy(dest, &nr, size); });
127   ASSERT_EQ(pos, sizeof(perf_event_header) + 4 * sizeof(uint64_t));
128 
129   event_attr.read_format |= PERF_FORMAT_GROUP;
130   RecordParser parser2(event_attr);
131   pos = parser2.GetStackSizePos([&](size_t, size_t size, void* dest) { memcpy(dest, &nr, size); });
132   ASSERT_EQ(pos, sizeof(perf_event_header) + (nr * 2 + 3) * sizeof(uint64_t));
133 }
134 
135 struct MockEventFd : public EventFd {
MockEventFdMockEventFd136   MockEventFd(const perf_event_attr& attr, int cpu, char* buffer, size_t buffer_size,
137               bool mock_aux_buffer)
138       : EventFd(attr, -1, "", 0, cpu) {
139     mmap_data_buffer_ = buffer;
140     mmap_data_buffer_size_ = buffer_size;
141     if (mock_aux_buffer) {
142       aux_buffer_size_ = 1;  // Make HasAuxBuffer() return true.
143     }
144   }
145 
146   MOCK_METHOD2(CreateMappedBuffer, bool(size_t, bool));
147   MOCK_METHOD0(DestroyMappedBuffer, void());
148   MOCK_METHOD2(StartPolling, bool(IOEventLoop&, const std::function<bool()>&));
149   MOCK_METHOD0(StopPolling, bool());
150   MOCK_METHOD1(GetAvailableMmapDataSize, size_t(size_t&));
151   MOCK_METHOD1(DiscardMmapData, void(size_t));
152 
153   MOCK_METHOD2(CreateAuxBuffer, bool(size_t, bool));
154   MOCK_METHOD0(DestroyAuxBuffer, void());
155   MOCK_METHOD4(GetAvailableAuxData, uint64_t(char**, size_t*, char**, size_t*));
156   MOCK_METHOD1(DiscardAuxData, void(size_t));
157 };
158 
CreateFakeEventAttr()159 static perf_event_attr CreateFakeEventAttr() {
160   const EventType* type = FindEventTypeByName("cpu-clock");
161   CHECK(type != nullptr);
162   return CreateDefaultPerfEventAttr(*type);
163 }
164 
CreateFakeRecords(const perf_event_attr & attr,size_t record_count,size_t stack_size,size_t dyn_stack_size)165 static std::vector<std::unique_ptr<Record>> CreateFakeRecords(const perf_event_attr& attr,
166                                                               size_t record_count,
167                                                               size_t stack_size,
168                                                               size_t dyn_stack_size) {
169   std::vector<std::unique_ptr<Record>> records;
170   for (size_t i = 0; i < record_count; ++i) {
171     SampleRecord* r = new SampleRecord(attr, i, i + 1, i + 2, i + 3, i + 4, i + 5, i + 6, {}, {},
172                                        std::vector<char>(stack_size), dyn_stack_size);
173     records.emplace_back(r);
174   }
175   return records;
176 }
177 
AlignToPowerOfTwo(size_t value)178 static size_t AlignToPowerOfTwo(size_t value) {
179   size_t result = 1;
180   while (result < value) {
181     result <<= 1;
182   }
183   return result;
184 }
185 
SetArg(size_t value)186 static inline std::function<bool(size_t&)> SetArg(size_t value) {
187   return [value](size_t& arg) {
188     arg = value;
189     return true;
190   };
191 }
192 
TEST(KernelRecordReader,smoke)193 TEST(KernelRecordReader, smoke) {
194   // 1. Create fake records.
195   perf_event_attr attr = CreateFakeEventAttr();
196   std::vector<std::unique_ptr<Record>> records = CreateFakeRecords(attr, 10, 0, 0);
197   // 2. Create a buffer whose size is power of two.
198   size_t data_size = records.size() * records[0]->size();
199   std::vector<char> buffer(AlignToPowerOfTwo(data_size));
200   // 3. Copy record data into the buffer. Since a record in a kernel buffer can be wrapped around
201   // to the beginning of the buffer, create the case in the first record.
202   size_t data_pos = buffer.size() - 4;
203   memcpy(&buffer[data_pos], records[0]->Binary(), 4);
204   memcpy(&buffer[0], records[0]->Binary() + 4, records[0]->size() - 4);
205   size_t pos = records[0]->size() - 4;
206   for (size_t i = 1; i < records.size(); ++i) {
207     memcpy(&buffer[pos], records[i]->Binary(), records[i]->size());
208     pos += records[i]->size();
209   }
210   // Read records using KernelRecordReader.
211   MockEventFd event_fd(attr, 0, buffer.data(), buffer.size(), false);
212 
213   EXPECT_CALL(event_fd, GetAvailableMmapDataSize(Truly(SetArg(data_pos))))
214       .Times(1)
215       .WillOnce(Return(data_size));
216   EXPECT_CALL(event_fd, DiscardMmapData(Eq(data_size))).Times(1);
217   KernelRecordReader reader(&event_fd);
218   RecordParser parser(attr);
219   ASSERT_TRUE(reader.GetDataFromKernelBuffer());
220   for (size_t i = 0; i < records.size(); ++i) {
221     ASSERT_TRUE(reader.MoveToNextRecord(parser));
222     ASSERT_EQ(reader.RecordHeader().type, records[i]->type());
223     ASSERT_EQ(reader.RecordHeader().size, records[i]->size());
224     ASSERT_EQ(reader.RecordTime(), records[i]->Timestamp());
225     std::vector<char> data(reader.RecordHeader().size);
226     reader.ReadRecord(0, data.size(), &data[0]);
227     ASSERT_EQ(0, memcmp(&data[0], records[i]->Binary(), records[i]->size()));
228   }
229   ASSERT_FALSE(reader.MoveToNextRecord(parser));
230 }
231 
232 class RecordReadThreadTest : public ::testing::Test {
233  protected:
CreateFakeEventFds(const perf_event_attr & attr,size_t event_fd_count)234   std::vector<EventFd*> CreateFakeEventFds(const perf_event_attr& attr, size_t event_fd_count) {
235     size_t records_per_fd = records_.size() / event_fd_count;
236     buffers_.clear();
237     buffers_.resize(event_fd_count);
238     for (size_t i = 0; i < records_.size(); ++i) {
239       std::vector<char>& buffer = buffers_[i % event_fd_count];
240       buffer.insert(buffer.end(), records_[i]->Binary(),
241                     records_[i]->Binary() + records_[i]->size());
242     }
243     size_t data_size = records_per_fd * records_[0]->size();
244     size_t buffer_size = AlignToPowerOfTwo(data_size);
245     for (auto& buffer : buffers_) {
246       buffer.resize(buffer_size);
247     }
248     event_fds_.resize(event_fd_count);
249     for (size_t i = 0; i < event_fd_count; ++i) {
250       event_fds_[i].reset(new MockEventFd(attr, i, buffers_[i].data(), buffer_size, false));
251       EXPECT_CALL(*event_fds_[i], CreateMappedBuffer(_, _)).Times(1).WillOnce(Return(true));
252       EXPECT_CALL(*event_fds_[i], StartPolling(_, _)).Times(1).WillOnce(Return(true));
253       EXPECT_CALL(*event_fds_[i], GetAvailableMmapDataSize(Truly(SetArg(0))))
254           .Times(1)
255           .WillOnce(Return(data_size));
256       EXPECT_CALL(*event_fds_[i], DiscardMmapData(Eq(data_size))).Times(1);
257       EXPECT_CALL(*event_fds_[i], StopPolling()).Times(1).WillOnce(Return(true));
258       EXPECT_CALL(*event_fds_[i], DestroyMappedBuffer()).Times(1);
259       EXPECT_CALL(*event_fds_[i], DestroyAuxBuffer()).Times(1);
260     }
261     std::vector<EventFd*> result;
262     for (auto& fd : event_fds_) {
263       result.push_back(fd.get());
264     }
265     return result;
266   }
267 
268   std::vector<std::unique_ptr<Record>> records_;
269   std::vector<std::vector<char>> buffers_;
270   std::vector<std::unique_ptr<MockEventFd>> event_fds_;
271 };
272 
TEST_F(RecordReadThreadTest,handle_cmds)273 TEST_F(RecordReadThreadTest, handle_cmds) {
274   perf_event_attr attr = CreateFakeEventAttr();
275   records_ = CreateFakeRecords(attr, 2, 0, 0);
276   std::vector<EventFd*> event_fds = CreateFakeEventFds(attr, 2);
277   RecordReadThread thread(128 * 1024, event_fds[0]->attr(), 1, 1, 0);
278   IOEventLoop loop;
279   bool has_notify = false;
280   auto callback = [&]() {
281     has_notify = true;
282     return loop.ExitLoop();
283   };
284   ASSERT_TRUE(thread.RegisterDataCallback(loop, callback));
285   ASSERT_TRUE(thread.AddEventFds(event_fds));
286   ASSERT_TRUE(thread.SyncKernelBuffer());
287   ASSERT_TRUE(loop.RunLoop());
288   ASSERT_TRUE(has_notify);
289   ASSERT_TRUE(thread.GetRecord());
290   ASSERT_TRUE(thread.RemoveEventFds(event_fds));
291   ASSERT_TRUE(thread.StopReadThread());
292 }
293 
TEST_F(RecordReadThreadTest,read_records)294 TEST_F(RecordReadThreadTest, read_records) {
295   perf_event_attr attr = CreateFakeEventAttr();
296   RecordReadThread thread(128 * 1024, attr, 1, 1, 0);
297   IOEventLoop loop;
298   size_t record_index;
299   auto callback = [&]() {
300     while (true) {
301       std::unique_ptr<Record> r = thread.GetRecord();
302       if (!r) {
303         break;
304       }
305       std::unique_ptr<Record>& expected = records_[record_index++];
306       if (r->size() != expected->size() ||
307           memcmp(r->Binary(), expected->Binary(), r->size()) != 0) {
308         return false;
309       }
310     }
311     return loop.ExitLoop();
312   };
313   ASSERT_TRUE(thread.RegisterDataCallback(loop, callback));
314   for (size_t event_fd_count = 1; event_fd_count < 10; ++event_fd_count) {
315     records_ = CreateFakeRecords(attr, event_fd_count * 10, 0, 0);
316     std::vector<EventFd*> event_fds = CreateFakeEventFds(attr, event_fd_count);
317     record_index = 0;
318     ASSERT_TRUE(thread.AddEventFds(event_fds));
319     ASSERT_TRUE(thread.SyncKernelBuffer());
320     ASSERT_TRUE(loop.RunLoop());
321     ASSERT_EQ(record_index, records_.size());
322     ASSERT_TRUE(thread.RemoveEventFds(event_fds));
323   }
324 }
325 
TEST_F(RecordReadThreadTest,process_sample_record)326 TEST_F(RecordReadThreadTest, process_sample_record) {
327   perf_event_attr attr = CreateFakeEventAttr();
328   attr.sample_type |= PERF_SAMPLE_STACK_USER;
329   attr.sample_stack_user = 64 * 1024;
330   size_t record_buffer_size = 128 * 1024;
331   RecordReadThread thread(record_buffer_size, attr, 1, 1, 0);
332   IOEventLoop loop;
333   ASSERT_TRUE(thread.RegisterDataCallback(loop, []() { return true; }));
334 
335   auto read_record = [&](std::unique_ptr<Record>& r) {
336     std::vector<EventFd*> event_fds = CreateFakeEventFds(attr, 1);
337     ASSERT_TRUE(thread.AddEventFds(event_fds));
338     ASSERT_TRUE(thread.SyncKernelBuffer());
339     ASSERT_TRUE(thread.RemoveEventFds(event_fds));
340     r = thread.GetRecord();
341   };
342 
343   // When the free space in record buffer is above low level, only invalid stack data in sample
344   // records is removed.
345   thread.SetBufferLevels(0, 0);
346   records_ = CreateFakeRecords(attr, 1, 8192, 8192);
347   std::unique_ptr<Record> r;
348   read_record(r);
349   ASSERT_TRUE(r);
350   SampleRecord* sr = static_cast<SampleRecord*>(r.get());
351   ASSERT_EQ(sr->stack_user_data.size, 8192u);
352   ASSERT_EQ(sr->stack_user_data.dyn_size, 8192u);
353   records_ = CreateFakeRecords(attr, 1, 8192, 4096);
354   read_record(r);
355   ASSERT_TRUE(r);
356   sr = static_cast<SampleRecord*>(r.get());
357   ASSERT_EQ(sr->stack_user_data.size, 4096u);
358   ASSERT_EQ(sr->stack_user_data.dyn_size, 4096u);
359 
360   // When the free space in record buffer is below low level but above critical level, only
361   // 1K stack data in sample records is left.
362   thread.SetBufferLevels(record_buffer_size, 0);
363   read_record(r);
364   ASSERT_TRUE(r);
365   sr = static_cast<SampleRecord*>(r.get());
366   ASSERT_EQ(sr->stack_user_data.size, 1024u);
367   ASSERT_EQ(sr->stack_user_data.dyn_size, 1024u);
368 
369   // When the free space in record buffer is below critical level, sample records are dropped.
370   thread.SetBufferLevels(record_buffer_size, record_buffer_size);
371   read_record(r);
372   ASSERT_FALSE(r);
373   ASSERT_EQ(thread.GetStat().userspace_lost_samples, 1u);
374   ASSERT_EQ(thread.GetStat().userspace_lost_non_samples, 0u);
375   ASSERT_EQ(thread.GetStat().userspace_cut_stack_samples, 1u);
376 }
377 
378 // Test that the data notification exists until the RecordBuffer is empty. So we can read all
379 // records even if reading one record at a time.
TEST_F(RecordReadThreadTest,has_data_notification_until_buffer_empty)380 TEST_F(RecordReadThreadTest, has_data_notification_until_buffer_empty) {
381   perf_event_attr attr = CreateFakeEventAttr();
382   RecordReadThread thread(128 * 1024, attr, 1, 1, 0);
383   IOEventLoop loop;
384   size_t record_index = 0;
385   auto read_one_record = [&]() {
386     std::unique_ptr<Record> r = thread.GetRecord();
387     if (!r) {
388       return loop.ExitLoop();
389     }
390     std::unique_ptr<Record>& expected = records_[record_index++];
391     if (r->size() != expected->size() || memcmp(r->Binary(), expected->Binary(), r->size()) != 0) {
392       return false;
393     }
394     return true;
395   };
396   ASSERT_TRUE(thread.RegisterDataCallback(loop, read_one_record));
397   records_ = CreateFakeRecords(attr, 2, 0, 0);
398   std::vector<EventFd*> event_fds = CreateFakeEventFds(attr, 1);
399   ASSERT_TRUE(thread.AddEventFds(event_fds));
400   ASSERT_TRUE(thread.SyncKernelBuffer());
401   ASSERT_TRUE(loop.RunLoop());
402   ASSERT_EQ(record_index, records_.size());
403   ASSERT_TRUE(thread.RemoveEventFds(event_fds));
404 }
405 
TEST_F(RecordReadThreadTest,no_cut_samples)406 TEST_F(RecordReadThreadTest, no_cut_samples) {
407   perf_event_attr attr = CreateFakeEventAttr();
408   attr.sample_type |= PERF_SAMPLE_STACK_USER;
409   attr.sample_stack_user = 64 * 1024;
410   RecordReadThread thread(128 * 1024, attr, 1, 1, 0, false);
411   IOEventLoop loop;
412   ASSERT_TRUE(thread.RegisterDataCallback(loop, []() { return true; }));
413   const size_t total_samples = 100;
414   records_ = CreateFakeRecords(attr, total_samples, 8 * 1024, 8 * 1024);
415   std::vector<EventFd*> event_fds = CreateFakeEventFds(attr, 1);
416   ASSERT_TRUE(thread.AddEventFds(event_fds));
417   ASSERT_TRUE(thread.SyncKernelBuffer());
418   ASSERT_TRUE(thread.RemoveEventFds(event_fds));
419   size_t received_samples = 0;
420   while (thread.GetRecord()) {
421     received_samples++;
422   }
423   ASSERT_GT(received_samples, 0u);
424   ASSERT_GT(thread.GetStat().userspace_lost_samples, 0u);
425   ASSERT_EQ(thread.GetStat().userspace_lost_samples, total_samples - received_samples);
426   ASSERT_EQ(thread.GetStat().userspace_cut_stack_samples, 0u);
427 }
428 
TEST_F(RecordReadThreadTest,exclude_perf)429 TEST_F(RecordReadThreadTest, exclude_perf) {
430   perf_event_attr attr = CreateFakeEventAttr();
431   attr.sample_type |= PERF_SAMPLE_STACK_USER;
432   size_t stack_size = 1024;
433   attr.sample_stack_user = stack_size;
434   records_.emplace_back(new SampleRecord(attr, 0, 1, getpid(), 3, 4, 5, 6, {}, {},
435                                          std::vector<char>(stack_size), stack_size));
436   records_.emplace_back(new SampleRecord(attr, 0, 1, getpid() + 1, 3, 4, 5, 6, {}, {},
437                                          std::vector<char>(stack_size), stack_size));
438 
439   auto read_records = [&](RecordReadThread& thread, std::vector<std::unique_ptr<Record>>& records) {
440     records.clear();
441     std::vector<EventFd*> event_fds = CreateFakeEventFds(attr, 1);
442     ASSERT_TRUE(thread.AddEventFds(event_fds));
443     ASSERT_TRUE(thread.SyncKernelBuffer());
444     ASSERT_TRUE(thread.RemoveEventFds(event_fds));
445     while (auto r = thread.GetRecord()) {
446       records.emplace_back(std::move(r));
447     }
448   };
449 
450   // By default, no samples are excluded.
451   RecordReadThread thread(128 * 1024, attr, 1, 1, 0);
452   IOEventLoop loop;
453   ASSERT_TRUE(thread.RegisterDataCallback(loop, []() { return true; }));
454   std::vector<std::unique_ptr<Record>> received_records;
455   read_records(thread, received_records);
456   ASSERT_EQ(received_records.size(), 2);
457   CheckRecordEqual(*received_records[0], *records_[0]);
458   CheckRecordEqual(*received_records[1], *records_[1]);
459 
460   // With exclude_perf, the first sample is excluded.
461   RecordReadThread thread2(128 * 1024, attr, 1, 1, 0, true, true);
462   ASSERT_TRUE(thread2.RegisterDataCallback(loop, []() { return true; }));
463   read_records(thread2, received_records);
464   ASSERT_EQ(received_records.size(), 1);
465   CheckRecordEqual(*received_records[0], *records_[1]);
466 }
467 
468 struct FakeAuxData {
469   std::vector<char> buf1;
470   std::vector<char> buf2;
471   std::vector<char> pad;
472   bool lost;
473 
FakeAuxDataFakeAuxData474   FakeAuxData(size_t buf1_size, size_t buf2_size, char c, size_t pad_size, bool lost)
475       : buf1(buf1_size, c), buf2(buf2_size, c), pad(pad_size, 0), lost(lost) {}
476 };
477 
TEST_F(RecordReadThreadTest,read_aux_data)478 TEST_F(RecordReadThreadTest, read_aux_data) {
479   ScopedEventTypes scoped_types("cs-etm,0,0");
480   const EventType* type = FindEventTypeByName("cs-etm");
481   ASSERT_TRUE(type != nullptr);
482   std::vector<FakeAuxData> aux_data;
483   aux_data.emplace_back(40, 0, '0', 0, false);   // one buffer
484   aux_data.emplace_back(40, 40, '1', 0, false);  // two buffers
485   aux_data.emplace_back(36, 0, '2', 4, false);   // one buffer needs padding to 8 bytes alignment
486   // one buffer too big to fit in record buffer, failing at checking free size
487   aux_data.emplace_back(1024, 0, '3', 0, true);
488   // one buffer too big to fit in record buffer, failing at AllocWriteSpace()
489   aux_data.emplace_back(800, 0, '4', 0, true);
490   size_t test_index = 0;
491 
492   auto SetBuf1 = [&](char** buf1) {
493     *buf1 = aux_data[test_index].buf1.data();
494     return true;
495   };
496   auto SetSize1 = [&](size_t* size1) {
497     *size1 = aux_data[test_index].buf1.size();
498     return true;
499   };
500   auto SetBuf2 = [&](char** buf2) {
501     *buf2 = aux_data[test_index].buf2.data();
502     return true;
503   };
504   auto SetSize2 = [&](size_t* size2) {
505     *size2 = aux_data[test_index].buf2.size();
506     return true;
507   };
508   auto CheckDiscardSize = [&](size_t size) {
509     return size == aux_data[test_index].buf1.size() + aux_data[test_index].buf2.size();
510   };
511 
512   const size_t AUX_BUFFER_SIZE = 4096;
513 
514   perf_event_attr attr = CreateDefaultPerfEventAttr(*type);
515   MockEventFd fd(attr, 0, nullptr, 1, true);
516   EXPECT_CALL(fd, CreateMappedBuffer(_, _)).Times(1).WillOnce(Return(true));
517   EXPECT_CALL(fd, CreateAuxBuffer(Eq(AUX_BUFFER_SIZE), _)).Times(1).WillOnce(Return(true));
518   EXPECT_CALL(fd, StartPolling(_, _)).Times(1).WillOnce(Return(true));
519   EXPECT_CALL(fd, GetAvailableMmapDataSize(_)).Times(aux_data.size()).WillRepeatedly(Return(0));
520   EXPECT_CALL(fd,
521               GetAvailableAuxData(Truly(SetBuf1), Truly(SetSize1), Truly(SetBuf2), Truly(SetSize2)))
522       .Times(aux_data.size());
523   EXPECT_CALL(fd, DiscardAuxData(Truly(CheckDiscardSize))).Times(aux_data.size());
524   EXPECT_CALL(fd, StopPolling()).Times(1).WillOnce(Return(true));
525   EXPECT_CALL(fd, DestroyMappedBuffer()).Times(1);
526   EXPECT_CALL(fd, DestroyAuxBuffer()).Times(1);
527 
528   RecordReadThread thread(1024, attr, 1, 1, AUX_BUFFER_SIZE);
529   IOEventLoop loop;
530   ASSERT_TRUE(thread.RegisterDataCallback(loop, []() { return true; }));
531   ASSERT_TRUE(thread.AddEventFds({&fd}));
532   for (; test_index < aux_data.size(); ++test_index) {
533     ASSERT_TRUE(thread.SyncKernelBuffer());
534     std::unique_ptr<Record> r = thread.GetRecord();
535     if (aux_data[test_index].lost) {
536       ASSERT_TRUE(r == nullptr);
537       continue;
538     }
539     ASSERT_TRUE(r);
540     ASSERT_EQ(r->type(), PERF_RECORD_AUXTRACE);
541     auto auxtrace = static_cast<AuxTraceRecord*>(r.get());
542     auto& expected = aux_data[test_index];
543     ASSERT_EQ(auxtrace->data->aux_size,
544               expected.buf1.size() + expected.buf2.size() + expected.pad.size());
545     const char* p = auxtrace->location.addr;
546     ASSERT_TRUE(p != nullptr);
547     if (!expected.buf1.empty()) {
548       ASSERT_EQ(memcmp(p, expected.buf1.data(), expected.buf1.size()), 0);
549       p += expected.buf1.size();
550     }
551     if (!expected.buf2.empty()) {
552       ASSERT_EQ(memcmp(p, expected.buf2.data(), expected.buf2.size()), 0);
553       p += expected.buf2.size();
554     }
555     if (!expected.pad.empty()) {
556       ASSERT_EQ(memcmp(p, expected.pad.data(), expected.pad.size()), 0);
557     }
558   }
559   ASSERT_TRUE(thread.GetRecord() == nullptr);
560   ASSERT_TRUE(thread.RemoveEventFds({&fd}));
561   size_t aux_data_size = 0;
562   size_t lost_aux_data_size = 0;
563   for (auto& aux : aux_data) {
564     if (aux.lost) {
565       lost_aux_data_size += aux.buf1.size() + aux.buf2.size();
566     } else {
567       aux_data_size += aux.buf1.size() + aux.buf2.size();
568     }
569   }
570   ASSERT_EQ(aux_data_size, thread.GetStat().aux_data_size);
571   ASSERT_EQ(lost_aux_data_size, thread.GetStat().lost_aux_data_size);
572 }