• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 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 <gtest/gtest.h>
18 
19 #include <string.h>
20 
21 #include <memory>
22 #include <vector>
23 
24 #include <android-base/file.h>
25 
26 #include "environment.h"
27 #include "event_attr.h"
28 #include "event_type.h"
29 #include "record.h"
30 #include "record_file.h"
31 #include "utils.h"
32 
33 #include "record_equal_test.h"
34 
35 using namespace simpleperf;
36 using namespace simpleperf::PerfFileFormat;
37 
38 class RecordFileTest : public ::testing::Test {
39  protected:
SetUp()40   void SetUp() override { close(tmpfile_.release()); }
41 
AddEventType(const std::string & event_type_str)42   void AddEventType(const std::string& event_type_str) {
43     std::unique_ptr<EventTypeAndModifier> event_type_modifier = ParseEventType(event_type_str);
44     ASSERT_TRUE(event_type_modifier != nullptr);
45     perf_event_attr attr = CreateDefaultPerfEventAttr(event_type_modifier->event_type);
46     attr.sample_id_all = 1;
47     attrs_.push_back(std::unique_ptr<perf_event_attr>(new perf_event_attr(attr)));
48     EventAttrWithId attr_id;
49     attr_id.attr = attrs_.back().get();
50     attr_id.ids.push_back(attrs_.size());  // Fake id.
51     attr_ids_.push_back(attr_id);
52   }
53 
54   TemporaryFile tmpfile_;
55   std::vector<std::unique_ptr<perf_event_attr>> attrs_;
56   std::vector<EventAttrWithId> attr_ids_;
57 };
58 
TEST_F(RecordFileTest,smoke)59 TEST_F(RecordFileTest, smoke) {
60   // Write to a record file.
61   std::unique_ptr<RecordFileWriter> writer = RecordFileWriter::CreateInstance(tmpfile_.path);
62   ASSERT_TRUE(writer != nullptr);
63 
64   // Write attr section.
65   AddEventType("cpu-cycles");
66   ASSERT_TRUE(writer->WriteAttrSection(attr_ids_));
67 
68   // Write data section.
69   MmapRecord mmap_record(*(attr_ids_[0].attr), true, 1, 1, 0x1000, 0x2000, 0x3000,
70                          "mmap_record_example", attr_ids_[0].ids[0]);
71   ASSERT_TRUE(writer->WriteRecord(mmap_record));
72 
73   // Write feature section.
74   ASSERT_TRUE(writer->BeginWriteFeatures(1));
75   char p[BuildId::Size()];
76   for (size_t i = 0; i < BuildId::Size(); ++i) {
77     p[i] = i;
78   }
79   BuildId build_id(p);
80   std::vector<BuildIdRecord> build_id_records;
81   build_id_records.push_back(BuildIdRecord(false, getpid(), build_id, "init"));
82   ASSERT_TRUE(writer->WriteBuildIdFeature(build_id_records));
83   ASSERT_TRUE(writer->EndWriteFeatures());
84   ASSERT_TRUE(writer->Close());
85 
86   // Read from a record file.
87   std::unique_ptr<RecordFileReader> reader = RecordFileReader::CreateInstance(tmpfile_.path);
88   ASSERT_TRUE(reader != nullptr);
89   std::vector<EventAttrWithId> attrs = reader->AttrSection();
90   ASSERT_EQ(1u, attrs.size());
91   ASSERT_EQ(0, memcmp(attrs[0].attr, attr_ids_[0].attr, sizeof(perf_event_attr)));
92   ASSERT_EQ(attrs[0].ids, attr_ids_[0].ids);
93 
94   // Read and check data section.
95   std::vector<std::unique_ptr<Record>> records = reader->DataSection();
96   ASSERT_EQ(1u, records.size());
97   CheckRecordEqual(mmap_record, *records[0]);
98 
99   // Read and check feature section.
100   std::vector<BuildIdRecord> read_build_id_records = reader->ReadBuildIdFeature();
101   ASSERT_EQ(1u, read_build_id_records.size());
102   CheckRecordEqual(read_build_id_records[0], build_id_records[0]);
103 
104   ASSERT_TRUE(reader->Close());
105 }
106 
TEST_F(RecordFileTest,record_more_than_one_attr)107 TEST_F(RecordFileTest, record_more_than_one_attr) {
108   // Write to a record file.
109   std::unique_ptr<RecordFileWriter> writer = RecordFileWriter::CreateInstance(tmpfile_.path);
110   ASSERT_TRUE(writer != nullptr);
111 
112   // Write attr section.
113   AddEventType("cpu-cycles");
114   AddEventType("cpu-clock");
115   AddEventType("task-clock");
116   ASSERT_TRUE(writer->WriteAttrSection(attr_ids_));
117 
118   ASSERT_TRUE(writer->Close());
119 
120   // Read from a record file.
121   std::unique_ptr<RecordFileReader> reader = RecordFileReader::CreateInstance(tmpfile_.path);
122   ASSERT_TRUE(reader != nullptr);
123   std::vector<EventAttrWithId> attrs = reader->AttrSection();
124   ASSERT_EQ(3u, attrs.size());
125   for (size_t i = 0; i < attrs.size(); ++i) {
126     ASSERT_EQ(0, memcmp(attrs[i].attr, attr_ids_[i].attr, sizeof(perf_event_attr)));
127     ASSERT_EQ(attrs[i].ids, attr_ids_[i].ids);
128   }
129 }
130 
TEST_F(RecordFileTest,write_meta_info_feature_section)131 TEST_F(RecordFileTest, write_meta_info_feature_section) {
132   // Write to a record file.
133   std::unique_ptr<RecordFileWriter> writer = RecordFileWriter::CreateInstance(tmpfile_.path);
134   ASSERT_TRUE(writer != nullptr);
135   AddEventType("cpu-cycles");
136   ASSERT_TRUE(writer->WriteAttrSection(attr_ids_));
137 
138   // Write meta_info feature section.
139   ASSERT_TRUE(writer->BeginWriteFeatures(1));
140   std::unordered_map<std::string, std::string> info_map;
141   for (int i = 0; i < 100; ++i) {
142     std::string s = std::to_string(i);
143     info_map[s] = s + s;
144   }
145   ASSERT_TRUE(writer->WriteMetaInfoFeature(info_map));
146   ASSERT_TRUE(writer->EndWriteFeatures());
147   ASSERT_TRUE(writer->Close());
148 
149   // Read from a record file.
150   std::unique_ptr<RecordFileReader> reader = RecordFileReader::CreateInstance(tmpfile_.path);
151   ASSERT_TRUE(reader != nullptr);
152   ASSERT_EQ(reader->GetMetaInfoFeature(), info_map);
153 }
154 
TEST_F(RecordFileTest,write_debug_unwind_feature_section)155 TEST_F(RecordFileTest, write_debug_unwind_feature_section) {
156   // Write to a record file.
157   std::unique_ptr<RecordFileWriter> writer = RecordFileWriter::CreateInstance(tmpfile_.path);
158   ASSERT_TRUE(writer != nullptr);
159   AddEventType("cpu-cycles");
160   ASSERT_TRUE(writer->WriteAttrSection(attr_ids_));
161 
162   // Write debug_unwind feature section.
163   ASSERT_TRUE(writer->BeginWriteFeatures(1));
164   DebugUnwindFeature debug_unwind(2);
165   debug_unwind[0].path = "file1";
166   debug_unwind[0].size = 1000;
167   debug_unwind[1].path = "file2";
168   debug_unwind[1].size = 2000;
169   ASSERT_TRUE(writer->WriteDebugUnwindFeature(debug_unwind));
170   ASSERT_TRUE(writer->EndWriteFeatures());
171   ASSERT_TRUE(writer->Close());
172 
173   // Read from a record file.
174   std::unique_ptr<RecordFileReader> reader = RecordFileReader::CreateInstance(tmpfile_.path);
175   ASSERT_TRUE(reader != nullptr);
176   std::optional<DebugUnwindFeature> opt_debug_unwind = reader->ReadDebugUnwindFeature();
177   ASSERT_TRUE(opt_debug_unwind.has_value());
178   ASSERT_EQ(opt_debug_unwind.value().size(), debug_unwind.size());
179   for (size_t i = 0; i < debug_unwind.size(); i++) {
180     ASSERT_EQ(opt_debug_unwind.value()[i].path, debug_unwind[i].path);
181     ASSERT_EQ(opt_debug_unwind.value()[i].size, debug_unwind[i].size);
182   }
183 }
184 
TEST_F(RecordFileTest,write_file2_feature_section)185 TEST_F(RecordFileTest, write_file2_feature_section) {
186   // Write to a record file.
187   std::unique_ptr<RecordFileWriter> writer = RecordFileWriter::CreateInstance(tmpfile_.path);
188   ASSERT_TRUE(writer != nullptr);
189   AddEventType("cpu-cycles");
190   ASSERT_TRUE(writer->WriteAttrSection(attr_ids_));
191 
192   // Write file2 feature section.
193   ASSERT_TRUE(writer->BeginWriteFeatures(1));
194   std::vector<FileFeature> files(3);
195   files[0].path = "fake_dex_file";
196   files[0].type = DSO_DEX_FILE;
197   files[0].min_vaddr = 0x1000;
198   files[0].symbols.emplace_back("dex_symbol", 0x1001, 0x1002);
199   files[0].dex_file_offsets.assign(0x1003, 0x1004);
200   files[1].path = "fake_elf_file";
201   files[1].type = DSO_ELF_FILE;
202   files[1].min_vaddr = 0x2000;
203   Symbol symbol("elf_symbol", 0x2001, 0x2002);
204   files[1].symbol_ptrs.emplace_back(&symbol);
205   files[1].file_offset_of_min_vaddr = 0x2003;
206   files[2].path = "fake_kernel_module";
207   files[2].type = DSO_KERNEL_MODULE;
208   files[2].min_vaddr = 0x3000;
209   files[2].symbols.emplace_back("kernel_module_symbol", 0x3001, 0x3002);
210   files[2].file_offset_of_min_vaddr = 0x3003;
211 
212   for (const auto& file : files) {
213     ASSERT_TRUE(writer->WriteFileFeature(file));
214   }
215   ASSERT_TRUE(writer->EndWriteFeatures());
216   ASSERT_TRUE(writer->Close());
217 
218   // Read from a record file.
219   std::unique_ptr<RecordFileReader> reader = RecordFileReader::CreateInstance(tmpfile_.path);
220   ASSERT_TRUE(reader != nullptr);
221   size_t read_pos = 0;
222   FileFeature file;
223 
224   auto check_symbol = [](const Symbol& sym1, const Symbol& sym2) {
225     return sym1.addr == sym2.addr && sym1.len == sym2.len && strcmp(sym1.Name(), sym2.Name()) == 0;
226   };
227 
228   size_t file_id = 0;
229   while (reader->ReadFileFeature(read_pos, &file)) {
230     ASSERT_LT(file_id, files.size());
231     const FileFeature& expected_file = files[file_id++];
232     ASSERT_EQ(file.path, expected_file.path);
233     ASSERT_EQ(file.type, expected_file.type);
234     ASSERT_EQ(file.min_vaddr, expected_file.min_vaddr);
235     if (!expected_file.symbols.empty()) {
236       ASSERT_EQ(file.symbols.size(), expected_file.symbols.size());
237       for (size_t i = 0; i < file.symbols.size(); i++) {
238         ASSERT_TRUE(check_symbol(file.symbols[i], expected_file.symbols[i]));
239       }
240     } else {
241       ASSERT_EQ(file.symbols.size(), expected_file.symbol_ptrs.size());
242       for (size_t i = 0; i < file.symbols.size(); i++) {
243         ASSERT_TRUE(check_symbol(file.symbols[i], *expected_file.symbol_ptrs[i]));
244       }
245     }
246     if (file.type == DSO_DEX_FILE) {
247       ASSERT_EQ(file.dex_file_offsets, expected_file.dex_file_offsets);
248     } else if (file.type == DSO_ELF_FILE) {
249       ASSERT_TRUE(file.dex_file_offsets.empty());
250       ASSERT_EQ(file.file_offset_of_min_vaddr, expected_file.file_offset_of_min_vaddr);
251     } else if (file.type == DSO_KERNEL_MODULE) {
252       ASSERT_TRUE(file.dex_file_offsets.empty());
253       ASSERT_EQ(file.file_offset_of_min_vaddr, expected_file.file_offset_of_min_vaddr);
254     }
255   }
256   ASSERT_EQ(file_id, files.size());
257 }