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