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