blob: 3282ff944812d7602f1248b3ce364a07a15bbea9 [file] [log] [blame]
Hector Dearman3d8970f2017-10-31 09:27:15 +00001/*
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
Hector Dearman0d300332017-11-22 11:05:34 +000017#include "cpu_reader.h"
Hector Dearman3d8970f2017-10-31 09:27:15 +000018
Hector Dearman2193ff42017-11-08 14:15:19 +000019#include <utility>
20
Hector Dearmanf5035e22017-11-13 12:52:46 +000021#include "base/logging.h"
Hector Dearman0d300332017-11-22 11:05:34 +000022#include "proto_translation_table.h"
Hector Dearman72a49052017-11-08 14:12:55 +000023
Primiano Tucci2ee254a2017-11-15 00:38:48 +000024#include "protos/ftrace/ftrace_event.pbzero.h"
Hector Dearmanbefe55b2017-11-24 19:02:59 +000025#include "protos/ftrace/print.pbzero.h"
Hector Dearman8d8ccd32017-11-27 16:06:34 +000026#include "protos/ftrace/sched_switch.pbzero.h"
Primiano Tucci2ee254a2017-11-15 00:38:48 +000027
Primiano Tucci5f48d7b2017-11-27 16:57:13 +000028#include "protos/ftrace/ftrace_event_bundle.pbzero.h"
29
Hector Dearman3d8970f2017-10-31 09:27:15 +000030namespace perfetto {
31
Hector Dearmanf5035e22017-11-13 12:52:46 +000032namespace {
33
Hector Dearman0d300332017-11-22 11:05:34 +000034using BundleHandle =
Primiano Tucci5f48d7b2017-11-27 16:57:13 +000035 protozero::ProtoZeroMessageHandle<protos::pbzero::FtraceEventBundle>;
Hector Dearman0d300332017-11-22 11:05:34 +000036
37const std::vector<bool> BuildEnabledVector(const ProtoTranslationTable& table,
38 const std::set<std::string>& names) {
39 std::vector<bool> enabled(table.largest_id() + 1);
40 for (const std::string& name : names) {
41 const ProtoTranslationTable::Event* event = table.GetEventByName(name);
42 if (!event)
43 continue;
44 enabled[event->ftrace_event_id] = true;
45 }
46 return enabled;
47}
48
Hector Dearmanf5035e22017-11-13 12:52:46 +000049// For further documentation of these constants see the kernel source:
50// linux/include/linux/ring_buffer.h
51// Some information about the values of these constants are exposed to user
52// space at: /sys/kernel/debug/tracing/events/header_event
53const uint32_t kTypeDataTypeLengthMax = 28;
54const uint32_t kTypePadding = 29;
55const uint32_t kTypeTimeExtend = 30;
56const uint32_t kTypeTimeStamp = 31;
57
58const size_t kPageSize = 4096;
59
60struct PageHeader {
61 uint64_t timestamp;
62 uint32_t size;
63 uint32_t : 24;
64 uint32_t overwrite : 8;
65};
66
67struct EventHeader {
68 uint32_t type_or_length : 5;
69 uint32_t time_delta : 27;
70};
71
72struct TimeStamp {
73 uint64_t tv_nsec;
74 uint64_t tv_sec;
75};
76
77} // namespace
78
Hector Dearman0d300332017-11-22 11:05:34 +000079EventFilter::EventFilter(const ProtoTranslationTable& table,
80 std::set<std::string> names)
81 : enabled_ids_(BuildEnabledVector(table, names)),
82 enabled_names_(std::move(names)) {}
83EventFilter::~EventFilter() = default;
84
85CpuReader::CpuReader(const ProtoTranslationTable* table,
86 size_t cpu,
87 base::ScopedFile fd)
Hector Dearman72a49052017-11-08 14:12:55 +000088 : table_(table), cpu_(cpu), fd_(std::move(fd)) {}
89
Hector Dearman0d300332017-11-22 11:05:34 +000090int CpuReader::GetFileDescriptor() {
91 return fd_.get();
92}
93
94bool CpuReader::Drain(const std::array<const EventFilter*, kMaxSinks>& filters,
95 const std::array<BundleHandle, kMaxSinks>& bundles) {
Hector Dearmanf5035e22017-11-13 12:52:46 +000096 if (!fd_)
97 return false;
98
99 uint8_t* buffer = GetBuffer();
100 // TOOD(hjd): One read() per page may be too many.
101 long bytes = PERFETTO_EINTR(read(fd_.get(), buffer, kPageSize));
102 if (bytes == -1 || bytes == 0)
103 return false;
104 PERFETTO_CHECK(bytes <= kPageSize);
105
Hector Dearman0d300332017-11-22 11:05:34 +0000106 for (size_t i = 0; i < kMaxSinks; i++) {
107 if (!filters[i])
108 break;
Hector Dearman8d8ccd32017-11-27 16:06:34 +0000109 bool result =
110 ParsePage(cpu_, buffer, bytes, filters[i], &*bundles[i], table_);
111 PERFETTO_DCHECK(result);
Hector Dearman0d300332017-11-22 11:05:34 +0000112 }
113 return true;
Hector Dearmanf5035e22017-11-13 12:52:46 +0000114}
Hector Dearman72a49052017-11-08 14:12:55 +0000115
Hector Dearman0d300332017-11-22 11:05:34 +0000116CpuReader::~CpuReader() = default;
Hector Dearman3d8970f2017-10-31 09:27:15 +0000117
Hector Dearman0d300332017-11-22 11:05:34 +0000118uint8_t* CpuReader::GetBuffer() {
Hector Dearmanf5035e22017-11-13 12:52:46 +0000119 // TODO(primiano): Guard against overflows, like BufferedFrameDeserializer.
120 if (!buffer_)
121 buffer_ = std::unique_ptr<uint8_t[]>(new uint8_t[kPageSize]);
122 return buffer_.get();
123}
124
125// The structure of a raw trace buffer page is as follows:
126// First a page header:
127// 8 bytes of timestamp
128// 8 bytes of page length TODO(hjd): other fields also defined here?
129// // TODO(hjd): Document rest of format.
130// Some information about the layout of the page header is available in user
131// space at: /sys/kernel/debug/tracing/events/header_event
132// This method is deliberately static so it can be tested independently.
Hector Dearman0d300332017-11-22 11:05:34 +0000133bool CpuReader::ParsePage(size_t cpu,
134 const uint8_t* ptr,
135 size_t size,
136 const EventFilter* filter,
Primiano Tucci5f48d7b2017-11-27 16:57:13 +0000137 protos::pbzero::FtraceEventBundle* bundle,
Hector Dearman8d8ccd32017-11-27 16:06:34 +0000138 const ProtoTranslationTable* table) {
139 // TODO(hjd): Remove when the generic parser comes in.
140 const size_t print_id = table->GetEventByName("print")->ftrace_event_id;
141 const size_t sched_switch_id =
142 table->GetEventByName("sched_switch")->ftrace_event_id;
143
Hector Dearmanbefe55b2017-11-24 19:02:59 +0000144 const uint8_t* const start_of_page = ptr;
145 const uint8_t* const end_of_page = ptr + size;
Hector Dearman8d8ccd32017-11-27 16:06:34 +0000146
Hector Dearmanf5035e22017-11-13 12:52:46 +0000147 bundle->set_cpu(cpu);
148
Hector Dearman8d8ccd32017-11-27 16:06:34 +0000149 (void)start_of_page;
150
Hector Dearmanf5035e22017-11-13 12:52:46 +0000151 // TODO(hjd): Read this format dynamically?
152 PageHeader page_header;
Hector Dearmanbefe55b2017-11-24 19:02:59 +0000153 if (!ReadAndAdvance(&ptr, end_of_page, &page_header))
Hector Dearmanf5035e22017-11-13 12:52:46 +0000154 return false;
155
Hector Dearmanbefe55b2017-11-24 19:02:59 +0000156 const uint8_t* const end = ptr + page_header.size;
157 if (end > end_of_page)
158 return false;
Hector Dearmanf5035e22017-11-13 12:52:46 +0000159
160 while (ptr < end) {
161 EventHeader event_header;
162 if (!ReadAndAdvance(&ptr, end, &event_header))
163 return false;
164 switch (event_header.type_or_length) {
165 case kTypePadding: {
166 // Left over page padding or discarded event.
Hector Dearmanf5035e22017-11-13 12:52:46 +0000167 if (event_header.time_delta == 0) {
168 // TODO(hjd): Look at the next few bytes for read size;
Hector Dearman8d8ccd32017-11-27 16:06:34 +0000169 PERFETTO_CHECK(false); // TODO(hjd): Handle
Hector Dearmanf5035e22017-11-13 12:52:46 +0000170 }
Hector Dearman8d8ccd32017-11-27 16:06:34 +0000171 uint32_t length;
172 if (!ReadAndAdvance<uint32_t>(&ptr, end, &length))
173 return false;
174 ptr += length;
Hector Dearmanf5035e22017-11-13 12:52:46 +0000175 break;
176 }
177 case kTypeTimeExtend: {
178 // Extend the time delta.
Hector Dearmanf5035e22017-11-13 12:52:46 +0000179 uint32_t time_delta_ext;
180 if (!ReadAndAdvance<uint32_t>(&ptr, end, &time_delta_ext))
181 return false;
182 (void)time_delta_ext;
183 // TODO(hjd): Handle.
184 break;
185 }
186 case kTypeTimeStamp: {
187 // Sync time stamp with external clock.
Hector Dearmanf5035e22017-11-13 12:52:46 +0000188 TimeStamp time_stamp;
189 if (!ReadAndAdvance<TimeStamp>(&ptr, end, &time_stamp))
190 return false;
191 // TODO(hjd): Handle.
192 break;
193 }
194 // Data record:
195 default: {
196 PERFETTO_CHECK(event_header.type_or_length <= kTypeDataTypeLengthMax);
197 // type_or_length is <=28 so it represents the length of a data record.
198 if (event_header.type_or_length == 0) {
199 // TODO(hjd): Look at the next few bytes for real size.
200 PERFETTO_CHECK(false);
201 }
202 const uint8_t* next = ptr + 4 * event_header.type_or_length;
203
Hector Dearmanbefe55b2017-11-24 19:02:59 +0000204 uint16_t ftrace_event_id;
205 if (!ReadAndAdvance<uint16_t>(&ptr, end, &ftrace_event_id))
Hector Dearmanf5035e22017-11-13 12:52:46 +0000206 return false;
Hector Dearmanbefe55b2017-11-24 19:02:59 +0000207 if (!filter->IsEventEnabled(ftrace_event_id)) {
208 ptr = next;
209 break;
210 }
Hector Dearmanf5035e22017-11-13 12:52:46 +0000211
212 // Common headers:
213 // TODO(hjd): Read this format dynamically?
214 uint8_t flags;
215 uint8_t preempt_count;
216 uint32_t pid;
217 if (!ReadAndAdvance<uint8_t>(&ptr, end, &flags))
218 return false;
219 if (!ReadAndAdvance<uint8_t>(&ptr, end, &preempt_count))
220 return false;
221 if (!ReadAndAdvance<uint32_t>(&ptr, end, &pid))
222 return false;
223
Hector Dearman8d8ccd32017-11-27 16:06:34 +0000224 // PERFETTO_DLOG("Event type=%d pid=%d", ftrace_event_id, pid);
Hector Dearmanf5035e22017-11-13 12:52:46 +0000225
Primiano Tucci5f48d7b2017-11-27 16:57:13 +0000226 protos::pbzero::FtraceEvent* event = bundle->add_event();
Hector Dearmanf5035e22017-11-13 12:52:46 +0000227 event->set_pid(pid);
228
Hector Dearmanbefe55b2017-11-24 19:02:59 +0000229 // TODO(hjd): Replace this handrolled code with generic parsing code.
Hector Dearman8d8ccd32017-11-27 16:06:34 +0000230 if (ftrace_event_id == print_id) {
Primiano Tucci5f48d7b2017-11-27 16:57:13 +0000231 protos::pbzero::PrintFtraceEvent* print_event = event->set_print();
Hector Dearmanf5035e22017-11-13 12:52:46 +0000232 // Trace Marker Parser
233 uint64_t ip;
234 if (!ReadAndAdvance<uint64_t>(&ptr, end, &ip))
235 return false;
Hector Dearmanbefe55b2017-11-24 19:02:59 +0000236 print_event->set_ip(ip);
Hector Dearman8d8ccd32017-11-27 16:06:34 +0000237
238 // TODO(hjd): Not sure if this is null-terminated.
239 const uint8_t* buf_start = ptr;
240 const uint8_t* buf_end = next - 2;
241 print_event->set_buf(reinterpret_cast<const char*>(buf_start),
242 buf_end - buf_start);
Hector Dearmanbefe55b2017-11-24 19:02:59 +0000243 print_event->Finalize();
Hector Dearmanf5035e22017-11-13 12:52:46 +0000244 }
245
Hector Dearman8d8ccd32017-11-27 16:06:34 +0000246 // TODO(hjd): Replace this handrolled code with generic parsing code.
247 if (ftrace_event_id == sched_switch_id) {
Primiano Tucci5f48d7b2017-11-27 16:57:13 +0000248 protos::pbzero::SchedSwitchFtraceEvent* switch_event =
Hector Dearman8d8ccd32017-11-27 16:06:34 +0000249 event->set_sched_switch();
250
251 char prev_comm[16];
252 uint32_t prev_pid;
253 uint32_t prev_prio;
254 uint64_t prev_state;
255 char next_comm[16];
256 uint32_t next_pid;
257 uint32_t next_prio;
258
259 // TODO(hjd): Avoid this copy.
260 if (!ReadAndAdvance<char[16]>(&ptr, end, &prev_comm))
261 return false;
262 if (!ReadAndAdvance<uint32_t>(&ptr, end, &prev_pid))
263 return false;
264 if (!ReadAndAdvance<uint32_t>(&ptr, end, &prev_prio))
265 return false;
266 if (!ReadAndAdvance<uint64_t>(&ptr, end, &prev_state))
267 return false;
268 if (!ReadAndAdvance<char[16]>(&ptr, end, &next_comm))
269 return false;
270 if (!ReadAndAdvance<uint32_t>(&ptr, end, &next_pid))
271 return false;
272 if (!ReadAndAdvance<uint32_t>(&ptr, end, &next_prio))
273 return false;
274 // TODO(hjd): Not sure if this is null-terminated.
275 prev_comm[15] = '\0';
276 switch_event->set_prev_comm(prev_comm);
277 switch_event->set_prev_pid(prev_pid);
278 switch_event->set_prev_prio(prev_prio);
279 switch_event->set_prev_state(prev_state);
280 // TODO(hjd): Not sure if this is null-terminated.
281 next_comm[15] = '\0';
282 switch_event->set_next_comm(next_comm);
283 switch_event->set_next_pid(next_pid);
284 switch_event->set_next_prio(next_prio);
285 switch_event->Finalize();
286 }
287
Hector Dearmanbefe55b2017-11-24 19:02:59 +0000288 event->Finalize();
289
Hector Dearmanf5035e22017-11-13 12:52:46 +0000290 // Jump to next event.
291 ptr = next;
Hector Dearmanf5035e22017-11-13 12:52:46 +0000292 }
293 }
294 }
295 return true;
296}
297
Hector Dearman3d8970f2017-10-31 09:27:15 +0000298} // namespace perfetto