1 /*
2 * Copyright (C) 2017 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/ftrace_reader/proto_translation_table.h"
18
19 #include "gmock/gmock.h"
20 #include "gtest/gtest.h"
21 #include "src/ftrace_reader/event_info.h"
22 #include "src/ftrace_reader/ftrace_procfs.h"
23
24 using testing::_;
25 using testing::ValuesIn;
26 using testing::TestWithParam;
27 using testing::Return;
28 using testing::AnyNumber;
29 using testing::IsNull;
30 using testing::Contains;
31 using testing::Eq;
32 using testing::Pointee;
33
34 namespace perfetto {
35 namespace {
36
37 class MockFtraceProcfs : public FtraceProcfs {
38 public:
MockFtraceProcfs()39 MockFtraceProcfs() : FtraceProcfs("/root/") {}
40
41 MOCK_CONST_METHOD2(ReadEventFormat,
42 std::string(const std::string& group,
43 const std::string& name));
44 };
45
46 class AllTranslationTableTest : public TestWithParam<const char*> {
47 public:
SetUp()48 void SetUp() override {
49 std::string path =
50 "src/ftrace_reader/test/data/" + std::string(GetParam()) + "/";
51 FtraceProcfs ftrace_procfs(path);
52 table_ = ProtoTranslationTable::Create(&ftrace_procfs, GetStaticEventInfo(),
53 GetStaticCommonFieldsInfo());
54 PERFETTO_CHECK(table_);
55 }
56
57 std::unique_ptr<ProtoTranslationTable> table_;
58 };
59
60 const char* kDevices[] = {
61 "android_seed_N2F62_3.10.49", "android_hammerhead_MRA59G_3.4.0",
62 };
63
TEST_P(AllTranslationTableTest,Create)64 TEST_P(AllTranslationTableTest, Create) {
65 EXPECT_TRUE(table_);
66 EXPECT_TRUE(table_->GetEventByName("print"));
67 EXPECT_TRUE(table_->GetEventByName("sched_switch"));
68 EXPECT_TRUE(table_->GetEventByName("sched_wakeup"));
69 EXPECT_TRUE(table_->GetEventByName("ext4_da_write_begin"));
70 for (const Event& event : table_->events()) {
71 if (!event.ftrace_event_id)
72 continue;
73 EXPECT_TRUE(event.name);
74 EXPECT_TRUE(event.group);
75 EXPECT_TRUE(event.proto_field_id);
76 for (const Field& field : event.fields) {
77 EXPECT_TRUE(field.proto_field_id);
78 EXPECT_TRUE(field.ftrace_type);
79 EXPECT_TRUE(field.proto_field_type);
80 }
81 }
82 ASSERT_EQ(table_->common_fields().size(), 1u);
83 const Field& pid_field = table_->common_fields().at(0);
84 EXPECT_EQ(std::string(pid_field.ftrace_name), "common_pid");
85 EXPECT_EQ(pid_field.proto_field_id, 2u);
86
87 {
88 auto event = table_->GetEventByName("print");
89 EXPECT_TRUE(event);
90 EXPECT_EQ(std::string(event->name), "print");
91 EXPECT_EQ(std::string(event->group), "ftrace");
92 EXPECT_EQ(event->fields.at(1).proto_field_type, kProtoString);
93 EXPECT_EQ(event->fields.at(1).ftrace_type, kFtraceCString);
94 EXPECT_EQ(event->fields.at(1).strategy, kCStringToString);
95 }
96 }
97
98 INSTANTIATE_TEST_CASE_P(ByDevice, AllTranslationTableTest, ValuesIn(kDevices));
99
TEST(TranslationTableTest,Seed)100 TEST(TranslationTableTest, Seed) {
101 std::string path = "src/ftrace_reader/test/data/android_seed_N2F62_3.10.49/";
102 FtraceProcfs ftrace_procfs(path);
103 auto table = ProtoTranslationTable::Create(
104 &ftrace_procfs, GetStaticEventInfo(), GetStaticCommonFieldsInfo());
105 const Field& pid_field = table->common_fields().at(0);
106 EXPECT_EQ(std::string(pid_field.ftrace_name), "common_pid");
107 EXPECT_EQ(pid_field.proto_field_id, 2u);
108 EXPECT_EQ(pid_field.ftrace_offset, 4u);
109 EXPECT_EQ(pid_field.ftrace_size, 4u);
110
111 {
112 auto event = table->GetEventByName("sched_switch");
113 EXPECT_EQ(std::string(event->name), "sched_switch");
114 EXPECT_EQ(std::string(event->group), "sched");
115 EXPECT_EQ(event->ftrace_event_id, 68ul);
116 EXPECT_EQ(event->fields.at(0).ftrace_offset, 8u);
117 EXPECT_EQ(event->fields.at(0).ftrace_size, 16u);
118 }
119
120 {
121 auto event = table->GetEventByName("sched_wakeup");
122 EXPECT_EQ(std::string(event->name), "sched_wakeup");
123 EXPECT_EQ(std::string(event->group), "sched");
124 EXPECT_EQ(event->ftrace_event_id, 70ul);
125 EXPECT_EQ(event->fields.at(0).ftrace_offset, 8u);
126 EXPECT_EQ(event->fields.at(0).ftrace_size, 16u);
127 }
128
129 {
130 auto event = table->GetEventByName("cpufreq_interactive_target");
131 EXPECT_EQ(std::string(event->name), "cpufreq_interactive_target");
132 EXPECT_EQ(std::string(event->group), "cpufreq_interactive");
133 EXPECT_EQ(event->ftrace_event_id, 509ul);
134 EXPECT_EQ(event->fields.at(0).ftrace_offset, 8u);
135 EXPECT_EQ(event->fields.at(0).ftrace_size, 4u);
136 }
137
138 {
139 auto event = table->GetEventByName("ext4_da_write_begin");
140 EXPECT_EQ(std::string(event->name), "ext4_da_write_begin");
141 EXPECT_EQ(std::string(event->group), "ext4");
142 EXPECT_EQ(event->ftrace_event_id, 303ul);
143 EXPECT_EQ(event->fields.at(0).ftrace_offset, 8u);
144 EXPECT_EQ(event->fields.at(0).ftrace_size, 4u);
145 }
146 }
147
TEST(TranslationTableTest,Create)148 TEST(TranslationTableTest, Create) {
149 MockFtraceProcfs ftrace;
150 std::vector<Field> common_fields;
151 std::vector<Event> events;
152
153 ON_CALL(ftrace, ReadEventFormat(_, _)).WillByDefault(Return(""));
154 ON_CALL(ftrace, ReadEventFormat("group", "foo"))
155 .WillByDefault(Return(R"(name: foo
156 ID: 42
157 format:
158 field:unsigned short common_type; offset:0; size:2; signed:0;
159 field:int common_pid; offset:4; size:4; signed:1;
160
161 field:char field_a[16]; offset:8; size:16; signed:0;
162 field:int field_b; offset:24; size:4; signed:1;
163 field:int field_d; offset:28; size:4; signed:1;
164 field:u32 field_e; offset:32; size:4; signed:0;
165
166 print fmt: "some format")"));
167 ;
168
169 EXPECT_CALL(ftrace, ReadEventFormat(_, _)).Times(AnyNumber());
170
171 {
172 events.emplace_back(Event{});
173 Event* event = &events.back();
174 event->name = "foo";
175 event->group = "group";
176 event->proto_field_id = 21;
177
178 {
179 // We should get this field.
180 event->fields.emplace_back(Field{});
181 Field* field = &event->fields.back();
182 field->proto_field_id = 501;
183 field->proto_field_type = kProtoString;
184 field->ftrace_name = "field_a";
185 }
186
187 {
188 // We shouldn't get this field: don't know how to read int -> string.
189 event->fields.emplace_back(Field{});
190 Field* field = &event->fields.back();
191 field->proto_field_id = 502;
192 field->proto_field_type = kProtoString;
193 field->ftrace_name = "field_b";
194 }
195
196 {
197 // We shouldn't get this field: no matching field in the format file.
198 event->fields.emplace_back(Field{});
199 Field* field = &event->fields.back();
200 field->proto_field_id = 503;
201 field->proto_field_type = kProtoString;
202 field->ftrace_name = "field_c";
203 }
204
205 {
206 // We should get this field.
207 event->fields.emplace_back(Field{});
208 Field* field = &event->fields.back();
209 field->proto_field_id = 504;
210 field->proto_field_type = kProtoUint64;
211 field->ftrace_name = "field_e";
212 }
213 }
214
215 {
216 events.emplace_back(Event{});
217 Event* event = &events.back();
218 event->name = "bar";
219 event->group = "group";
220 event->proto_field_id = 22;
221 }
222
223 auto table = ProtoTranslationTable::Create(&ftrace, std::move(events),
224 std::move(common_fields));
225 EXPECT_EQ(table->largest_id(), 42ul);
226 EXPECT_EQ(table->EventNameToFtraceId("foo"), 42ul);
227 EXPECT_EQ(table->EventNameToFtraceId("bar"), 0ul);
228 EXPECT_EQ(table->EventNameToFtraceId("bar"), 0ul);
229 EXPECT_FALSE(table->GetEventById(43ul));
230 ASSERT_TRUE(table->GetEventById(42ul));
231 auto event = table->GetEventById(42);
232 EXPECT_EQ(event->ftrace_event_id, 42ul);
233 EXPECT_EQ(event->proto_field_id, 21ul);
234 EXPECT_EQ(event->size, 36u);
235 EXPECT_EQ(std::string(event->name), "foo");
236 EXPECT_EQ(std::string(event->group), "group");
237
238 ASSERT_EQ(event->fields.size(), 2ul);
239 auto field_a = event->fields.at(0);
240 EXPECT_EQ(field_a.proto_field_id, 501ul);
241 EXPECT_EQ(field_a.strategy, kFixedCStringToString);
242
243 auto field_e = event->fields.at(1);
244 EXPECT_EQ(field_e.proto_field_id, 504ul);
245 EXPECT_EQ(field_e.strategy, kUint32ToUint64);
246 }
247
TEST(TranslationTableTest,InferFtraceType)248 TEST(TranslationTableTest, InferFtraceType) {
249 FtraceFieldType type;
250
251 ASSERT_TRUE(InferFtraceType("char foo[16]", 16, false, &type));
252 EXPECT_EQ(type, kFtraceFixedCString);
253
254 ASSERT_TRUE(InferFtraceType("__data_loc char[] foo", 4, false, &type));
255 EXPECT_EQ(type, kFtraceStringPtr);
256
257 ASSERT_TRUE(InferFtraceType("char[] foo", 8, false, &type));
258 EXPECT_EQ(type, kFtraceStringPtr);
259
260 ASSERT_TRUE(InferFtraceType("char * foo", 8, false, &type));
261 EXPECT_EQ(type, kFtraceStringPtr);
262
263 ASSERT_TRUE(InferFtraceType("char foo[64]", 64, false, &type));
264 EXPECT_EQ(type, kFtraceFixedCString);
265
266 ASSERT_TRUE(InferFtraceType("u32 foo", 4, false, &type));
267 EXPECT_EQ(type, kFtraceUint32);
268
269 ASSERT_TRUE(InferFtraceType("i_ino foo", 4, false, &type));
270 ASSERT_EQ(type, kFtraceInode32);
271
272 ASSERT_TRUE(InferFtraceType("i_ino foo", 8, false, &type));
273 ASSERT_EQ(type, kFtraceInode64);
274
275 ASSERT_TRUE(InferFtraceType("ino_t foo", 4, false, &type));
276 ASSERT_EQ(type, kFtraceInode32);
277
278 ASSERT_TRUE(InferFtraceType("ino_t foo", 8, false, &type));
279 ASSERT_EQ(type, kFtraceInode64);
280
281 ASSERT_TRUE(InferFtraceType("dev_t foo", 4, false, &type));
282 ASSERT_EQ(type, kFtraceDevId32);
283
284 ASSERT_TRUE(InferFtraceType("dev_t foo", 8, false, &type));
285 ASSERT_EQ(type, kFtraceDevId64);
286
287 ASSERT_TRUE(InferFtraceType("pid_t foo", 4, false, &type));
288 ASSERT_EQ(type, kFtracePid32);
289
290 ASSERT_TRUE(InferFtraceType("int common_pid", 4, false, &type));
291 ASSERT_EQ(type, kFtraceCommonPid32);
292
293 ASSERT_TRUE(InferFtraceType("char foo", 1, true, &type));
294 ASSERT_EQ(type, kFtraceInt8);
295
296 EXPECT_FALSE(InferFtraceType("foo", 64, false, &type));
297 }
298
TEST(TranslationTableTest,Getters)299 TEST(TranslationTableTest, Getters) {
300 std::vector<Field> common_fields;
301 std::vector<Event> events;
302
303 {
304 Event event;
305 event.name = "foo";
306 event.group = "group_one";
307 event.ftrace_event_id = 1;
308 events.push_back(event);
309 }
310
311 {
312 Event event;
313 event.name = "bar";
314 event.group = "group_one";
315 event.ftrace_event_id = 2;
316 events.push_back(event);
317 }
318
319 {
320 Event event;
321 event.name = "baz";
322 event.group = "group_two";
323 event.ftrace_event_id = 100;
324 events.push_back(event);
325 }
326
327 ProtoTranslationTable table(events, std::move(common_fields));
328 EXPECT_EQ(table.largest_id(), 100ul);
329 EXPECT_EQ(table.EventNameToFtraceId("foo"), 1ul);
330 EXPECT_EQ(table.EventNameToFtraceId("baz"), 100ul);
331 EXPECT_EQ(table.EventNameToFtraceId("no_such_event"), 0ul);
332 EXPECT_EQ(table.GetEventById(1)->name, "foo");
333 EXPECT_EQ(table.GetEventById(3), nullptr);
334 EXPECT_EQ(table.GetEventById(200), nullptr);
335 EXPECT_EQ(table.GetEventById(0), nullptr);
336 EXPECT_EQ(table.GetEventByName("foo")->ftrace_event_id, 1u);
337 EXPECT_THAT(*table.GetEventsByGroup("group_one"),
338 Contains(testing::Field(&Event::name, "foo")));
339 EXPECT_THAT(*table.GetEventsByGroup("group_one"),
340 Contains(testing::Field(&Event::name, "bar")));
341 EXPECT_THAT(*table.GetEventsByGroup("group_two"),
342 Contains(testing::Field(&Event::name, "baz")));
343 EXPECT_THAT(table.GetEventsByGroup("group_three"), IsNull());
344 }
345
346 } // namespace
347 } // namespace perfetto
348