/* * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "src/trace_processor/ftrace_utils.h" #include <stdint.h> #include <algorithm> #include "perfetto/base/logging.h" #include "perfetto/base/string_writer.h" namespace perfetto { namespace trace_processor { namespace ftrace_utils { namespace { struct FtraceTime { FtraceTime(int64_t ns) : secs(ns / 1000000000LL), micros((ns - secs * 1000000000LL) / 1000) {} const int64_t secs; const int64_t micros; }; } // namespace TaskState::TaskState(const char* state_str) { bool invalid_char = false; bool is_runnable = false; for (size_t i = 0; state_str[i] != '\0'; i++) { char c = state_str[i]; if (is_kernel_preempt()) { // No other character should be encountered after '+'. invalid_char = true; break; } else if (c == '+') { state_ |= kMaxState; continue; } if (is_runnable) { // We should not encounter any character apart from '+' if runnable. invalid_char = true; break; } if (c == 'R') { if (state_ != 0) { // We should not encounter R if we already have set other atoms. invalid_char = true; break; } else { is_runnable = true; continue; } } if (c == 'S') state_ |= Atom::kInterruptibleSleep; else if (c == 'D') state_ |= Atom::kUninterruptibleSleep; else if (c == 'T') state_ |= Atom::kStopped; else if (c == 't') state_ |= Atom::kTraced; else if (c == 'X') state_ |= Atom::kExitDead; else if (c == 'Z') state_ |= Atom::kExitZombie; else if (c == 'x') state_ |= Atom::kTaskDead; else if (c == 'K') state_ |= Atom::kWakeKill; else if (c == 'W') state_ |= Atom::kWaking; else if (c == 'P') state_ |= Atom::kParked; else if (c == 'N') state_ |= Atom::kNoLoad; else { invalid_char = true; break; } } bool no_state = !is_runnable && state_ == 0; if (invalid_char || no_state) { state_ = 0; } else { state_ |= kValid; } } TaskState::TaskStateStr TaskState::ToString() const { PERFETTO_CHECK(is_valid()); char buffer[32]; size_t pos = 0; // This mapping is given by the file // https://android.googlesource.com/kernel/msm.git/+/android-msm-wahoo-4.4-pie-qpr1/include/trace/events/sched.h#155 if (is_runnable()) { buffer[pos++] = 'R'; } else { if (state_ & Atom::kInterruptibleSleep) buffer[pos++] = 'S'; if (state_ & Atom::kUninterruptibleSleep) buffer[pos++] = 'D'; // D for (D)isk sleep if (state_ & Atom::kStopped) buffer[pos++] = 'T'; if (state_ & Atom::kTraced) buffer[pos++] = 't'; if (state_ & Atom::kExitDead) buffer[pos++] = 'X'; if (state_ & Atom::kExitZombie) buffer[pos++] = 'Z'; if (state_ & Atom::kTaskDead) buffer[pos++] = 'x'; if (state_ & Atom::kWakeKill) buffer[pos++] = 'K'; if (state_ & Atom::kWaking) buffer[pos++] = 'W'; if (state_ & Atom::kParked) buffer[pos++] = 'P'; if (state_ & Atom::kNoLoad) buffer[pos++] = 'N'; } if (is_kernel_preempt()) buffer[pos++] = '+'; TaskStateStr output{}; memcpy(output.data(), buffer, std::min(pos, output.size() - 1)); return output; } void FormatSystracePrefix(int64_t timestamp, uint32_t cpu, uint32_t pid, uint32_t tgid, base::StringView name, base::StringWriter* writer) { FtraceTime ftrace_time(timestamp); if (pid == 0) { name = "<idle>"; } int64_t padding = 16 - static_cast<int64_t>(name.size()); if (PERFETTO_LIKELY(padding > 0)) { writer->AppendChar(' ', static_cast<size_t>(padding)); } writer->AppendString(name); writer->AppendChar('-'); size_t pre_pid_pos = writer->pos(); writer->AppendInt(pid); size_t pid_chars = writer->pos() - pre_pid_pos; if (PERFETTO_LIKELY(pid_chars < 5)) { writer->AppendChar(' ', 5 - pid_chars); } writer->AppendLiteral(" ("); if (tgid == 0) { writer->AppendLiteral("-----"); } else { writer->AppendPaddedInt<' ', 5>(tgid); } writer->AppendLiteral(") ["); writer->AppendPaddedInt<'0', 3>(cpu); writer->AppendLiteral("] .... "); writer->AppendInt(ftrace_time.secs); writer->AppendChar('.'); writer->AppendPaddedInt<'0', 6>(ftrace_time.micros); writer->AppendChar(':'); } } // namespace ftrace_utils } // namespace trace_processor } // namespace perfetto