xref: /aosp_15_r20/system/extras/simpleperf/record_test.cpp (revision 288bf5226967eb3dac5cce6c939ccc2a7f2b4fe5)
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 "event_attr.h"
20 #include "event_type.h"
21 #include "record.h"
22 #include "record_equal_test.h"
23 
24 using namespace simpleperf;
25 
26 // @CddTest = 6.1/C-0-2
27 class RecordTest : public ::testing::Test {
28  protected:
SetUp()29   virtual void SetUp() {
30     const EventType* type = FindEventTypeByName("cpu-clock");
31     ASSERT_TRUE(type != nullptr);
32     event_attr = CreateDefaultPerfEventAttr(*type);
33     event_attr.sample_id_all = 1;
34   }
35 
CheckRecordMatchBinary(Record & record)36   void CheckRecordMatchBinary(Record& record) {
37     std::vector<std::unique_ptr<Record>> records =
38         ReadRecordsFromBuffer(event_attr, record.BinaryForTestingOnly(), record.size());
39     ASSERT_EQ(1u, records.size());
40     CheckRecordEqual(record, *records[0]);
41   }
42 
43   perf_event_attr event_attr;
44 };
45 
46 // @CddTest = 6.1/C-0-2
TEST_F(RecordTest,MmapRecordMatchBinary)47 TEST_F(RecordTest, MmapRecordMatchBinary) {
48   MmapRecord record(event_attr, true, 1, 2, 0x1000, 0x2000, 0x3000, "MmapRecord", 0);
49   CheckRecordMatchBinary(record);
50 }
51 
52 // @CddTest = 6.1/C-0-2
TEST_F(RecordTest,CommRecordMatchBinary)53 TEST_F(RecordTest, CommRecordMatchBinary) {
54   CommRecord record(event_attr, 1, 2, "CommRecord", 0, 7);
55   CheckRecordMatchBinary(record);
56 }
57 
58 // @CddTest = 6.1/C-0-2
TEST_F(RecordTest,SampleRecordMatchBinary)59 TEST_F(RecordTest, SampleRecordMatchBinary) {
60   event_attr.sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_TIME | PERF_SAMPLE_ID |
61                            PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD | PERF_SAMPLE_CALLCHAIN;
62   SampleRecord record(event_attr, 1, 2, 3, 4, 5, 6, 7, {}, {8, 9, 10}, {}, 0);
63   CheckRecordMatchBinary(record);
64 }
65 
66 // @CddTest = 6.1/C-0-2
TEST_F(RecordTest,SampleRecord_exclude_kernel_callchain)67 TEST_F(RecordTest, SampleRecord_exclude_kernel_callchain) {
68   SampleRecord r(event_attr, 0, 1, 0, 0, 0, 0, 0, {}, {}, {}, 0);
69   ASSERT_TRUE(r.ExcludeKernelCallChain());
70 
71   event_attr.sample_type |= PERF_SAMPLE_CALLCHAIN;
72   SampleRecord r1(event_attr, 0, 1, 0, 0, 0, 0, 0, {}, {PERF_CONTEXT_USER, 2}, {}, 0);
73   ASSERT_TRUE(r1.ExcludeKernelCallChain());
74   ASSERT_EQ(2u, r1.ip_data.ip);
75   SampleRecord r2;
76   ASSERT_TRUE(
77       r2.Parse(event_attr, r1.BinaryForTestingOnly(), r1.BinaryForTestingOnly() + r1.size()));
78   ASSERT_EQ(1u, r.ip_data.ip);
79   ASSERT_EQ(2u, r2.callchain_data.ip_nr);
80   ASSERT_EQ(PERF_CONTEXT_USER, r2.callchain_data.ips[0]);
81   ASSERT_EQ(2u, r2.callchain_data.ips[1]);
82 
83   SampleRecord r3(event_attr, 0, 1, 0, 0, 0, 0, 0, {}, {1, PERF_CONTEXT_USER, 2}, {}, 0);
84   ASSERT_TRUE(r3.ExcludeKernelCallChain());
85   ASSERT_EQ(2u, r3.ip_data.ip);
86   SampleRecord r4;
87   ASSERT_TRUE(
88       r4.Parse(event_attr, r3.BinaryForTestingOnly(), r3.BinaryForTestingOnly() + r3.size()));
89   ASSERT_EQ(2u, r4.ip_data.ip);
90   ASSERT_EQ(3u, r4.callchain_data.ip_nr);
91   ASSERT_EQ(PERF_CONTEXT_USER, r4.callchain_data.ips[0]);
92   ASSERT_EQ(PERF_CONTEXT_USER, r4.callchain_data.ips[1]);
93   ASSERT_EQ(2u, r4.callchain_data.ips[2]);
94 
95   SampleRecord r5(event_attr, 0, 1, 0, 0, 0, 0, 0, {}, {1, 2}, {}, 0);
96   ASSERT_FALSE(r5.ExcludeKernelCallChain());
97   SampleRecord r6(event_attr, 0, 1, 0, 0, 0, 0, 0, {}, {1, 2, PERF_CONTEXT_USER}, {}, 0);
98   ASSERT_FALSE(r6.ExcludeKernelCallChain());
99 
100   // Process consecutive context values.
101   SampleRecord r7(event_attr, 0, 1, 0, 0, 0, 0, 0, {},
102                   {1, 2, PERF_CONTEXT_USER, PERF_CONTEXT_USER, 3, 4}, {}, 0);
103   r7.header.misc = PERF_RECORD_MISC_KERNEL;
104   ASSERT_TRUE(r7.ExcludeKernelCallChain());
105   CheckRecordEqual(r7, SampleRecord(event_attr, 0, 3, 0, 0, 0, 0, 0, {},
106                                     {PERF_CONTEXT_USER, PERF_CONTEXT_USER, PERF_CONTEXT_USER,
107                                      PERF_CONTEXT_USER, 3, 4},
108                                     {}, 0));
109 }
110 
111 // @CddTest = 6.1/C-0-2
TEST_F(RecordTest,SampleRecord_ReplaceRegAndStackWithCallChain)112 TEST_F(RecordTest, SampleRecord_ReplaceRegAndStackWithCallChain) {
113   event_attr.sample_type |= PERF_SAMPLE_CALLCHAIN;
114   std::vector<std::vector<uint64_t>> user_ip_tests = {
115       {},                     // no userspace ips, just remove stack and reg fields
116       {2},                    // add one userspace ip, no need to allocate new binary
117       {2, 3, 4, 5, 6, 7, 8},  // add more userspace ips, may need to allocate new binary
118   };
119   std::vector<uint64_t> stack_size_tests = {0, 8, 1024};
120 
121   for (const auto& user_ips : user_ip_tests) {
122     std::vector<uint64_t> ips = {1};
123     if (!user_ips.empty()) {
124       ips.push_back(PERF_CONTEXT_USER);
125       ips.insert(ips.end(), user_ips.begin(), user_ips.end());
126     }
127     SampleRecord expected(event_attr, 0, 1, 2, 3, 4, 5, 6, {}, ips, {}, 0);
128     for (size_t stack_size : stack_size_tests) {
129       event_attr.sample_type |= PERF_SAMPLE_REGS_USER | PERF_SAMPLE_STACK_USER;
130       SampleRecord r(event_attr, 0, 1, 2, 3, 4, 5, 6, {}, {1}, std::vector<char>(stack_size), 10);
131       event_attr.sample_type &= ~(PERF_SAMPLE_REGS_USER | PERF_SAMPLE_STACK_USER);
132       r.ReplaceRegAndStackWithCallChain(user_ips);
133       CheckRecordMatchBinary(r);
134       CheckRecordEqual(r, expected);
135 
136       // Test a sample with record size > the end of user stack (). See
137       // https://lkml.org/lkml/2024/5/28/1224.
138       event_attr.sample_type |= PERF_SAMPLE_REGS_USER | PERF_SAMPLE_STACK_USER;
139       SampleRecord r2(event_attr, 0, 1, 2, 3, 4, 5, 6, {}, {1}, std::vector<char>(stack_size), 10);
140 
141       std::vector<char> big_binary(r2.size() + 72, '\0');
142       memcpy(big_binary.data(), r2.Binary(), r2.size());
143       perf_event_header header;
144       memcpy(&header, big_binary.data(), sizeof(perf_event_header));
145       header.size = big_binary.size();
146       SampleRecord r3;
147       ASSERT_TRUE(r3.Parse(event_attr, big_binary.data(), big_binary.data() + big_binary.size()));
148       event_attr.sample_type &= ~(PERF_SAMPLE_REGS_USER | PERF_SAMPLE_STACK_USER);
149       r3.ReplaceRegAndStackWithCallChain(user_ips);
150       CheckRecordMatchBinary(r3);
151       CheckRecordEqual(r3, expected);
152     }
153   }
154 }
155 
156 // @CddTest = 6.1/C-0-2
TEST_F(RecordTest,SampleRecord_UpdateUserCallChain)157 TEST_F(RecordTest, SampleRecord_UpdateUserCallChain) {
158   event_attr.sample_type |= PERF_SAMPLE_CALLCHAIN;
159   SampleRecord r(event_attr, 0, 1, 2, 3, 4, 5, 6, {}, {1, PERF_CONTEXT_USER, 2}, {}, 0);
160   r.UpdateUserCallChain({3, 4, 5});
161   CheckRecordMatchBinary(r);
162   SampleRecord expected(event_attr, 0, 1, 2, 3, 4, 5, 6, {}, {1, PERF_CONTEXT_USER, 3, 4, 5}, {},
163                         0);
164   CheckRecordEqual(r, expected);
165 }
166 
167 // @CddTest = 6.1/C-0-2
TEST_F(RecordTest,SampleRecord_AdjustCallChainGeneratedByKernel)168 TEST_F(RecordTest, SampleRecord_AdjustCallChainGeneratedByKernel) {
169   event_attr.sample_type |= PERF_SAMPLE_CALLCHAIN | PERF_SAMPLE_REGS_USER | PERF_SAMPLE_STACK_USER;
170   SampleRecord r(event_attr, 0, 1, 2, 3, 4, 5, 6, {}, {1, 5, 0, PERF_CONTEXT_USER, 6, 0}, {}, 0);
171   r.header.misc = PERF_RECORD_MISC_KERNEL;
172   r.AdjustCallChainGeneratedByKernel();
173   uint64_t adjustValue = (GetTargetArch() == ARCH_ARM || GetTargetArch() == ARCH_ARM64) ? 2 : 1;
174   SampleRecord expected(event_attr, 0, 1, 2, 3, 4, 5, 6, {},
175                         {1, 5 - adjustValue, PERF_CONTEXT_KERNEL, PERF_CONTEXT_USER,
176                          6 - adjustValue, PERF_CONTEXT_USER},
177                         {}, 0);
178   expected.header.misc = PERF_RECORD_MISC_KERNEL;
179   CheckRecordEqual(r, expected);
180 }
181 
182 // @CddTest = 6.1/C-0-2
TEST_F(RecordTest,SampleRecord_PerfSampleReadData)183 TEST_F(RecordTest, SampleRecord_PerfSampleReadData) {
184   event_attr.sample_type |= PERF_SAMPLE_READ;
185   event_attr.read_format =
186       PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_TOTAL_TIME_RUNNING | PERF_FORMAT_ID;
187   PerfSampleReadType read_data;
188   read_data.time_enabled = 1000;
189   read_data.time_running = 500;
190   read_data.counts = {100};
191   read_data.ids = {200};
192   SampleRecord r(event_attr, 0, 1, 2, 3, 4, 5, 6, read_data, {}, {}, 0);
193   ASSERT_EQ(read_data.time_enabled, r.read_data.time_enabled);
194   ASSERT_EQ(read_data.time_running, r.read_data.time_running);
195   ASSERT_TRUE(read_data.counts == r.read_data.counts);
196   ASSERT_TRUE(read_data.ids == r.read_data.ids);
197   CheckRecordMatchBinary(r);
198   event_attr.read_format |= PERF_FORMAT_GROUP;
199   read_data.counts = {100, 200, 300, 400};
200   read_data.ids = {500, 600, 700, 800};
201   SampleRecord r2(event_attr, 0, 1, 2, 3, 4, 5, 6, read_data, {}, {}, 0);
202   ASSERT_EQ(read_data.time_enabled, r2.read_data.time_enabled);
203   ASSERT_EQ(read_data.time_running, r2.read_data.time_running);
204   ASSERT_TRUE(read_data.counts == r2.read_data.counts);
205   ASSERT_TRUE(read_data.ids == r2.read_data.ids);
206   CheckRecordMatchBinary(r2);
207 }
208 
209 // @CddTest = 6.1/C-0-2
TEST_F(RecordTest,CommRecord)210 TEST_F(RecordTest, CommRecord) {
211   CommRecord r(event_attr, 1, 2, "init_name", 3, 4);
212   size_t record_size = r.size();
213   std::string new_name = "a_much_longer_name";
214   r.SetCommandName(new_name);
215   ASSERT_EQ(r.size(), record_size + 8);
216   ASSERT_EQ(std::string(r.comm), new_name);
217   ASSERT_EQ(r.data->pid, 1u);
218   ASSERT_EQ(r.data->tid, 2u);
219   ASSERT_EQ(r.sample_id.id_data.id, 3u);
220   ASSERT_EQ(r.sample_id.time_data.time, 4u);
221   CheckRecordMatchBinary(r);
222 }
223 
224 // @CddTest = 6.1/C-0-2
TEST_F(RecordTest,DebugRecord)225 TEST_F(RecordTest, DebugRecord) {
226   DebugRecord r(1234, "hello");
227   ASSERT_EQ(r.size() % sizeof(uint64_t), 0);
228   ASSERT_EQ(r.Timestamp(), 1234);
229   ASSERT_STREQ(r.s, "hello");
230   CheckRecordMatchBinary(r);
231 }
232