• 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/types/task_state.h"
18 
19 #include <stdint.h>
20 #include <algorithm>
21 
22 #include "perfetto/base/logging.h"
23 #include "perfetto/ext/base/string_writer.h"
24 
25 namespace perfetto {
26 namespace trace_processor {
27 namespace ftrace_utils {
28 
TaskState(uint16_t raw_state,base::Optional<VersionNumber> opt_version)29 TaskState::TaskState(uint16_t raw_state,
30                      base::Optional<VersionNumber> opt_version) {
31   auto version = VersionNumber{4, 4};
32   if (opt_version) {
33     version = opt_version.value();
34   }
35   max_state_ = version < VersionNumber{4, 9} ? 2048 : 4096;
36 
37   if (raw_state > max_state_) {
38     state_ = 0;
39   } else {
40     state_ |= kValid;
41   }
42 
43   if (version < VersionNumber{4, 14}) {
44     state_ |= raw_state;
45     return;
46   }
47   // All values below kTaskDead are consistent between kernels.
48   state_ |= raw_state & (kTaskDead - 1);
49 
50   // Only values up to 0x80 (plus max_state) are relevant in kernels >= 4.14.
51   // See
52   // https://android.googlesource.com/kernel/msm.git/+/refs/heads/android-msm-coral-4.14-android10-qpr1/include/trace/events/sched.h#219
53   if (raw_state & 0x40) {
54     state_ |= kParked;
55   }
56   if (raw_state & 0x80) {
57     state_ |= kTaskDead;
58   }
59   if (raw_state & max_state_) {
60     state_ |= max_state_;
61   }
62 }
63 
TaskState(const char * state_str)64 TaskState::TaskState(const char* state_str) {
65   bool invalid_char = false;
66   bool is_runnable = false;
67   for (size_t i = 0; state_str[i] != '\0'; i++) {
68     char c = state_str[i];
69     if (is_kernel_preempt()) {
70       // No other character should be encountered after '+'.
71       invalid_char = true;
72       break;
73     } else if (c == '+') {
74       state_ |= max_state_;
75       continue;
76     }
77 
78     if (is_runnable) {
79       // We should not encounter any character apart from '+' if runnable.
80       invalid_char = true;
81       break;
82     }
83 
84     if (c == 'R') {
85       if (state_ != 0) {
86         // We should not encounter R if we already have set other atoms.
87         invalid_char = true;
88         break;
89       } else {
90         is_runnable = true;
91         continue;
92       }
93     }
94 
95     if (c == 'S')
96       state_ |= Atom::kInterruptibleSleep;
97     else if (c == 'D')
98       state_ |= Atom::kUninterruptibleSleep;
99     else if (c == 'T')
100       state_ |= Atom::kStopped;
101     else if (c == 't')
102       state_ |= Atom::kTraced;
103     else if (c == 'X')
104       state_ |= Atom::kExitDead;
105     else if (c == 'Z')
106       state_ |= Atom::kExitZombie;
107     else if (c == 'x' || c == 'I')
108       // On Linux kernels 4.14+, the character for task dead changed
109       // from 'x' to 'I'.
110       state_ |= Atom::kTaskDead;
111     else if (c == 'K')
112       state_ |= Atom::kWakeKill;
113     else if (c == 'W')
114       state_ |= Atom::kWaking;
115     else if (c == 'P')
116       state_ |= Atom::kParked;
117     else if (c == 'N')
118       state_ |= Atom::kNoLoad;
119     else if (c == '|')
120       continue;
121     else {
122       invalid_char = true;
123       break;
124     }
125   }
126   bool no_state = !is_runnable && state_ == 0;
127   if (invalid_char || no_state || state_ > max_state_) {
128     state_ = 0;
129   } else {
130     state_ |= kValid;
131   }
132 }
133 
ToString(char separator) const134 TaskState::TaskStateStr TaskState::ToString(char separator) const {
135   if (!is_valid()) {
136     return TaskStateStr{"?"};
137   }
138 
139   char buffer[32];
140   size_t pos = 0;
141 
142   // This mapping is given by the file
143   // https://android.googlesource.com/kernel/msm.git/+/android-msm-wahoo-4.4-pie-qpr1/include/trace/events/sched.h#155
144   // Some of these flags are ignored in later kernels but we output them anyway.
145   if (is_runnable()) {
146     buffer[pos++] = 'R';
147   } else {
148     if (state_ & Atom::kInterruptibleSleep)
149       buffer[pos++] = 'S';
150     if (state_ & Atom::kUninterruptibleSleep) {
151       if (separator && pos != 0)
152         buffer[pos++] = separator;
153       buffer[pos++] = 'D';  // D for (D)isk sleep
154     }
155     if (state_ & Atom::kStopped) {
156       if (separator && pos != 0)
157         buffer[pos++] = separator;
158       buffer[pos++] = 'T';
159     }
160     if (state_ & Atom::kTraced) {
161       if (separator && pos != 0)
162         buffer[pos++] = separator;
163       buffer[pos++] = 't';
164     }
165     if (state_ & Atom::kExitDead) {
166       if (separator && pos != 0)
167         buffer[pos++] = separator;
168       buffer[pos++] = 'X';
169     }
170     if (state_ & Atom::kExitZombie) {
171       if (separator && pos != 0)
172         buffer[pos++] = separator;
173       buffer[pos++] = 'Z';
174     }
175     if (state_ & Atom::kTaskDead) {
176       if (separator && pos != 0)
177         buffer[pos++] = separator;
178       buffer[pos++] = 'I';
179     }
180     if (state_ & Atom::kWakeKill) {
181       if (separator && pos != 0)
182         buffer[pos++] = separator;
183       buffer[pos++] = 'K';
184     }
185     if (state_ & Atom::kWaking) {
186       if (separator && pos != 0)
187         buffer[pos++] = separator;
188       buffer[pos++] = 'W';
189     }
190     if (state_ & Atom::kParked) {
191       if (separator && pos != 0)
192         buffer[pos++] = separator;
193       buffer[pos++] = 'P';
194     }
195     if (state_ & Atom::kNoLoad) {
196       if (separator && pos != 0)
197         buffer[pos++] = separator;
198       buffer[pos++] = 'N';
199     }
200   }
201 
202   if (is_kernel_preempt())
203     buffer[pos++] = '+';
204 
205   TaskStateStr output{};
206   memcpy(output.data(), buffer, std::min(pos, output.size() - 1));
207   return output;
208 }
209 
210 }  // namespace ftrace_utils
211 }  // namespace trace_processor
212 }  // namespace perfetto
213