1 // Copyright 2014 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef BASE_TASK_COMMON_TASK_ANNOTATOR_H_ 6 #define BASE_TASK_COMMON_TASK_ANNOTATOR_H_ 7 8 #include <stdint.h> 9 10 #include "base/auto_reset.h" 11 #include "base/base_export.h" 12 #include "base/memory/raw_ptr_exclusion.h" 13 #include "base/pending_task.h" 14 #include "base/strings/string_piece.h" 15 #include "base/time/tick_clock.h" 16 #include "base/trace_event/base_tracing.h" 17 18 namespace base { 19 20 // Constant used to measure which long-running tasks should be traced. 21 constexpr TimeDelta kMaxTaskDurationTimeDelta = Milliseconds(4); 22 23 // Implements common debug annotations for posted tasks. This includes data 24 // such as task origins, IPC message contexts, queueing durations and memory 25 // usage. 26 class BASE_EXPORT TaskAnnotator { 27 public: 28 class ObserverForTesting { 29 public: 30 // Invoked just before RunTask() in the scope in which the task is about to 31 // be executed. 32 virtual void BeforeRunTask(const PendingTask* pending_task) = 0; 33 }; 34 35 // This is used to set the |ipc_hash| field for PendingTasks. It is intended 36 // to be used only from within generated IPC handler dispatch code. 37 class ScopedSetIpcHash; 38 39 // This is used to track long-running browser-UI tasks. It is intended to 40 // be used for low-overhead logging to produce longer traces, particularly to 41 // help the scroll jank reduction effort. 42 class LongTaskTracker; 43 44 static const PendingTask* CurrentTaskForThread(); 45 46 static void OnIPCReceived(const char* interface_name, 47 uint32_t (*method_info)(), 48 bool is_response); 49 50 static void MarkCurrentTaskAsInterestingForTracing(); 51 52 TaskAnnotator(); 53 54 TaskAnnotator(const TaskAnnotator&) = delete; 55 TaskAnnotator& operator=(const TaskAnnotator&) = delete; 56 57 ~TaskAnnotator(); 58 59 // Called to indicate that a task is about to be queued to run in the future, 60 // giving one last chance for this TaskAnnotator to add metadata to 61 // |pending_task| before it is moved into the queue. 62 void WillQueueTask(perfetto::StaticString trace_event_name, 63 TaskMetadata* pending_task); 64 65 // Creates a process-wide unique ID to represent this task in trace events. 66 // This will be mangled with a Process ID hash to reduce the likelyhood of 67 // colliding with TaskAnnotator pointers on other processes. Callers may use 68 // this when generating their own flow events (i.e. when passing 69 // |queue_function == nullptr| in above methods). 70 uint64_t GetTaskTraceID(const TaskMetadata& task) const; 71 72 // Run the given task, emitting the toplevel trace event and additional 73 // trace event arguments. Like for TRACE_EVENT macros, all of the arguments 74 // are used (i.e. lambdas are invoked) before this function exits, so it's 75 // safe to pass reference-capturing lambdas here. 76 template <typename... Args> RunTask(perfetto::StaticString event_name,PendingTask & pending_task,Args &&...args)77 void RunTask(perfetto::StaticString event_name, 78 PendingTask& pending_task, 79 Args&&... args) { 80 TRACE_EVENT( 81 "toplevel", event_name, 82 [&](perfetto::EventContext& ctx) { 83 EmitTaskLocation(ctx, pending_task); 84 MaybeEmitDelayAndPolicy(ctx, pending_task); 85 MaybeEmitIncomingTaskFlow(ctx, pending_task); 86 MaybeEmitIPCHash(ctx, pending_task); 87 }, 88 std::forward<Args>(args)...); 89 RunTaskImpl(pending_task); 90 } 91 92 private: 93 friend class TaskAnnotatorBacktraceIntegrationTest; 94 95 // Run a previously queued task. 96 NOT_TAIL_CALLED void RunTaskImpl(PendingTask& pending_task); 97 98 // Registers an ObserverForTesting that will be invoked by all TaskAnnotators' 99 // RunTask(). This registration and the implementation of BeforeRunTask() are 100 // responsible to ensure thread-safety. 101 static void RegisterObserverForTesting(ObserverForTesting* observer); 102 static void ClearObserverForTesting(); 103 104 #if BUILDFLAG(ENABLE_BASE_TRACING) 105 // TRACE_EVENT argument helper, writing the task location data into 106 // EventContext. 107 static void EmitTaskLocation(perfetto::EventContext& ctx, 108 const PendingTask& task); 109 static void MaybeEmitDelayAndPolicy(perfetto::EventContext& ctx, 110 const PendingTask& task); 111 112 // TRACE_EVENT argument helper, writing the incoming task flow information 113 // into EventContext if toplevel.flow category is enabled. 114 void MaybeEmitIncomingTaskFlow(perfetto::EventContext& ctx, 115 const PendingTask& task) const; 116 117 void MaybeEmitIPCHash(perfetto::EventContext& ctx, 118 const PendingTask& task) const; 119 #endif // BUILDFLAG(ENABLE_BASE_TRACING) 120 }; 121 122 class BASE_EXPORT [[maybe_unused, nodiscard]] TaskAnnotator::ScopedSetIpcHash { 123 public: 124 explicit ScopedSetIpcHash(uint32_t ipc_hash); 125 126 // Compile-time-const string identifying the current IPC context. Not always 127 // available due to binary size constraints, so IPC hash might be set instead. 128 explicit ScopedSetIpcHash(const char* ipc_interface_name); 129 130 ScopedSetIpcHash(const ScopedSetIpcHash&) = delete; 131 ScopedSetIpcHash& operator=(const ScopedSetIpcHash&) = delete; 132 133 ~ScopedSetIpcHash(); 134 GetIpcHash()135 uint32_t GetIpcHash() const { return ipc_hash_; } GetIpcInterfaceName()136 const char* GetIpcInterfaceName() const { return ipc_interface_name_; } 137 138 static uint32_t MD5HashMetricName(base::StringPiece name); 139 140 private: 141 ScopedSetIpcHash(uint32_t ipc_hash, const char* ipc_interface_name); 142 143 const AutoReset<ScopedSetIpcHash*> resetter_; 144 uint32_t ipc_hash_; 145 const char* ipc_interface_name_; 146 }; 147 148 class BASE_EXPORT [[maybe_unused, nodiscard]] TaskAnnotator::LongTaskTracker { 149 public: 150 explicit LongTaskTracker(const TickClock* tick_clock, 151 PendingTask& pending_task, 152 TaskAnnotator* task_annotator); 153 154 LongTaskTracker(const LongTaskTracker&) = delete; 155 156 ~LongTaskTracker(); 157 158 void SetIpcDetails(const char* interface_name, 159 uint32_t (*method_info)(), 160 bool is_response); 161 162 void MaybeTraceInterestingTaskDetails(); 163 164 // In long-task tracking, not every task (including its queue time) will be 165 // recorded in a trace. If a particular task + queue time needs to be 166 // recorded, flag it explicitly. For example, input tasks are required for 167 // calculating scroll jank metrics. 168 bool is_interesting_task = false; 169 170 private: 171 void EmitReceivedIPCDetails(perfetto::EventContext& ctx); 172 173 const AutoReset<LongTaskTracker*> resetter_; 174 175 // For tracking task duration. 176 // 177 // Not a raw_ptr<...> for performance reasons: based on analysis of sampling 178 // profiler data (TaskAnnotator::LongTaskTracker::~LongTaskTracker). 179 RAW_PTR_EXCLUSION const TickClock* tick_clock_; // Not owned. 180 TimeTicks task_start_time_; 181 TimeTicks task_end_time_; 182 183 // Tracing variables. 184 185 // Use this to ensure that tracing and NowTicks() are not called 186 // unnecessarily. 187 bool is_tracing_; 188 const char* ipc_interface_name_ = nullptr; 189 uint32_t ipc_hash_ = 0; 190 191 // IPC method info to retrieve IPC hash and method address from trace, if 192 // known. Note that this will not compile in the Native client. 193 uint32_t (*ipc_method_info_)(); 194 bool is_response_ = false; 195 // Not a raw_ptr/raw_ref<...> for performance reasons: based on analysis of 196 // sampling profiler data (TaskAnnotator::LongTaskTracker::~LongTaskTracker). 197 [[maybe_unused]] RAW_PTR_EXCLUSION PendingTask& pending_task_; 198 [[maybe_unused]] RAW_PTR_EXCLUSION TaskAnnotator* task_annotator_; 199 }; 200 201 } // namespace base 202 203 #endif // BASE_TASK_COMMON_TASK_ANNOTATOR_H_ 204