xref: /aosp_15_r20/system/extras/simpleperf/BranchListFile_test.cpp (revision 288bf5226967eb3dac5cce6c939ccc2a7f2b4fe5)
1 /*
2  * Copyright (C) 2023 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 "BranchListFile.h"
20 #include "get_test_data.h"
21 
22 using namespace simpleperf;
23 
24 // @CddTest = 6.1/C-0-2
TEST(BranchListFile,etm_branch_to_proto_string)25 TEST(BranchListFile, etm_branch_to_proto_string) {
26   std::vector<bool> branch;
27   for (size_t i = 0; i < 100; i++) {
28     branch.push_back(i % 2 == 0);
29     std::string s = ETMBranchToProtoString(branch);
30     for (size_t j = 0; j <= i; j++) {
31       bool b = s[j >> 3] & (1 << (j & 7));
32       ASSERT_EQ(b, branch[j]);
33     }
34     std::vector<bool> branch2 = ProtoStringToETMBranch(s, branch.size());
35     ASSERT_EQ(branch, branch2);
36   }
37 }
38 
IsETMDataEqual(ETMBinaryMap & data1,ETMBinaryMap & data2)39 static bool IsETMDataEqual(ETMBinaryMap& data1, ETMBinaryMap& data2) {
40   if (data1.size() != data2.size()) {
41     return false;
42   }
43   for (const auto& [key, binary1] : data1) {
44     auto it = data2.find(key);
45     if (it == data2.end()) {
46       return false;
47     }
48     ETMBinary& binary2 = it->second;
49     if (binary1.dso_type != binary2.dso_type) {
50       return false;
51     }
52     const UnorderedETMBranchMap& branch_map1 = binary1.branch_map;
53     const UnorderedETMBranchMap& branch_map2 = binary2.branch_map;
54     if (branch_map1.size() != branch_map2.size()) {
55       return false;
56     }
57     for (const auto& [addr, b_map1] : branch_map1) {
58       auto it2 = branch_map2.find(addr);
59       if (it2 == branch_map2.end()) {
60         return false;
61       }
62       const auto& b_map2 = it2->second;
63       if (b_map1.size() != b_map2.size()) {
64         return false;
65       }
66       for (const auto& [branch, count1] : b_map1) {
67         auto it3 = b_map2.find(branch);
68         if (it3 == b_map2.end()) {
69           return false;
70         }
71         if (count1 != it3->second) {
72           return false;
73         }
74       }
75     }
76   }
77   return true;
78 }
79 
IsLBRDataEqual(const LBRData & data1,const LBRData & data2)80 static bool IsLBRDataEqual(const LBRData& data1, const LBRData& data2) {
81   if (data1.samples.size() != data2.samples.size()) {
82     return false;
83   }
84   for (size_t i = 0; i < data1.samples.size(); i++) {
85     const LBRSample& sample1 = data1.samples[i];
86     const LBRSample& sample2 = data2.samples[i];
87     if (sample1.binary_id != sample2.binary_id) {
88       return false;
89     }
90     if (sample1.vaddr_in_file != sample2.vaddr_in_file) {
91       return false;
92     }
93     if (sample1.branches.size() != sample2.branches.size()) {
94       return false;
95     }
96     for (size_t j = 0; j < sample1.branches.size(); j++) {
97       const LBRBranch& b1 = sample1.branches[j];
98       const LBRBranch& b2 = sample2.branches[j];
99       if (b1.from_binary_id != b2.from_binary_id || b1.to_binary_id != b2.to_binary_id ||
100           b1.from_vaddr_in_file != b2.from_vaddr_in_file ||
101           b1.to_vaddr_in_file != b2.to_vaddr_in_file) {
102         return false;
103       }
104     }
105   }
106   return data1.binaries == data2.binaries;
107 }
108 
109 // @CddTest = 6.1/C-0-2
TEST(BranchListProtoReaderWriter,smoke)110 TEST(BranchListProtoReaderWriter, smoke) {
111   ETMBinaryMap etm_data;
112   ETMBinary& binary = etm_data[BinaryKey("fake_binary", BuildId())];
113   binary.dso_type = DSO_ELF_FILE;
114   UnorderedETMBranchMap& branch_map = binary.branch_map;
115   for (size_t addr = 0; addr <= 1024; addr++) {
116     auto& b_map = branch_map[addr];
117     std::vector<bool> branch1 = {true};
118     b_map[branch1] = 1;
119     std::vector<bool> branch2 = {true, false};
120     b_map[branch2] = 2;
121   }
122   LBRData lbr_data;
123   lbr_data.binaries.emplace_back(BinaryKey("binary1", BuildId()));
124   lbr_data.binaries.emplace_back(BinaryKey("binary2", BuildId()));
125   for (uint64_t from_addr = 0; from_addr <= 10; from_addr++) {
126     for (uint64_t to_addr = 100; to_addr <= 110; to_addr++) {
127       LBRBranch branch = {0, 1, from_addr, to_addr};
128       LBRSample sample = {0, from_addr, {branch}};
129       lbr_data.samples.emplace_back(sample);
130     }
131   }
132 
133   TemporaryFile tmpfile;
134   close(tmpfile.fd);
135   for (size_t max_branches_per_message : {100, 100000000}) {
136     for (bool compress : {false, true}) {
137       auto writer =
138           BranchListProtoWriter::CreateForFile(tmpfile.path, compress, max_branches_per_message);
139       ASSERT_TRUE(writer);
140       ASSERT_TRUE(writer->Write(etm_data));
141       ASSERT_TRUE(writer->Write(lbr_data));
142       writer = nullptr;
143       auto reader = BranchListProtoReader::CreateForFile(tmpfile.path);
144       ASSERT_TRUE(reader);
145       ETMBinaryMap new_etm_data;
146       LBRData new_lbr_data;
147       ASSERT_TRUE(reader->Read(new_etm_data, new_lbr_data));
148       ASSERT_TRUE(IsETMDataEqual(etm_data, new_etm_data));
149       ASSERT_TRUE(IsLBRDataEqual(lbr_data, new_lbr_data));
150     }
151   }
152 }
153 
154 // @CddTest = 6.1/C-0-2
TEST(BranchListProtoReaderWriter,read_old_branch_list_file)155 TEST(BranchListProtoReaderWriter, read_old_branch_list_file) {
156   std::string path = GetTestData("etm/old_branch_list.data");
157   auto reader = BranchListProtoReader::CreateForFile(path);
158   ASSERT_TRUE(reader);
159   ETMBinaryMap etm_data;
160   LBRData lbr_data;
161   ASSERT_TRUE(reader->Read(etm_data, lbr_data));
162   ASSERT_EQ(etm_data.size(), 1u);
163 }
164