• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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