• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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