1 /*
2 * Copyright (C) 2024 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 "src/trace_processor/importers/perf/perf_session.h"
18
19 #include <cstdint>
20 #include <cstring>
21
22 #include "perfetto/ext/base/status_or.h"
23 #include "perfetto/trace_processor/trace_blob.h"
24 #include "perfetto/trace_processor/trace_blob_view.h"
25 #include "src/trace_processor/importers/perf/perf_event.h"
26 #include "src/trace_processor/storage/trace_storage.h"
27 #include "src/trace_processor/types/trace_processor_context.h"
28 #include "test/gtest_and_gmock.h"
29
30 namespace perfetto::trace_processor::perf_importer {
31 namespace {
32
33 using ::testing::Eq;
34 using ::testing::NotNull;
35
36 MATCHER(IsOk, "is ok") {
37 return arg.ok();
38 }
39
40 MATCHER_P(IsOkAndHolds, matcher, "") {
41 return ExplainMatchResult(IsOk(), arg, result_listener) &&
42 ExplainMatchResult(matcher, *arg, result_listener);
43 }
44
TEST(PerfSessionTest,NoAttrBuildFails)45 TEST(PerfSessionTest, NoAttrBuildFails) {
46 TraceProcessorContext context;
47 context.storage.reset(new TraceStorage());
48 PerfSession::Builder builder(&context);
49 EXPECT_FALSE(builder.Build().ok());
50 }
51
TEST(PerfSessionTest,OneAttrAndNoIdBuildSucceeds)52 TEST(PerfSessionTest, OneAttrAndNoIdBuildSucceeds) {
53 TraceProcessorContext context;
54 context.storage.reset(new TraceStorage());
55 PerfSession::Builder builder(&context);
56 perf_event_attr attr;
57 attr.sample_id_all = false;
58 attr.sample_type = PERF_SAMPLE_CALLCHAIN | PERF_SAMPLE_CPU | PERF_SAMPLE_TIME;
59 builder.AddAttrAndIds(attr, {1});
60
61 auto session = builder.Build();
62 ASSERT_TRUE(session.ok());
63
64 EXPECT_THAT(
65 (*session)->FindAttrForRecord(perf_event_header{}, TraceBlobView()),
66 IsOkAndHolds(NotNull()));
67 }
68
TEST(PerfSessionTest,MultipleAttrsAndNoIdBuildFails)69 TEST(PerfSessionTest, MultipleAttrsAndNoIdBuildFails) {
70 TraceProcessorContext context;
71 context.storage.reset(new TraceStorage());
72 PerfSession::Builder builder(&context);
73 perf_event_attr attr;
74 attr.sample_id_all = true;
75 attr.sample_type = PERF_SAMPLE_CALLCHAIN | PERF_SAMPLE_CPU | PERF_SAMPLE_TIME;
76 builder.AddAttrAndIds(attr, {1});
77 builder.AddAttrAndIds(attr, {2});
78 EXPECT_FALSE(builder.Build().ok());
79 }
80
TEST(PerfSessionTest,MultipleIdsSameAttrAndNoIdCanExtractAttrFromRecord)81 TEST(PerfSessionTest, MultipleIdsSameAttrAndNoIdCanExtractAttrFromRecord) {
82 TraceProcessorContext context;
83 context.storage.reset(new TraceStorage());
84 PerfSession::Builder builder(&context);
85 perf_event_attr attr;
86 attr.sample_id_all = true;
87 attr.sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_CPU | PERF_SAMPLE_TIME;
88 builder.AddAttrAndIds(attr, {1, 2, 3});
89
90 auto session = builder.Build();
91 ASSERT_TRUE(session.ok());
92
93 perf_event_header header;
94 header.type = PERF_RECORD_SAMPLE;
95 auto attr_ptr = (*session)->FindAttrForRecord(header, TraceBlobView());
96
97 ASSERT_THAT(attr_ptr, IsOkAndHolds(NotNull()));
98 EXPECT_THAT((*attr_ptr)->sample_type(), Eq(attr.sample_type));
99
100 header.type = PERF_RECORD_MMAP2;
101 attr_ptr = (*session)->FindAttrForRecord(header, TraceBlobView());
102
103 ASSERT_THAT(attr_ptr, IsOkAndHolds(NotNull()));
104 EXPECT_THAT((*attr_ptr)->sample_type(), Eq(attr.sample_type));
105 }
106
TEST(PerfSessionTest,NoCommonSampleIdAllBuildFails)107 TEST(PerfSessionTest, NoCommonSampleIdAllBuildFails) {
108 TraceProcessorContext context;
109 context.storage.reset(new TraceStorage());
110 PerfSession::Builder builder(&context);
111 perf_event_attr attr;
112 attr.sample_id_all = true;
113 attr.sample_type = PERF_SAMPLE_IDENTIFIER;
114 builder.AddAttrAndIds(attr, {1});
115 builder.AddAttrAndIds(attr, {2});
116 // Make sure sample_type is correct (i.e. the test is really testing the
117 // sample_id_all).
118 ASSERT_TRUE(builder.Build().ok());
119
120 attr.sample_id_all = false;
121 builder.AddAttrAndIds(attr, {3});
122 EXPECT_FALSE(builder.Build().ok());
123 }
124
TEST(PerfSessionTest,NoCommonOffsetForSampleBuildFails)125 TEST(PerfSessionTest, NoCommonOffsetForSampleBuildFails) {
126 TraceProcessorContext context;
127 context.storage.reset(new TraceStorage());
128 PerfSession::Builder builder(&context);
129 perf_event_attr attr;
130 attr.sample_id_all = true;
131 attr.sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_ID;
132 builder.AddAttrAndIds(attr, {1});
133 attr.sample_type |= PERF_SAMPLE_TID;
134 builder.AddAttrAndIds(attr, {2});
135 EXPECT_FALSE(builder.Build().ok());
136 }
137
TEST(PerfSessionTest,NoCommonOffsetForNonSampleBuildFails)138 TEST(PerfSessionTest, NoCommonOffsetForNonSampleBuildFails) {
139 TraceProcessorContext context;
140 context.storage.reset(new TraceStorage());
141 PerfSession::Builder builder(&context);
142 perf_event_attr attr;
143 attr.sample_id_all = true;
144 attr.sample_type = PERF_SAMPLE_ID | PERF_SAMPLE_TID;
145 builder.AddAttrAndIds(attr, {1});
146 builder.AddAttrAndIds(attr, {2});
147 // Make sure sample_type is correct (i.e. the test is really testing the
148 // non common sample_type).
149 ASSERT_TRUE(builder.Build().ok());
150
151 attr.sample_type |= PERF_SAMPLE_IDENTIFIER;
152 builder.AddAttrAndIds(attr, {3});
153 EXPECT_FALSE(builder.Build().ok());
154 }
155
TEST(PerfSessionTest,NoCommonOffsetForNonSampleAndNoSampleIdAllBuildSucceeds)156 TEST(PerfSessionTest, NoCommonOffsetForNonSampleAndNoSampleIdAllBuildSucceeds) {
157 TraceProcessorContext context;
158 context.storage.reset(new TraceStorage());
159 PerfSession::Builder builder(&context);
160 perf_event_attr attr;
161 attr.sample_id_all = false;
162 attr.sample_type = PERF_SAMPLE_IDENTIFIER | PERF_SAMPLE_TID;
163 builder.AddAttrAndIds(attr, {1});
164 attr.sample_type |= PERF_SAMPLE_ID;
165 builder.AddAttrAndIds(attr, {2});
166 EXPECT_TRUE(builder.Build().ok());
167 }
168
TEST(PerfSessionTest,MultiplesessionBuildSucceeds)169 TEST(PerfSessionTest, MultiplesessionBuildSucceeds) {
170 TraceProcessorContext context;
171 context.storage.reset(new TraceStorage());
172 PerfSession::Builder builder(&context);
173 perf_event_attr attr;
174 attr.sample_id_all = true;
175 attr.sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_ID;
176 builder.AddAttrAndIds(attr, {1});
177 builder.AddAttrAndIds(attr, {2});
178 EXPECT_TRUE(builder.Build().ok());
179 }
180
TEST(PerfSessionTest,FindAttrInRecordWithId)181 TEST(PerfSessionTest, FindAttrInRecordWithId) {
182 TraceProcessorContext context;
183 context.storage.reset(new TraceStorage());
184 PerfSession::Builder builder(&context);
185 perf_event_attr attr;
186 attr.sample_id_all = true;
187 attr.sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_ID;
188 attr.read_format = 1;
189 builder.AddAttrAndIds(attr, {1});
190 attr.read_format = 2;
191 builder.AddAttrAndIds(attr, {2});
192
193 auto session = builder.Build();
194 ASSERT_TRUE(session.ok());
195
196 struct {
197 uint64_t ip = 1234;
198 uint64_t id = 2;
199 } data;
200
201 perf_event_header header;
202 header.type = PERF_RECORD_SAMPLE;
203 auto attr_ptr = (*session)->FindAttrForRecord(
204 header, TraceBlobView(TraceBlob ::CopyFrom(&data, sizeof(data))));
205
206 ASSERT_THAT(attr_ptr, IsOkAndHolds(NotNull()));
207 EXPECT_THAT((*attr_ptr)->read_format(), Eq(2u));
208
209 header.type = PERF_RECORD_MMAP2;
210 data.id = 1;
211 attr_ptr = (*session)->FindAttrForRecord(
212 header, TraceBlobView(TraceBlob::CopyFrom(&data, sizeof(data))));
213
214 ASSERT_THAT(attr_ptr, IsOkAndHolds(NotNull()));
215 EXPECT_THAT((*attr_ptr)->read_format(), Eq(1u));
216 }
217
TEST(PerfSessionTest,FindAttrInRecordWithIdentifier)218 TEST(PerfSessionTest, FindAttrInRecordWithIdentifier) {
219 TraceProcessorContext context;
220 context.storage.reset(new TraceStorage());
221 PerfSession::Builder builder(&context);
222 perf_event_attr attr;
223 attr.sample_id_all = true;
224 attr.sample_type = PERF_SAMPLE_IDENTIFIER | PERF_SAMPLE_IP;
225 attr.read_format = 1;
226 builder.AddAttrAndIds(attr, {1});
227 attr.read_format = 2;
228 builder.AddAttrAndIds(attr, {2});
229
230 auto session = builder.Build();
231 ASSERT_TRUE(session.ok());
232
233 struct {
234 uint64_t identifier = 2;
235 uint64_t ip = 1234;
236 } sample;
237
238 struct {
239 uint64_t ip = 1234;
240 uint64_t identifier = 1;
241 } mmap;
242
243 perf_event_header header;
244 header.type = PERF_RECORD_SAMPLE;
245 auto attr_ptr = (*session)->FindAttrForRecord(
246 header, TraceBlobView(TraceBlob ::CopyFrom(&sample, sizeof(sample))));
247
248 ASSERT_THAT(attr_ptr, IsOkAndHolds(NotNull()));
249 EXPECT_THAT((*attr_ptr)->read_format(), Eq(2u));
250
251 header.type = PERF_RECORD_MMAP2;
252 attr_ptr = (*session)->FindAttrForRecord(
253 header, TraceBlobView(TraceBlob::CopyFrom(&mmap, sizeof(mmap))));
254
255 ASSERT_THAT(attr_ptr, IsOkAndHolds(NotNull()));
256 EXPECT_THAT((*attr_ptr)->read_format(), Eq(1u));
257 }
258
259 } // namespace
260 } // namespace perfetto::trace_processor::perf_importer
261