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/ftrace_utils.h" 18 19 #include <stdint.h> 20 #include <algorithm> 21 22 #include "perfetto/base/logging.h" 23 #include "perfetto/base/string_writer.h" 24 25 namespace perfetto { 26 namespace trace_processor { 27 namespace ftrace_utils { 28 29 namespace { 30 struct FtraceTime { 31 FtraceTime(int64_t ns) 32 : secs(ns / 1000000000LL), micros((ns - secs * 1000000000LL) / 1000) {} 33 34 const int64_t secs; 35 const int64_t micros; 36 }; 37 } // namespace 38 39 TaskState::TaskState(const char* state_str) { 40 bool invalid_char = false; 41 bool is_runnable = false; 42 for (size_t i = 0; state_str[i] != '\0'; i++) { 43 char c = state_str[i]; 44 if (is_kernel_preempt()) { 45 // No other character should be encountered after '+'. 46 invalid_char = true; 47 break; 48 } else if (c == '+') { 49 state_ |= kMaxState; 50 continue; 51 } 52 53 if (is_runnable) { 54 // We should not encounter any character apart from '+' if runnable. 55 invalid_char = true; 56 break; 57 } 58 59 if (c == 'R') { 60 if (state_ != 0) { 61 // We should not encounter R if we already have set other atoms. 62 invalid_char = true; 63 break; 64 } else { 65 is_runnable = true; 66 continue; 67 } 68 } 69 70 if (c == 'S') 71 state_ |= Atom::kInterruptibleSleep; 72 else if (c == 'D') 73 state_ |= Atom::kUninterruptibleSleep; 74 else if (c == 'T') 75 state_ |= Atom::kStopped; 76 else if (c == 't') 77 state_ |= Atom::kTraced; 78 else if (c == 'X') 79 state_ |= Atom::kExitDead; 80 else if (c == 'Z') 81 state_ |= Atom::kExitZombie; 82 else if (c == 'x') 83 state_ |= Atom::kTaskDead; 84 else if (c == 'K') 85 state_ |= Atom::kWakeKill; 86 else if (c == 'W') 87 state_ |= Atom::kWaking; 88 else if (c == 'P') 89 state_ |= Atom::kParked; 90 else if (c == 'N') 91 state_ |= Atom::kNoLoad; 92 else { 93 invalid_char = true; 94 break; 95 } 96 } 97 98 bool no_state = !is_runnable && state_ == 0; 99 if (invalid_char || no_state) { 100 state_ = 0; 101 } else { 102 state_ |= kValid; 103 } 104 } 105 106 TaskState::TaskStateStr TaskState::ToString() const { 107 PERFETTO_CHECK(is_valid()); 108 109 char buffer[32]; 110 size_t pos = 0; 111 112 // This mapping is given by the file 113 // https://android.googlesource.com/kernel/msm.git/+/android-msm-wahoo-4.4-pie-qpr1/include/trace/events/sched.h#155 114 if (is_runnable()) { 115 buffer[pos++] = 'R'; 116 } else { 117 if (state_ & Atom::kInterruptibleSleep) 118 buffer[pos++] = 'S'; 119 if (state_ & Atom::kUninterruptibleSleep) 120 buffer[pos++] = 'D'; // D for (D)isk sleep 121 if (state_ & Atom::kStopped) 122 buffer[pos++] = 'T'; 123 if (state_ & Atom::kTraced) 124 buffer[pos++] = 't'; 125 if (state_ & Atom::kExitDead) 126 buffer[pos++] = 'X'; 127 if (state_ & Atom::kExitZombie) 128 buffer[pos++] = 'Z'; 129 if (state_ & Atom::kTaskDead) 130 buffer[pos++] = 'x'; 131 if (state_ & Atom::kWakeKill) 132 buffer[pos++] = 'K'; 133 if (state_ & Atom::kWaking) 134 buffer[pos++] = 'W'; 135 if (state_ & Atom::kParked) 136 buffer[pos++] = 'P'; 137 if (state_ & Atom::kNoLoad) 138 buffer[pos++] = 'N'; 139 } 140 141 if (is_kernel_preempt()) 142 buffer[pos++] = '+'; 143 144 TaskStateStr output{}; 145 memcpy(output.data(), buffer, std::min(pos, output.size() - 1)); 146 return output; 147 } 148 149 void FormatSystracePrefix(int64_t timestamp, 150 uint32_t cpu, 151 uint32_t pid, 152 uint32_t tgid, 153 base::StringView name, 154 base::StringWriter* writer) { 155 FtraceTime ftrace_time(timestamp); 156 if (pid == 0) { 157 name = "<idle>"; 158 } 159 160 int64_t padding = 16 - static_cast<int64_t>(name.size()); 161 if (PERFETTO_LIKELY(padding > 0)) { 162 writer->AppendChar(' ', static_cast<size_t>(padding)); 163 } 164 writer->AppendString(name); 165 writer->AppendChar('-'); 166 167 size_t pre_pid_pos = writer->pos(); 168 writer->AppendInt(pid); 169 size_t pid_chars = writer->pos() - pre_pid_pos; 170 if (PERFETTO_LIKELY(pid_chars < 5)) { 171 writer->AppendChar(' ', 5 - pid_chars); 172 } 173 174 writer->AppendLiteral(" ("); 175 if (tgid == 0) { 176 writer->AppendLiteral("-----"); 177 } else { 178 writer->AppendPaddedInt<' ', 5>(tgid); 179 } 180 writer->AppendLiteral(") ["); 181 writer->AppendPaddedInt<'0', 3>(cpu); 182 writer->AppendLiteral("] .... "); 183 184 writer->AppendInt(ftrace_time.secs); 185 writer->AppendChar('.'); 186 writer->AppendPaddedInt<'0', 6>(ftrace_time.micros); 187 writer->AppendChar(':'); 188 } 189 190 } // namespace ftrace_utils 191 } // namespace trace_processor 192 } // namespace perfetto 193