blob: 8fb12814e451a943c28bd6f0012fb77c32e68de9 [file] [log] [blame]
Eric Secklerab0604c2019-10-25 10:12:07 +01001/*
2 * Copyright (C) 2019 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/proto/system_probes_parser.h"
18
19#include "perfetto/base/logging.h"
20#include "perfetto/ext/traced/sys_stats_counters.h"
21#include "perfetto/protozero/proto_decoder.h"
22#include "src/trace_processor/event_tracker.h"
Isabelle Taylor13a75852019-11-20 10:29:40 +000023#include "src/trace_processor/metadata.h"
Eric Secklerab0604c2019-10-25 10:12:07 +010024#include "src/trace_processor/process_tracker.h"
25#include "src/trace_processor/syscall_tracker.h"
26#include "src/trace_processor/trace_processor_context.h"
27
28#include "protos/perfetto/trace/ps/process_stats.pbzero.h"
29#include "protos/perfetto/trace/ps/process_tree.pbzero.h"
30#include "protos/perfetto/trace/sys_stats/sys_stats.pbzero.h"
31#include "protos/perfetto/trace/system_info.pbzero.h"
32
33namespace perfetto {
34namespace trace_processor {
35
36namespace {
37// kthreadd is the parent process for all kernel threads and always has
38// pid == 2 on Linux and Android.
39const uint32_t kKthreaddPid = 2;
40const char kKthreaddName[] = "kthreadd";
41} // namespace
42
Eric Seckler5fbcf6d2019-10-28 15:09:10 +000043SystemProbesParser::SystemProbesParser(TraceProcessorContext* context)
Eric Secklerab0604c2019-10-25 10:12:07 +010044 : context_(context),
45 utid_name_id_(context->storage->InternString("utid")),
46 num_forks_name_id_(context->storage->InternString("num_forks")),
47 num_irq_total_name_id_(context->storage->InternString("num_irq_total")),
48 num_softirq_total_name_id_(
49 context->storage->InternString("num_softirq_total")),
50 num_irq_name_id_(context->storage->InternString("num_irq")),
51 num_softirq_name_id_(context->storage->InternString("num_softirq")),
52 cpu_times_user_ns_id_(
53 context->storage->InternString("cpu.times.user_ns")),
54 cpu_times_user_nice_ns_id_(
55 context->storage->InternString("cpu.times.user_nice_ns")),
56 cpu_times_system_mode_ns_id_(
57 context->storage->InternString("cpu.times.system_mode_ns")),
58 cpu_times_idle_ns_id_(
59 context->storage->InternString("cpu.times.idle_ns")),
60 cpu_times_io_wait_ns_id_(
61 context->storage->InternString("cpu.times.io_wait_ns")),
62 cpu_times_irq_ns_id_(context->storage->InternString("cpu.times.irq_ns")),
63 cpu_times_softirq_ns_id_(
64 context->storage->InternString("cpu.times.softirq_ns")),
65 oom_score_adj_id_(context->storage->InternString("oom_score_adj")) {
66 for (const auto& name : BuildMeminfoCounterNames()) {
67 meminfo_strs_id_.emplace_back(context->storage->InternString(name));
68 }
69 for (const auto& name : BuildVmstatCounterNames()) {
70 vmstat_strs_id_.emplace_back(context->storage->InternString(name));
71 }
72
73 using ProcessStats = protos::pbzero::ProcessStats;
74 proc_stats_process_names_[ProcessStats::Process::kVmSizeKbFieldNumber] =
75 context->storage->InternString("mem.virt");
76 proc_stats_process_names_[ProcessStats::Process::kVmRssKbFieldNumber] =
77 context->storage->InternString("mem.rss");
78 proc_stats_process_names_[ProcessStats::Process::kRssAnonKbFieldNumber] =
79 context->storage->InternString("mem.rss.anon");
80 proc_stats_process_names_[ProcessStats::Process::kRssFileKbFieldNumber] =
81 context->storage->InternString("mem.rss.file");
82 proc_stats_process_names_[ProcessStats::Process::kRssShmemKbFieldNumber] =
83 context->storage->InternString("mem.rss.shmem");
84 proc_stats_process_names_[ProcessStats::Process::kVmSwapKbFieldNumber] =
85 context->storage->InternString("mem.swap");
86 proc_stats_process_names_[ProcessStats::Process::kVmLockedKbFieldNumber] =
87 context->storage->InternString("mem.locked");
88 proc_stats_process_names_[ProcessStats::Process::kVmHwmKbFieldNumber] =
89 context->storage->InternString("mem.rss.watermark");
90 proc_stats_process_names_[ProcessStats::Process::kOomScoreAdjFieldNumber] =
91 oom_score_adj_id_;
92}
93
Eric Seckler5fbcf6d2019-10-28 15:09:10 +000094void SystemProbesParser::ParseSysStats(int64_t ts, ConstBytes blob) {
Eric Secklerab0604c2019-10-25 10:12:07 +010095 protos::pbzero::SysStats::Decoder sys_stats(blob.data, blob.size);
96
97 for (auto it = sys_stats.meminfo(); it; ++it) {
98 protos::pbzero::SysStats::MeminfoValue::Decoder mi(*it);
99 auto key = static_cast<size_t>(mi.key());
100 if (PERFETTO_UNLIKELY(key >= meminfo_strs_id_.size())) {
101 PERFETTO_ELOG("MemInfo key %zu is not recognized.", key);
102 context_->storage->IncrementStats(stats::meminfo_unknown_keys);
103 continue;
104 }
105 // /proc/meminfo counters are in kB, convert to bytes
Lalit Maganti809b2f92019-11-07 13:27:26 +0000106 TrackId track = context_->track_tracker->InternGlobalCounterTrack(
107 meminfo_strs_id_[key]);
108 context_->event_tracker->PushCounter(ts, mi.value() * 1024L, track);
Eric Secklerab0604c2019-10-25 10:12:07 +0100109 }
110
111 for (auto it = sys_stats.vmstat(); it; ++it) {
112 protos::pbzero::SysStats::VmstatValue::Decoder vm(*it);
113 auto key = static_cast<size_t>(vm.key());
114 if (PERFETTO_UNLIKELY(key >= vmstat_strs_id_.size())) {
115 PERFETTO_ELOG("VmStat key %zu is not recognized.", key);
116 context_->storage->IncrementStats(stats::vmstat_unknown_keys);
117 continue;
118 }
Lalit Maganti809b2f92019-11-07 13:27:26 +0000119 TrackId track =
120 context_->track_tracker->InternGlobalCounterTrack(vmstat_strs_id_[key]);
121 context_->event_tracker->PushCounter(ts, vm.value(), track);
Eric Secklerab0604c2019-10-25 10:12:07 +0100122 }
123
124 for (auto it = sys_stats.cpu_stat(); it; ++it) {
125 protos::pbzero::SysStats::CpuTimes::Decoder ct(*it);
126 if (PERFETTO_UNLIKELY(!ct.has_cpu_id())) {
127 PERFETTO_ELOG("CPU field not found in CpuTimes");
128 context_->storage->IncrementStats(stats::invalid_cpu_times);
129 continue;
130 }
Lalit Maganti809b2f92019-11-07 13:27:26 +0000131
132 TrackId track = context_->track_tracker->InternCpuCounterTrack(
133 cpu_times_user_ns_id_, ct.cpu_id());
134 context_->event_tracker->PushCounter(ts, ct.user_ns(), track);
135
136 track = context_->track_tracker->InternCpuCounterTrack(
137 cpu_times_user_nice_ns_id_, ct.cpu_id());
138 context_->event_tracker->PushCounter(ts, ct.user_ice_ns(), track);
139
140 track = context_->track_tracker->InternCpuCounterTrack(
141 cpu_times_system_mode_ns_id_, ct.cpu_id());
142 context_->event_tracker->PushCounter(ts, ct.system_mode_ns(), track);
143
144 track = context_->track_tracker->InternCpuCounterTrack(
145 cpu_times_idle_ns_id_, ct.cpu_id());
146 context_->event_tracker->PushCounter(ts, ct.idle_ns(), track);
147
148 track = context_->track_tracker->InternCpuCounterTrack(
149 cpu_times_io_wait_ns_id_, ct.cpu_id());
150 context_->event_tracker->PushCounter(ts, ct.io_wait_ns(), track);
151
152 track = context_->track_tracker->InternCpuCounterTrack(cpu_times_irq_ns_id_,
153 ct.cpu_id());
154 context_->event_tracker->PushCounter(ts, ct.irq_ns(), track);
155
156 track = context_->track_tracker->InternCpuCounterTrack(
157 cpu_times_softirq_ns_id_, ct.cpu_id());
158 context_->event_tracker->PushCounter(ts, ct.softirq_ns(), track);
Eric Secklerab0604c2019-10-25 10:12:07 +0100159 }
160
161 for (auto it = sys_stats.num_irq(); it; ++it) {
162 protos::pbzero::SysStats::InterruptCount::Decoder ic(*it);
Lalit Maganti809b2f92019-11-07 13:27:26 +0000163
164 TrackId track = context_->track_tracker->InternIrqCounterTrack(
165 num_irq_name_id_, ic.irq());
166 context_->event_tracker->PushCounter(ts, ic.count(), track);
Eric Secklerab0604c2019-10-25 10:12:07 +0100167 }
168
169 for (auto it = sys_stats.num_softirq(); it; ++it) {
170 protos::pbzero::SysStats::InterruptCount::Decoder ic(*it);
Lalit Maganti809b2f92019-11-07 13:27:26 +0000171
172 TrackId track = context_->track_tracker->InternSoftirqCounterTrack(
173 num_softirq_name_id_, ic.irq());
174 context_->event_tracker->PushCounter(ts, ic.count(), track);
Eric Secklerab0604c2019-10-25 10:12:07 +0100175 }
176
177 if (sys_stats.has_num_forks()) {
Lalit Maganti809b2f92019-11-07 13:27:26 +0000178 TrackId track =
179 context_->track_tracker->InternGlobalCounterTrack(num_forks_name_id_);
180 context_->event_tracker->PushCounter(ts, sys_stats.num_forks(), track);
Eric Secklerab0604c2019-10-25 10:12:07 +0100181 }
182
183 if (sys_stats.has_num_irq_total()) {
Lalit Maganti809b2f92019-11-07 13:27:26 +0000184 TrackId track = context_->track_tracker->InternGlobalCounterTrack(
185 num_irq_total_name_id_);
186 context_->event_tracker->PushCounter(ts, sys_stats.num_irq_total(), track);
Eric Secklerab0604c2019-10-25 10:12:07 +0100187 }
188
189 if (sys_stats.has_num_softirq_total()) {
Lalit Maganti809b2f92019-11-07 13:27:26 +0000190 TrackId track = context_->track_tracker->InternGlobalCounterTrack(
191 num_softirq_total_name_id_);
Eric Secklerab0604c2019-10-25 10:12:07 +0100192 context_->event_tracker->PushCounter(ts, sys_stats.num_softirq_total(),
Lalit Maganti809b2f92019-11-07 13:27:26 +0000193 track);
Eric Secklerab0604c2019-10-25 10:12:07 +0100194 }
195}
196
Eric Seckler5fbcf6d2019-10-28 15:09:10 +0000197void SystemProbesParser::ParseProcessTree(ConstBytes blob) {
Eric Secklerab0604c2019-10-25 10:12:07 +0100198 protos::pbzero::ProcessTree::Decoder ps(blob.data, blob.size);
199
200 for (auto it = ps.processes(); it; ++it) {
201 protos::pbzero::ProcessTree::Process::Decoder proc(*it);
202 if (!proc.has_cmdline())
203 continue;
204 auto pid = static_cast<uint32_t>(proc.pid());
205 auto ppid = static_cast<uint32_t>(proc.ppid());
206
207 // If the parent pid is kthreadd's pid, even though this pid is of a
208 // "process", we want to treat it as being a child thread of kthreadd.
209 if (ppid == kKthreaddPid) {
210 context_->process_tracker->SetProcessMetadata(kKthreaddPid, base::nullopt,
211 kKthreaddName);
212 context_->process_tracker->UpdateThread(pid, kKthreaddPid);
213 } else {
214 auto args = proc.cmdline();
215 base::StringView argv0 = args ? *args : base::StringView();
Ioannis Ilkosfd554bc2019-11-16 01:14:57 +0000216 UniquePid upid =
217 context_->process_tracker->SetProcessMetadata(pid, ppid, argv0);
218 if (proc.has_uid()) {
219 context_->process_tracker->SetProcessUid(
220 upid, static_cast<uint32_t>(proc.uid()));
221 }
Eric Secklerab0604c2019-10-25 10:12:07 +0100222 }
223 }
224
225 for (auto it = ps.threads(); it; ++it) {
226 protos::pbzero::ProcessTree::Thread::Decoder thd(*it);
227 auto tid = static_cast<uint32_t>(thd.tid());
228 auto tgid = static_cast<uint32_t>(thd.tgid());
229 context_->process_tracker->UpdateThread(tid, tgid);
230
231 if (thd.has_name()) {
232 StringId threadNameId = context_->storage->InternString(thd.name());
233 context_->process_tracker->UpdateThreadName(tid, threadNameId);
234 }
235 }
236}
237
Eric Seckler5fbcf6d2019-10-28 15:09:10 +0000238void SystemProbesParser::ParseProcessStats(int64_t ts, ConstBytes blob) {
Eric Secklerab0604c2019-10-25 10:12:07 +0100239 protos::pbzero::ProcessStats::Decoder stats(blob.data, blob.size);
240 const auto kOomScoreAdjFieldNumber =
241 protos::pbzero::ProcessStats::Process::kOomScoreAdjFieldNumber;
242 for (auto it = stats.processes(); it; ++it) {
243 // Maps a process counter field it to its value.
244 // E.g., 4 := 1024 -> "mem.rss.anon" := 1024.
245 std::array<int64_t, kProcStatsProcessSize> counter_values{};
246 std::array<bool, kProcStatsProcessSize> has_counter{};
247
248 protozero::ProtoDecoder proc(*it);
249 uint32_t pid = 0;
250 for (auto fld = proc.ReadField(); fld.valid(); fld = proc.ReadField()) {
251 if (fld.id() == protos::pbzero::ProcessStats::Process::kPidFieldNumber) {
252 pid = fld.as_uint32();
253 continue;
254 }
255 bool is_counter_field = fld.id() < proc_stats_process_names_.size() &&
256 proc_stats_process_names_[fld.id()] != 0;
257 if (is_counter_field) {
258 // Memory counters are in KB, keep values in bytes in the trace
259 // processor.
260 counter_values[fld.id()] = fld.id() == kOomScoreAdjFieldNumber
261 ? fld.as_int64()
262 : fld.as_int64() * 1024;
263 has_counter[fld.id()] = true;
264 } else {
265 context_->storage->IncrementStats(stats::proc_stat_unknown_counters);
266 }
267 }
268
269 // Skip field_id 0 (invalid) and 1 (pid).
270 for (size_t field_id = 2; field_id < counter_values.size(); field_id++) {
271 if (!has_counter[field_id])
272 continue;
273
274 // Lookup the interned string id from the field name using the
275 // pre-cached |proc_stats_process_names_| map.
276 StringId name = proc_stats_process_names_[field_id];
277 int64_t value = counter_values[field_id];
278 UniquePid upid = context_->process_tracker->GetOrCreateProcess(pid);
Lalit Maganti809b2f92019-11-07 13:27:26 +0000279 TrackId track =
280 context_->track_tracker->InternProcessCounterTrack(name, upid);
281 context_->event_tracker->PushCounter(ts, value, track);
Eric Secklerab0604c2019-10-25 10:12:07 +0100282 }
283 }
284}
285
Eric Seckler5fbcf6d2019-10-28 15:09:10 +0000286void SystemProbesParser::ParseSystemInfo(ConstBytes blob) {
Eric Secklerab0604c2019-10-25 10:12:07 +0100287 protos::pbzero::SystemInfo::Decoder packet(blob.data, blob.size);
288 if (packet.has_utsname()) {
289 ConstBytes utsname_blob = packet.utsname();
290 protos::pbzero::Utsname::Decoder utsname(utsname_blob.data,
291 utsname_blob.size);
292 base::StringView machine = utsname.machine();
293 if (machine == "aarch64" || machine == "armv8l") {
294 context_->syscall_tracker->SetArchitecture(kAarch64);
295 } else if (machine == "x86_64") {
296 context_->syscall_tracker->SetArchitecture(kX86_64);
297 } else {
298 PERFETTO_ELOG("Unknown architecture %s", machine.ToStdString().c_str());
299 }
Isabelle Taylor13a75852019-11-20 10:29:40 +0000300
301 StringPool::Id sysname_id =
302 context_->storage->InternString(utsname.sysname());
303 StringPool::Id version_id =
304 context_->storage->InternString(utsname.version());
305 StringPool::Id release_id =
306 context_->storage->InternString(utsname.release());
307 StringPool::Id machine_id =
308 context_->storage->InternString(utsname.machine());
309
310 context_->storage->SetMetadata(metadata::system_name,
311 Variadic::String(sysname_id));
312 context_->storage->SetMetadata(metadata::system_version,
313 Variadic::String(version_id));
314 context_->storage->SetMetadata(metadata::system_release,
315 Variadic::String(release_id));
316 context_->storage->SetMetadata(metadata::system_machine,
317 Variadic::String(machine_id));
Eric Secklerab0604c2019-10-25 10:12:07 +0100318 }
Ioannis Ilkos2f875b22019-11-27 19:26:02 +0000319
320 if (packet.has_android_build_fingerprint()) {
321 context_->storage->SetMetadata(
322 metadata::android_build_fingerprint,
323 Variadic::String(context_->storage->InternString(
324 packet.android_build_fingerprint())));
325 }
Eric Secklerab0604c2019-10-25 10:12:07 +0100326}
327
328} // namespace trace_processor
329} // namespace perfetto