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