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 class RecordTest : public ::testing::Test {
25  protected:
SetUp()26   virtual void SetUp() {
27     const EventType* type = FindEventTypeByName("cpu-clock");
28     ASSERT_TRUE(type != nullptr);
29     event_attr = CreateDefaultPerfEventAttr(*type);
30     event_attr.sample_id_all = 1;
31   }
32 
CheckRecordMatchBinary(Record & record)33   void CheckRecordMatchBinary(Record& record) {
34     std::vector<std::unique_ptr<Record>> records =
35         ReadRecordsFromBuffer(event_attr, record.BinaryForTestingOnly(), record.size());
36     ASSERT_EQ(1u, records.size());
37     CheckRecordEqual(record, *records[0]);
38   }
39 
40   perf_event_attr event_attr;
41 };
42 
TEST_F(RecordTest,MmapRecordMatchBinary)43 TEST_F(RecordTest, MmapRecordMatchBinary) {
44   MmapRecord record(event_attr, true, 1, 2, 0x1000, 0x2000, 0x3000,
45                     "MmapRecord", 0);
46   CheckRecordMatchBinary(record);
47 }
48 
TEST_F(RecordTest,CommRecordMatchBinary)49 TEST_F(RecordTest, CommRecordMatchBinary) {
50   CommRecord record(event_attr, 1, 2, "CommRecord", 0, 7);
51   CheckRecordMatchBinary(record);
52 }
53 
TEST_F(RecordTest,SampleRecordMatchBinary)54 TEST_F(RecordTest, SampleRecordMatchBinary) {
55   event_attr.sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_TIME
56                            | PERF_SAMPLE_ID | PERF_SAMPLE_CPU
57                            | 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(event_attr, r1.BinaryForTestingOnly());
71   ASSERT_EQ(1u, r.ip_data.ip);
72   ASSERT_EQ(2u, r2.callchain_data.ip_nr);
73   ASSERT_EQ(PERF_CONTEXT_USER, r2.callchain_data.ips[0]);
74   ASSERT_EQ(2u, r2.callchain_data.ips[1]);
75 
76   SampleRecord r3(event_attr, 0, 1, 0, 0, 0, 0, 0, {1, PERF_CONTEXT_USER, 2}, {}, 0);
77   ASSERT_TRUE(r3.ExcludeKernelCallChain());
78   ASSERT_EQ(2u, r3.ip_data.ip);
79   SampleRecord r4(event_attr, r3.BinaryForTestingOnly());
80   ASSERT_EQ(2u, r4.ip_data.ip);
81   ASSERT_EQ(3u, r4.callchain_data.ip_nr);
82   ASSERT_EQ(PERF_CONTEXT_USER, r4.callchain_data.ips[0]);
83   ASSERT_EQ(PERF_CONTEXT_USER, r4.callchain_data.ips[1]);
84   ASSERT_EQ(2u, r4.callchain_data.ips[2]);
85 
86   SampleRecord r5(event_attr, 0, 1, 0, 0, 0, 0, 0, {1, 2}, {}, 0);
87   ASSERT_FALSE(r5.ExcludeKernelCallChain());
88   SampleRecord r6(event_attr, 0, 1, 0, 0, 0, 0, 0, {1, 2, PERF_CONTEXT_USER}, {}, 0);
89   ASSERT_FALSE(r6.ExcludeKernelCallChain());
90 
91   // Process consecutive context values.
92   SampleRecord r7(event_attr, 0, 1, 0, 0, 0, 0, 0,
93                   {1, 2, PERF_CONTEXT_USER, PERF_CONTEXT_USER, 3, 4}, {}, 0);
94   r7.header.misc = PERF_RECORD_MISC_KERNEL;
95   ASSERT_TRUE(r7.ExcludeKernelCallChain());
96   CheckRecordEqual(r7, SampleRecord(event_attr, 0, 3, 0, 0, 0, 0, 0,
97                                     {PERF_CONTEXT_USER, PERF_CONTEXT_USER, PERF_CONTEXT_USER,
98                                      PERF_CONTEXT_USER, 3, 4}, {}, 0));
99 }
100 
TEST_F(RecordTest,SampleRecord_ReplaceRegAndStackWithCallChain)101 TEST_F(RecordTest, SampleRecord_ReplaceRegAndStackWithCallChain) {
102   event_attr.sample_type |= PERF_SAMPLE_CALLCHAIN | PERF_SAMPLE_REGS_USER | PERF_SAMPLE_STACK_USER;
103   SampleRecord expected(event_attr, 0, 1, 2, 3, 4, 5, 6, {1, PERF_CONTEXT_USER, 2, 3, 4, 5}, {},
104                         0);
105   for (size_t stack_size : {8, 1024}) {
106     SampleRecord r(event_attr, 0, 1, 2, 3, 4, 5, 6, {1}, std::vector<char>(stack_size), 10);
107     r.ReplaceRegAndStackWithCallChain({2, 3, 4, 5});
108     CheckRecordMatchBinary(r);
109     CheckRecordEqual(r, expected);
110   }
111 }
112 
TEST_F(RecordTest,SampleRecord_UpdateUserCallChain)113 TEST_F(RecordTest, SampleRecord_UpdateUserCallChain) {
114   event_attr.sample_type |= PERF_SAMPLE_CALLCHAIN | PERF_SAMPLE_REGS_USER | PERF_SAMPLE_STACK_USER;
115   SampleRecord r(event_attr, 0, 1, 2, 3, 4, 5, 6, {1, PERF_CONTEXT_USER, 2}, {}, 0);
116   r.UpdateUserCallChain({3, 4, 5});
117   CheckRecordMatchBinary(r);
118   SampleRecord expected(event_attr, 0, 1, 2, 3, 4, 5, 6, {1, PERF_CONTEXT_USER, 3, 4, 5}, {}, 0);
119   CheckRecordEqual(r, expected);
120 }
121 
TEST_F(RecordTest,SampleRecord_AdjustCallChainGeneratedByKernel)122 TEST_F(RecordTest, SampleRecord_AdjustCallChainGeneratedByKernel) {
123   event_attr.sample_type |= PERF_SAMPLE_CALLCHAIN | PERF_SAMPLE_REGS_USER | PERF_SAMPLE_STACK_USER;
124   SampleRecord r(event_attr, 0, 1, 2, 3, 4, 5, 6, {1, 5, 0, PERF_CONTEXT_USER, 6, 0}, {}, 0);
125   r.header.misc = PERF_RECORD_MISC_KERNEL;
126   r.AdjustCallChainGeneratedByKernel();
127   uint64_t adjustValue = (GetBuildArch() == ARCH_ARM || GetBuildArch() == ARCH_ARM64) ? 2 : 1;
128   SampleRecord expected(event_attr, 0, 1, 2, 3, 4, 5, 6,
129                         {1, 5 - adjustValue, PERF_CONTEXT_KERNEL, PERF_CONTEXT_USER,
130                          6 - adjustValue, PERF_CONTEXT_USER}, {}, 0);
131   expected.header.misc = PERF_RECORD_MISC_KERNEL;
132   CheckRecordEqual(r, expected);
133 }
134 
TEST_F(RecordTest,CommRecord)135 TEST_F(RecordTest, CommRecord) {
136   CommRecord r(event_attr, 1, 2, "init_name", 3, 4);
137   size_t record_size = r.size();
138   std::string new_name = "a_much_longer_name";
139   r.SetCommandName(new_name);
140   ASSERT_EQ(r.size(), record_size + 8);
141   ASSERT_EQ(std::string(r.comm), new_name);
142   ASSERT_EQ(r.data->pid, 1u);
143   ASSERT_EQ(r.data->tid, 2u);
144   ASSERT_EQ(r.sample_id.id_data.id, 3u);
145   ASSERT_EQ(r.sample_id.time_data.time, 4u);
146   CheckRecordMatchBinary(r);
147 }
148