xref: /aosp_15_r20/external/perfetto/src/trace_processor/types/task_state.h (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
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 #ifndef SRC_TRACE_PROCESSOR_TYPES_TASK_STATE_H_
18 #define SRC_TRACE_PROCESSOR_TYPES_TASK_STATE_H_
19 
20 #include <stdint.h>
21 #include <array>
22 #include <optional>
23 
24 #include "src/trace_processor/types/version_number.h"
25 
26 namespace perfetto {
27 namespace trace_processor {
28 namespace ftrace_utils {
29 
30 // Linux kernel scheduling events (sched_switch) contain a bitmask of the
31 // switched-out task's state (prev_state). Perfetto doesn't record the event
32 // format string during tracing, the trace contains only the raw bitmask as an
33 // integer. Certain kernel versions made backwards incompatible changes to the
34 // bitmask's raw representation, so this class guesses how to decode the flags
35 // based on the kernel's major+minor version as recorded in the trace. Note:
36 // this means we can be wrong if patch backports change the flags, or the
37 // kernel diverged from upstream. But this has worked well enough in practice
38 // so far.
39 //
40 // There are three specific kernel version intervals we handle:
41 // * [4.14, ...)
42 // * [4.8, 4.14)
43 // * (..., 4.8), where we assume the 4.4 bitmask
44 //
45 // (Therefore kernels before 4.2 most likely have incorrect preemption flag
46 // parsing.)
47 //
48 // For 4.14, we assume that the kernel has a backport of the bugfix
49 // https://github.com/torvalds/linux/commit/3f5fe9fe ("sched/debug: Fix task
50 // state recording/printout"). In other words, traces collected on unpatched
51 // 4.14 kernels will have incorrect flags decoded.
52 class TaskState {
53  public:
54   using TaskStateStr = std::array<char, 4>;
55 
56   // We transcode the raw bitmasks into a set of these flags to make them
57   // kernel version agnostic.
58   //
59   // Warning: do NOT depend on the numeric values of these constants, and
60   // especially do NOT attempt to use these constants when operating on raw
61   // prev_state masks unless you're changing task_state.cc itself.
62   enum ParsedFlag : uint16_t {
63     kRunnable = 0x0000,  // no flag (besides kPreempted) means "running"
64     kInterruptibleSleep = 0x0001,
65     kUninterruptibleSleep = 0x0002,
66     kStopped = 0x0004,
67     kTraced = 0x0008,
68     kExitDead = 0x0010,
69     kExitZombie = 0x0020,
70 
71     // Starting from here, different kernels have different values:
72     kParked = 0x0040,
73 
74     // No longer reported on 4.14+:
75     kTaskDead = 0x0080,
76     kWakeKill = 0x0100,
77     kWaking = 0x0200,
78     kNoLoad = 0x0400,
79 
80     // Special states that don't map onto the scheduler's constants:
81     kIdle = 0x4000,
82     kPreempted = 0x8000,  // exclusive as only running tasks can be preempted
83 
84     // Sentinel value that is an invalid combination of flags:
85     kInvalid = 0xffff
86   };
87 
88   static TaskState FromRawPrevState(
89       uint16_t raw_state,
90       std::optional<VersionNumber> kernel_version);
91   static TaskState FromSystrace(const char* state_str);
92   static TaskState FromParsedFlags(uint16_t parsed_state);
93 
94   // TODO(rsavitski): consider moving the factory methods to an optional return
95   // type instead.
is_valid()96   bool is_valid() const { return parsed_ != kInvalid; }
97 
98   // Returns the textual representation of this state as a null-terminated
99   // array. |separator| specifies if a separator should be printed between the
100   // atoms (default: \0 meaning no separator).
101   TaskStateStr ToString(char separator = '\0') const;
102 
103   // Converts the TaskState back to the raw format, to be used only when
104   // parsing systrace.
105   // NB: this makes a hard assumption on the 4.4 flag layout, since systrace
106   // files don't specify a kernel version, so when trace_processor later calls
107   // FromRawPrevState to construct sched.end_state column values, it'll default
108   // to the 4.4 layout.
109   // TODO(rsavitski): can we get rid of this entirely and avoid the
110   // str -> TaskState -> uint16_t -> str conversion chain?
111   uint16_t ToRawStateOnlyForSystraceConversions() const;
112 
ParsedForTesting()113   uint16_t ParsedForTesting() const { return parsed_; }
114 
115  private:
116   TaskState() = default;
117   explicit TaskState(uint16_t raw_state,
118                      std::optional<VersionNumber> kernel_version);
119   explicit TaskState(const char* state_str);
120 
is_runnable()121   bool is_runnable() const { return !(parsed_ & ~kPreempted); }
122 
123   uint16_t parsed_ = 0;
124 };
125 
126 }  // namespace ftrace_utils
127 }  // namespace trace_processor
128 }  // namespace perfetto
129 
130 #endif  // SRC_TRACE_PROCESSOR_TYPES_TASK_STATE_H_
131