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