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 {
FtraceTimeperfetto::trace_processor::ftrace_utils::__anon7fd62b5f0111::FtraceTime31 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
TaskState(const char * state_str)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
ToString() const106 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
FormatSystracePrefix(int64_t timestamp,uint32_t cpu,uint32_t pid,uint32_t tgid,base::StringView name,base::StringWriter * writer)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