1 /*
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 <set>
20
21 #include "perfetto/base/logging.h"
22 #include "perfetto/ext/base/string_utils.h"
23 #include "perfetto/ext/traced/sys_stats_counters.h"
24 #include "perfetto/protozero/proto_decoder.h"
25 #include "src/trace_processor/importers/common/event_tracker.h"
26 #include "src/trace_processor/importers/common/process_tracker.h"
27 #include "src/trace_processor/importers/common/system_info_tracker.h"
28 #include "src/trace_processor/importers/proto/metadata_tracker.h"
29 #include "src/trace_processor/importers/syscalls/syscall_tracker.h"
30 #include "src/trace_processor/storage/metadata.h"
31 #include "src/trace_processor/types/trace_processor_context.h"
32
33 #include "protos/perfetto/trace/ps/process_stats.pbzero.h"
34 #include "protos/perfetto/trace/ps/process_tree.pbzero.h"
35 #include "protos/perfetto/trace/sys_stats/sys_stats.pbzero.h"
36 #include "protos/perfetto/trace/system_info.pbzero.h"
37 #include "protos/perfetto/trace/system_info/cpu_info.pbzero.h"
38
39 namespace perfetto {
40 namespace trace_processor {
41
42 namespace {
43 // kthreadd is the parent process for all kernel threads and always has
44 // pid == 2 on Linux and Android.
45 const uint32_t kKthreaddPid = 2;
46 const char kKthreaddName[] = "kthreadd";
47
VersionStringToSdkVersion(const std::string & version)48 base::Optional<int> VersionStringToSdkVersion(const std::string& version) {
49 // TODO(lalitm): remove this when the SDK version polling saturates
50 // S/T traces in practice.
51 if (base::StartsWith(version, "T") || base::StartsWith(version, "S")) {
52 return 31;
53 }
54
55 // Documentation for this mapping can be found at
56 // https://source.android.com/compatibility/cdd.
57 if (version == "12") {
58 return 31;
59 } else if (version == "11") {
60 return 30;
61 } else if (version == "10") {
62 return 29;
63 } else if (version == "9") {
64 return 28;
65 } else if (version == "8.1") {
66 return 27;
67 } else if (version == "8.0") {
68 return 26;
69 } else if (version == "7.1") {
70 return 25;
71 } else if (version == "7.0") {
72 return 24;
73 } else if (version == "6.0") {
74 return 23;
75 } else if (version == "5.1" || version == "5.1.1") {
76 return 22;
77 } else if (version == "5.0" || version == "5.0.1" || version == "5.0.2") {
78 return 21;
79 }
80 // If we reached this point, we don't know how to parse this version
81 // so just return null.
82 return base::nullopt;
83 }
84
FingerprintToSdkVersion(const std::string & fingerprint)85 base::Optional<int> FingerprintToSdkVersion(const std::string& fingerprint) {
86 // Try to parse the SDK version from the fingerprint.
87 // Examples of fingerprints:
88 // google/shamu/shamu:7.0/NBD92F/3753956:userdebug/dev-keys
89 // google/coral/coral:12/SP1A.210812.015/7679548:userdebug/dev-keys
90 size_t colon = fingerprint.find(':');
91 if (colon == std::string::npos)
92 return base::nullopt;
93
94 size_t slash = fingerprint.find('/', colon);
95 if (slash == std::string::npos)
96 return base::nullopt;
97
98 std::string version = fingerprint.substr(colon + 1, slash - (colon + 1));
99 return VersionStringToSdkVersion(version);
100 }
101 } // namespace
102
SystemProbesParser(TraceProcessorContext * context)103 SystemProbesParser::SystemProbesParser(TraceProcessorContext* context)
104 : context_(context),
105 utid_name_id_(context->storage->InternString("utid")),
106 num_forks_name_id_(context->storage->InternString("num_forks")),
107 num_irq_total_name_id_(context->storage->InternString("num_irq_total")),
108 num_softirq_total_name_id_(
109 context->storage->InternString("num_softirq_total")),
110 num_irq_name_id_(context->storage->InternString("num_irq")),
111 num_softirq_name_id_(context->storage->InternString("num_softirq")),
112 cpu_times_user_ns_id_(
113 context->storage->InternString("cpu.times.user_ns")),
114 cpu_times_user_nice_ns_id_(
115 context->storage->InternString("cpu.times.user_nice_ns")),
116 cpu_times_system_mode_ns_id_(
117 context->storage->InternString("cpu.times.system_mode_ns")),
118 cpu_times_idle_ns_id_(
119 context->storage->InternString("cpu.times.idle_ns")),
120 cpu_times_io_wait_ns_id_(
121 context->storage->InternString("cpu.times.io_wait_ns")),
122 cpu_times_irq_ns_id_(context->storage->InternString("cpu.times.irq_ns")),
123 cpu_times_softirq_ns_id_(
124 context->storage->InternString("cpu.times.softirq_ns")),
125 oom_score_adj_id_(context->storage->InternString("oom_score_adj")),
126 thread_time_in_state_id_(context->storage->InternString("time_in_state")),
127 thread_time_in_state_cpu_id_(
128 context_->storage->InternString("time_in_state_cpu_id")),
129 cpu_freq_id_(context_->storage->InternString("freq")) {
130 for (const auto& name : BuildMeminfoCounterNames()) {
131 meminfo_strs_id_.emplace_back(context->storage->InternString(name));
132 }
133 for (const auto& name : BuildVmstatCounterNames()) {
134 vmstat_strs_id_.emplace_back(context->storage->InternString(name));
135 }
136
137 using ProcessStats = protos::pbzero::ProcessStats;
138 proc_stats_process_names_[ProcessStats::Process::kVmSizeKbFieldNumber] =
139 context->storage->InternString("mem.virt");
140 proc_stats_process_names_[ProcessStats::Process::kVmRssKbFieldNumber] =
141 context->storage->InternString("mem.rss");
142 proc_stats_process_names_[ProcessStats::Process::kRssAnonKbFieldNumber] =
143 context->storage->InternString("mem.rss.anon");
144 proc_stats_process_names_[ProcessStats::Process::kRssFileKbFieldNumber] =
145 context->storage->InternString("mem.rss.file");
146 proc_stats_process_names_[ProcessStats::Process::kRssShmemKbFieldNumber] =
147 context->storage->InternString("mem.rss.shmem");
148 proc_stats_process_names_[ProcessStats::Process::kVmSwapKbFieldNumber] =
149 context->storage->InternString("mem.swap");
150 proc_stats_process_names_[ProcessStats::Process::kVmLockedKbFieldNumber] =
151 context->storage->InternString("mem.locked");
152 proc_stats_process_names_[ProcessStats::Process::kVmHwmKbFieldNumber] =
153 context->storage->InternString("mem.rss.watermark");
154 proc_stats_process_names_[ProcessStats::Process::kOomScoreAdjFieldNumber] =
155 oom_score_adj_id_;
156 }
157
ParseSysStats(int64_t ts,ConstBytes blob)158 void SystemProbesParser::ParseSysStats(int64_t ts, ConstBytes blob) {
159 protos::pbzero::SysStats::Decoder sys_stats(blob.data, blob.size);
160
161 for (auto it = sys_stats.meminfo(); it; ++it) {
162 protos::pbzero::SysStats::MeminfoValue::Decoder mi(*it);
163 auto key = static_cast<size_t>(mi.key());
164 if (PERFETTO_UNLIKELY(key >= meminfo_strs_id_.size())) {
165 PERFETTO_ELOG("MemInfo key %zu is not recognized.", key);
166 context_->storage->IncrementStats(stats::meminfo_unknown_keys);
167 continue;
168 }
169 // /proc/meminfo counters are in kB, convert to bytes
170 TrackId track = context_->track_tracker->InternGlobalCounterTrack(
171 meminfo_strs_id_[key]);
172 context_->event_tracker->PushCounter(
173 ts, static_cast<double>(mi.value()) * 1024., track);
174 }
175
176 for (auto it = sys_stats.devfreq(); it; ++it) {
177 protos::pbzero::SysStats::DevfreqValue::Decoder vm(*it);
178 auto key = static_cast<base::StringView>(vm.key());
179 // Append " Frequency" to align names with
180 // FtraceParser::ParseClockSetRate
181 base::StringView devfreq_subtitle("Frequency");
182 base::StackString<255> counter_name(
183 "%.*s %.*s", int(key.size()), key.data(), int(devfreq_subtitle.size()),
184 devfreq_subtitle.data());
185 StringId name = context_->storage->InternString(counter_name.string_view());
186 TrackId track = context_->track_tracker->InternGlobalCounterTrack(name);
187 context_->event_tracker->PushCounter(ts, static_cast<double>(vm.value()),
188 track);
189 }
190
191 int c = 0;
192 for (auto it = sys_stats.cpufreq_khz(); it; ++it, ++c) {
193 base::StackString<255> counter_name("CPU %d Freq in kHz", c);
194 StringId name = context_->storage->InternString(counter_name.string_view());
195 TrackId track = context_->track_tracker->InternGlobalCounterTrack(name);
196 context_->event_tracker->PushCounter(ts, static_cast<double>(*it), track);
197 }
198
199 for (auto it = sys_stats.vmstat(); it; ++it) {
200 protos::pbzero::SysStats::VmstatValue::Decoder vm(*it);
201 auto key = static_cast<size_t>(vm.key());
202 if (PERFETTO_UNLIKELY(key >= vmstat_strs_id_.size())) {
203 PERFETTO_ELOG("VmStat key %zu is not recognized.", key);
204 context_->storage->IncrementStats(stats::vmstat_unknown_keys);
205 continue;
206 }
207 TrackId track =
208 context_->track_tracker->InternGlobalCounterTrack(vmstat_strs_id_[key]);
209 context_->event_tracker->PushCounter(ts, static_cast<double>(vm.value()),
210 track);
211 }
212
213 for (auto it = sys_stats.cpu_stat(); it; ++it) {
214 protos::pbzero::SysStats::CpuTimes::Decoder ct(*it);
215 if (PERFETTO_UNLIKELY(!ct.has_cpu_id())) {
216 PERFETTO_ELOG("CPU field not found in CpuTimes");
217 context_->storage->IncrementStats(stats::invalid_cpu_times);
218 continue;
219 }
220
221 TrackId track = context_->track_tracker->InternCpuCounterTrack(
222 cpu_times_user_ns_id_, ct.cpu_id());
223 context_->event_tracker->PushCounter(ts, static_cast<double>(ct.user_ns()),
224 track);
225
226 track = context_->track_tracker->InternCpuCounterTrack(
227 cpu_times_user_nice_ns_id_, ct.cpu_id());
228 context_->event_tracker->PushCounter(
229 ts, static_cast<double>(ct.user_ice_ns()), track);
230
231 track = context_->track_tracker->InternCpuCounterTrack(
232 cpu_times_system_mode_ns_id_, ct.cpu_id());
233 context_->event_tracker->PushCounter(
234 ts, static_cast<double>(ct.system_mode_ns()), track);
235
236 track = context_->track_tracker->InternCpuCounterTrack(
237 cpu_times_idle_ns_id_, ct.cpu_id());
238 context_->event_tracker->PushCounter(ts, static_cast<double>(ct.idle_ns()),
239 track);
240
241 track = context_->track_tracker->InternCpuCounterTrack(
242 cpu_times_io_wait_ns_id_, ct.cpu_id());
243 context_->event_tracker->PushCounter(
244 ts, static_cast<double>(ct.io_wait_ns()), track);
245
246 track = context_->track_tracker->InternCpuCounterTrack(cpu_times_irq_ns_id_,
247 ct.cpu_id());
248 context_->event_tracker->PushCounter(ts, static_cast<double>(ct.irq_ns()),
249 track);
250
251 track = context_->track_tracker->InternCpuCounterTrack(
252 cpu_times_softirq_ns_id_, ct.cpu_id());
253 context_->event_tracker->PushCounter(
254 ts, static_cast<double>(ct.softirq_ns()), track);
255 }
256
257 for (auto it = sys_stats.num_irq(); it; ++it) {
258 protos::pbzero::SysStats::InterruptCount::Decoder ic(*it);
259
260 TrackId track = context_->track_tracker->InternIrqCounterTrack(
261 num_irq_name_id_, ic.irq());
262 context_->event_tracker->PushCounter(ts, static_cast<double>(ic.count()),
263 track);
264 }
265
266 for (auto it = sys_stats.num_softirq(); it; ++it) {
267 protos::pbzero::SysStats::InterruptCount::Decoder ic(*it);
268
269 TrackId track = context_->track_tracker->InternSoftirqCounterTrack(
270 num_softirq_name_id_, ic.irq());
271 context_->event_tracker->PushCounter(ts, static_cast<double>(ic.count()),
272 track);
273 }
274
275 if (sys_stats.has_num_forks()) {
276 TrackId track =
277 context_->track_tracker->InternGlobalCounterTrack(num_forks_name_id_);
278 context_->event_tracker->PushCounter(
279 ts, static_cast<double>(sys_stats.num_forks()), track);
280 }
281
282 if (sys_stats.has_num_irq_total()) {
283 TrackId track = context_->track_tracker->InternGlobalCounterTrack(
284 num_irq_total_name_id_);
285 context_->event_tracker->PushCounter(
286 ts, static_cast<double>(sys_stats.num_irq_total()), track);
287 }
288
289 if (sys_stats.has_num_softirq_total()) {
290 TrackId track = context_->track_tracker->InternGlobalCounterTrack(
291 num_softirq_total_name_id_);
292 context_->event_tracker->PushCounter(
293 ts, static_cast<double>(sys_stats.num_softirq_total()), track);
294 }
295 }
296
ParseProcessTree(ConstBytes blob)297 void SystemProbesParser::ParseProcessTree(ConstBytes blob) {
298 protos::pbzero::ProcessTree::Decoder ps(blob.data, blob.size);
299
300 for (auto it = ps.processes(); it; ++it) {
301 protos::pbzero::ProcessTree::Process::Decoder proc(*it);
302 if (!proc.has_cmdline())
303 continue;
304 auto pid = static_cast<uint32_t>(proc.pid());
305 auto ppid = static_cast<uint32_t>(proc.ppid());
306
307 if (proc.has_nspid()) {
308 std::vector<uint32_t> nspid;
309 for (auto nspid_it = proc.nspid(); nspid_it; nspid_it++) {
310 nspid.emplace_back(static_cast<uint32_t>(*nspid_it));
311 }
312 context_->process_tracker->UpdateNamespacedProcess(pid, std::move(nspid));
313 }
314
315 // If the parent pid is kthreadd's pid, even though this pid is of a
316 // "process", we want to treat it as being a child thread of
317 // kthreadd.
318 if (ppid == kKthreaddPid) {
319 context_->process_tracker->SetProcessMetadata(
320 kKthreaddPid, base::nullopt, kKthreaddName, base::StringView());
321 context_->process_tracker->UpdateThread(pid, kKthreaddPid);
322 } else {
323 auto raw_cmdline = proc.cmdline();
324 base::StringView argv0 = raw_cmdline ? *raw_cmdline : base::StringView();
325 // Chrome child process overwrites /proc/self/cmdline and replaces all
326 // '\0' with ' '. This makes argv0 contain the full command line. Extract
327 // the actual argv0 if it's Chrome.
328 static const char kChromeBinary[] = "/chrome ";
329 auto pos = argv0.find(kChromeBinary);
330 if (pos != base::StringView::npos) {
331 argv0 = argv0.substr(0, pos + strlen(kChromeBinary) - 1);
332 }
333
334 std::string cmdline_str;
335 for (auto cmdline_it = raw_cmdline; cmdline_it;) {
336 auto cmdline_part = *cmdline_it;
337 cmdline_str.append(cmdline_part.data, cmdline_part.size);
338
339 if (++cmdline_it)
340 cmdline_str.append(" ");
341 }
342 base::StringView cmdline = base::StringView(cmdline_str);
343 UniquePid upid = context_->process_tracker->SetProcessMetadata(
344 pid, ppid, argv0, cmdline);
345 if (proc.has_uid()) {
346 context_->process_tracker->SetProcessUid(
347 upid, static_cast<uint32_t>(proc.uid()));
348 }
349 }
350 }
351
352 for (auto it = ps.threads(); it; ++it) {
353 protos::pbzero::ProcessTree::Thread::Decoder thd(*it);
354 auto tid = static_cast<uint32_t>(thd.tid());
355 auto tgid = static_cast<uint32_t>(thd.tgid());
356 context_->process_tracker->UpdateThread(tid, tgid);
357
358 if (thd.has_name()) {
359 StringId thread_name_id = context_->storage->InternString(thd.name());
360 context_->process_tracker->UpdateThreadName(
361 tid, thread_name_id, ThreadNamePriority::kProcessTree);
362 }
363
364 if (thd.has_nstid()) {
365 std::vector<uint32_t> nstid;
366 for (auto nstid_it = thd.nstid(); nstid_it; nstid_it++) {
367 nstid.emplace_back(static_cast<uint32_t>(*nstid_it));
368 }
369 context_->process_tracker->UpdateNamespacedThread(tgid, tid,
370 std::move(nstid));
371 }
372 }
373 }
374
ParseProcessStats(int64_t ts,ConstBytes blob)375 void SystemProbesParser::ParseProcessStats(int64_t ts, ConstBytes blob) {
376 using Process = protos::pbzero::ProcessStats::Process;
377 protos::pbzero::ProcessStats::Decoder stats(blob.data, blob.size);
378 const auto kOomScoreAdjFieldNumber =
379 protos::pbzero::ProcessStats::Process::kOomScoreAdjFieldNumber;
380 for (auto it = stats.processes(); it; ++it) {
381 // Maps a process counter field it to its value.
382 // E.g., 4 := 1024 -> "mem.rss.anon" := 1024.
383 std::array<int64_t, kProcStatsProcessSize> counter_values{};
384 std::array<bool, kProcStatsProcessSize> has_counter{};
385
386 protozero::ProtoDecoder proc(*it);
387 uint32_t pid = 0;
388 for (auto fld = proc.ReadField(); fld.valid(); fld = proc.ReadField()) {
389 if (fld.id() == protos::pbzero::ProcessStats::Process::kPidFieldNumber) {
390 pid = fld.as_uint32();
391 continue;
392 }
393 if (fld.id() ==
394 protos::pbzero::ProcessStats::Process::kThreadsFieldNumber) {
395 if (PERFETTO_UNLIKELY(ms_per_tick_ == 0 ||
396 thread_time_in_state_cpus_.empty())) {
397 context_->storage->IncrementStats(
398 stats::thread_time_in_state_out_of_order);
399 continue;
400 }
401 ParseThreadStats(ts, pid, fld.as_bytes());
402 continue;
403 }
404 bool is_counter_field = fld.id() < proc_stats_process_names_.size() &&
405 !proc_stats_process_names_[fld.id()].is_null();
406 if (is_counter_field) {
407 // Memory counters are in KB, keep values in bytes in the trace
408 // processor.
409 counter_values[fld.id()] = fld.id() == kOomScoreAdjFieldNumber
410 ? fld.as_int64()
411 : fld.as_int64() * 1024;
412 has_counter[fld.id()] = true;
413 } else {
414 // Chrome fields are processed by ChromeSystemProbesParser.
415 if (fld.id() == Process::kIsPeakRssResettableFieldNumber ||
416 fld.id() == Process::kChromePrivateFootprintKbFieldNumber ||
417 fld.id() == Process::kChromePrivateFootprintKbFieldNumber) {
418 continue;
419 }
420 context_->storage->IncrementStats(stats::proc_stat_unknown_counters);
421 }
422 }
423
424 // Skip field_id 0 (invalid) and 1 (pid).
425 for (size_t field_id = 2; field_id < counter_values.size(); field_id++) {
426 if (!has_counter[field_id] || field_id ==
427 protos::pbzero::ProcessStats::Process::
428 kIsPeakRssResettableFieldNumber) {
429 continue;
430 }
431
432 // Lookup the interned string id from the field name using the
433 // pre-cached |proc_stats_process_names_| map.
434 const StringId& name = proc_stats_process_names_[field_id];
435 UniquePid upid = context_->process_tracker->GetOrCreateProcess(pid);
436 TrackId track =
437 context_->track_tracker->InternProcessCounterTrack(name, upid);
438 int64_t value = counter_values[field_id];
439 context_->event_tracker->PushCounter(ts, static_cast<double>(value),
440 track);
441 }
442 }
443 }
444
ParseThreadStats(int64_t ts,uint32_t pid,ConstBytes blob)445 void SystemProbesParser::ParseThreadStats(int64_t ts,
446 uint32_t pid,
447 ConstBytes blob) {
448 protos::pbzero::ProcessStats::Thread::Decoder stats(blob.data, blob.size);
449 UniqueTid utid = context_->process_tracker->UpdateThread(
450 static_cast<uint32_t>(stats.tid()), pid);
451 TrackId track_id = context_->track_tracker->InternThreadCounterTrack(
452 thread_time_in_state_id_, utid);
453
454 std::vector<uint64_t> ticks(thread_time_in_state_cpu_freqs_.size());
455 auto index_it = stats.cpu_freq_indices();
456 auto tick_it = stats.cpu_freq_ticks();
457 for (; index_it && tick_it; index_it++, tick_it++) {
458 auto freq_index = *index_it;
459 if (PERFETTO_UNLIKELY(!IsValidCpuFreqIndex(freq_index))) {
460 context_->storage->IncrementStats(
461 stats::thread_time_in_state_unknown_cpu_freq);
462 continue;
463 }
464 ticks[freq_index] = *tick_it;
465 }
466
467 for (uint32_t cpu : thread_time_in_state_cpus_) {
468 size_t start = thread_time_in_state_freq_index_[cpu];
469 size_t end = thread_time_in_state_freq_index_[cpu + 1];
470 for (size_t freq_index = start; freq_index < end; freq_index++) {
471 if (stats.cpu_freq_full() || ticks[freq_index] > 0) {
472 context_->event_tracker->PushCounter(
473 ts, static_cast<double>(ticks[freq_index] * ms_per_tick_), track_id,
474 [cpu, freq_index, this](ArgsTracker::BoundInserter* args_table) {
475 args_table->AddArg(thread_time_in_state_cpu_id_,
476 Variadic::UnsignedInteger(cpu));
477 args_table->AddArg(
478 cpu_freq_id_,
479 Variadic::UnsignedInteger(
480 thread_time_in_state_cpu_freqs_[freq_index]));
481 });
482 }
483 }
484 }
485 }
486
ParseSystemInfo(ConstBytes blob)487 void SystemProbesParser::ParseSystemInfo(ConstBytes blob) {
488 protos::pbzero::SystemInfo::Decoder packet(blob.data, blob.size);
489 if (packet.has_utsname()) {
490 ConstBytes utsname_blob = packet.utsname();
491 protos::pbzero::Utsname::Decoder utsname(utsname_blob.data,
492 utsname_blob.size);
493 base::StringView machine = utsname.machine();
494 SyscallTracker* syscall_tracker = SyscallTracker::GetOrCreate(context_);
495 if (machine == "aarch64") {
496 syscall_tracker->SetArchitecture(kAarch64);
497 } else if (machine == "armv8l") {
498 syscall_tracker->SetArchitecture(kArmEabi);
499 } else if (machine == "armv7l") {
500 syscall_tracker->SetArchitecture(kAarch32);
501 } else if (machine == "x86_64") {
502 syscall_tracker->SetArchitecture(kX86_64);
503 } else if (machine == "i686") {
504 syscall_tracker->SetArchitecture(kX86);
505 } else {
506 PERFETTO_ELOG("Unknown architecture %s. Syscall traces will not work.",
507 machine.ToStdString().c_str());
508 }
509
510 SystemInfoTracker* system_info_tracker =
511 SystemInfoTracker::GetOrCreate(context_);
512 system_info_tracker->SetKernelVersion(utsname.sysname(), utsname.release());
513
514 StringPool::Id sysname_id =
515 context_->storage->InternString(utsname.sysname());
516 StringPool::Id version_id =
517 context_->storage->InternString(utsname.version());
518 StringPool::Id release_id =
519 context_->storage->InternString(utsname.release());
520 StringPool::Id machine_id =
521 context_->storage->InternString(utsname.machine());
522
523 MetadataTracker* metadata = context_->metadata_tracker.get();
524 metadata->SetMetadata(metadata::system_name, Variadic::String(sysname_id));
525 metadata->SetMetadata(metadata::system_version,
526 Variadic::String(version_id));
527 metadata->SetMetadata(metadata::system_release,
528 Variadic::String(release_id));
529 metadata->SetMetadata(metadata::system_machine,
530 Variadic::String(machine_id));
531 }
532
533 if (packet.has_android_build_fingerprint()) {
534 context_->metadata_tracker->SetMetadata(
535 metadata::android_build_fingerprint,
536 Variadic::String(context_->storage->InternString(
537 packet.android_build_fingerprint())));
538 }
539
540 // If we have the SDK version in the trace directly just use that.
541 // Otherwise, try and parse it from the fingerprint.
542 base::Optional<int64_t> opt_sdk_version;
543 if (packet.has_android_sdk_version()) {
544 opt_sdk_version = static_cast<int64_t>(packet.android_sdk_version());
545 } else if (packet.has_android_build_fingerprint()) {
546 opt_sdk_version = FingerprintToSdkVersion(
547 packet.android_build_fingerprint().ToStdString());
548 }
549
550 if (opt_sdk_version) {
551 context_->metadata_tracker->SetMetadata(
552 metadata::android_sdk_version, Variadic::Integer(*opt_sdk_version));
553 }
554
555 int64_t hz = packet.hz();
556 if (hz > 0)
557 ms_per_tick_ = 1000u / static_cast<uint64_t>(hz);
558 }
559
ParseCpuInfo(ConstBytes blob)560 void SystemProbesParser::ParseCpuInfo(ConstBytes blob) {
561 // invalid_freq is used as the guard in
562 // thread_time_in_state_cpu_freq_ids_, see IsValidCpuFreqIndex.
563 uint32_t invalid_freq = 0;
564 thread_time_in_state_cpu_freqs_.push_back(invalid_freq);
565
566 protos::pbzero::CpuInfo::Decoder packet(blob.data, blob.size);
567 uint32_t cpu_index = 0;
568 uint32_t time_in_state_cpu_index = 0;
569 size_t freq_index = 1;
570 std::vector<uint32_t> last_cpu_freqs;
571 for (auto it = packet.cpus(); it; it++) {
572 thread_time_in_state_freq_index_.push_back(freq_index);
573
574 protos::pbzero::CpuInfo::Cpu::Decoder cpu(*it);
575 tables::CpuTable::Row cpu_row;
576 if (cpu.has_processor())
577 cpu_row.processor = context_->storage->InternString(cpu.processor());
578 std::vector<uint32_t> freqs;
579 for (auto freq_it = cpu.frequencies(); freq_it; freq_it++)
580 freqs.push_back(*freq_it);
581 if (freqs != last_cpu_freqs) {
582 time_in_state_cpu_index = cpu_index;
583 thread_time_in_state_cpus_.insert(cpu_index);
584 }
585 cpu_row.time_in_state_cpu_id = time_in_state_cpu_index;
586 last_cpu_freqs = freqs;
587 tables::CpuTable::Id cpu_row_id =
588 context_->storage->mutable_cpu_table()->Insert(cpu_row).id;
589
590 for (auto freq_it = cpu.frequencies(); freq_it; freq_it++) {
591 uint32_t freq = *freq_it;
592 tables::CpuFreqTable::Row cpu_freq_row;
593 cpu_freq_row.cpu_id = cpu_row_id;
594 cpu_freq_row.freq = freq;
595 context_->storage->mutable_cpu_freq_table()->Insert(cpu_freq_row);
596 thread_time_in_state_cpu_freqs_.push_back(freq);
597 freq_index++;
598 }
599
600 cpu_index++;
601 }
602 thread_time_in_state_freq_index_.push_back(freq_index);
603 thread_time_in_state_cpu_freqs_.push_back(invalid_freq);
604 }
605
IsValidCpuFreqIndex(uint32_t freq_index) const606 bool SystemProbesParser::IsValidCpuFreqIndex(uint32_t freq_index) const {
607 // Frequency index 0 is invalid.
608 return freq_index > 0 && freq_index < thread_time_in_state_cpu_freqs_.size();
609 }
610
611 } // namespace trace_processor
612 } // namespace perfetto
613