HelperThreads.h (10782B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 /* 8 * API for managing off-thread work. 9 */ 10 11 #ifndef vm_HelperThreads_h 12 #define vm_HelperThreads_h 13 14 #include "mozilla/Variant.h" 15 16 #include "js/AllocPolicy.h" 17 #include "js/HelperThreadAPI.h" 18 #include "js/shadow/Zone.h" 19 #include "js/UniquePtr.h" 20 #include "js/Vector.h" 21 #include "threading/LockGuard.h" 22 #include "threading/Mutex.h" 23 #include "wasm/WasmConstants.h" 24 25 namespace mozilla { 26 union Utf8Unit; 27 } 28 29 namespace JS { 30 class JS_PUBLIC_API ReadOnlyCompileOptions; 31 class JS_PUBLIC_API ReadOnlyDecodeOptions; 32 class Zone; 33 34 template <typename UnitT> 35 class SourceText; 36 } // namespace JS 37 38 namespace js { 39 40 class AutoLockHelperThreadState; 41 struct PromiseHelperTask; 42 43 namespace frontend { 44 struct InitialStencilAndDelazifications; 45 } 46 47 namespace gc { 48 class GCRuntime; 49 } 50 51 namespace jit { 52 class BaselineCompileTask; 53 class IonCompileTask; 54 class IonFreeTask; 55 class JitRuntime; 56 using IonFreeCompileTasks = Vector<IonCompileTask*, 8, SystemAllocPolicy>; 57 } // namespace jit 58 59 namespace wasm { 60 struct CompileTask; 61 struct CompileTaskState; 62 struct CompleteTier2GeneratorTask; 63 using UniqueCompleteTier2GeneratorTask = UniquePtr<CompleteTier2GeneratorTask>; 64 struct PartialTier2CompileTask; 65 using UniquePartialTier2CompileTask = UniquePtr<PartialTier2CompileTask>; 66 } // namespace wasm 67 68 /* 69 * Lock protecting all mutable shared state accessed by helper threads, and used 70 * by all condition variables. 71 */ 72 extern Mutex gHelperThreadLock MOZ_UNANNOTATED; 73 74 // Set of tasks to dispatch when the helper thread state lock is released. 75 class AutoHelperTaskQueue { 76 public: 77 ~AutoHelperTaskQueue() { dispatchQueuedTasks(); } 78 bool hasQueuedTasks() const { return !tasksToDispatch.empty(); } 79 void queueTaskToDispatch(JS::HelperThreadTask* task) const; 80 void dispatchQueuedTasks(); 81 82 private: 83 // TODO: Convert this to use a linked list. 84 mutable Vector<JS::HelperThreadTask*, 1, SystemAllocPolicy> tasksToDispatch; 85 }; 86 87 // A lock guard for data protected by the helper thread lock. 88 // 89 // This can also queue helper thread tasks to be triggered when the lock is 90 // released. 91 class MOZ_RAII AutoLockHelperThreadState 92 : public AutoHelperTaskQueue, // Must come before LockGuard. 93 public LockGuard<Mutex> { 94 public: 95 AutoLockHelperThreadState() : LockGuard<Mutex>(gHelperThreadLock) {} 96 AutoLockHelperThreadState(const AutoLockHelperThreadState&) = delete; 97 98 private: 99 friend class UnlockGuard<AutoLockHelperThreadState>; 100 void unlock() { 101 LockGuard<Mutex>::unlock(); 102 dispatchQueuedTasks(); 103 } 104 105 friend class GlobalHelperThreadState; 106 }; 107 108 using AutoUnlockHelperThreadState = UnlockGuard<AutoLockHelperThreadState>; 109 110 // Create data structures used by helper threads. 111 bool CreateHelperThreadsState(); 112 113 // Destroy data structures used by helper threads. 114 void DestroyHelperThreadsState(); 115 116 // Initialize helper threads unless already initialized. 117 bool EnsureHelperThreadsInitialized(); 118 119 size_t GetHelperThreadCount(); 120 size_t GetHelperThreadCPUCount(); 121 size_t GetMaxWasmCompilationThreads(); 122 123 // This allows the JS shell to override GetCPUCount() when passed the 124 // --thread-count=N option. 125 bool SetFakeCPUCount(size_t count); 126 127 // Enqueues a wasm compilation task. 128 bool StartOffThreadWasmCompile(wasm::CompileTask* task, 129 wasm::CompileState state); 130 131 // Remove any pending wasm compilation tasks queued with 132 // StartOffThreadWasmCompile that match the arguments. Return the number 133 // removed. 134 size_t RemovePendingWasmCompileTasks(const wasm::CompileTaskState& taskState, 135 wasm::CompileState state, 136 const AutoLockHelperThreadState& lock); 137 138 // Enqueues a wasm Complete Tier-2 compilation task. This (logically, at 139 // least) manages a set of sub-tasks that perform compilation of groups of 140 // functions. 141 void StartOffThreadWasmCompleteTier2Generator( 142 wasm::UniqueCompleteTier2GeneratorTask task); 143 144 // Enqueues a wasm Partial Tier-2 compilation task. This compiles one 145 // function, doing so itself, without any sub-tasks. 146 void StartOffThreadWasmPartialTier2Compile( 147 wasm::UniquePartialTier2CompileTask task); 148 149 // Cancel all background Wasm Complete Tier-2 compilations, both the generator 150 // task and the individual compilation tasks. 151 void CancelOffThreadWasmCompleteTier2Generator(); 152 153 // Cancel a single background Wasm Partial Tier-2 compilation. 154 void CancelOffThreadWasmPartialTier2Compile(); 155 156 /* 157 * If helper threads are available, call execute() then dispatchResolve() on the 158 * given task in a helper thread. If no helper threads are available, the given 159 * task is executed and resolved synchronously. 160 * 161 * This function takes ownership of task unconditionally; if it fails, task is 162 * deleted. 163 */ 164 bool StartOffThreadPromiseHelperTask(JSContext* cx, 165 UniquePtr<PromiseHelperTask> task); 166 167 /* 168 * Like the JSContext-accepting version, but only safe to use when helper 169 * threads are available, so we can be sure we'll never need to fall back on 170 * synchronous execution. 171 * 172 * This function can be called from any thread, but takes ownership of the task 173 * only on success. On OOM, it is the caller's responsibility to arrange for the 174 * task to be cleaned up properly. 175 */ 176 bool StartOffThreadPromiseHelperTask(PromiseHelperTask* task); 177 178 /* 179 * Schedule an off-thread Baseline compilation for a script, given a task. 180 */ 181 bool StartOffThreadBaselineCompile(jit::BaselineCompileTask* task, 182 const AutoLockHelperThreadState& lock); 183 184 void FinishOffThreadBaselineCompile(jit::BaselineCompileTask* task, 185 const AutoLockHelperThreadState& lock); 186 187 /* 188 * Schedule an off-thread Ion compilation for a script, given a task. 189 */ 190 bool StartOffThreadIonCompile(jit::IonCompileTask* task, 191 const AutoLockHelperThreadState& lock); 192 193 void FinishOffThreadIonCompile(jit::IonCompileTask* task, 194 const AutoLockHelperThreadState& lock); 195 196 // RAII class to handle batching compile tasks and starting an IonFreeTask. 197 class MOZ_RAII AutoStartIonFreeTask { 198 jit::JitRuntime* jitRuntime_; 199 200 // If true, start an IonFreeTask even if the batch is small. 201 bool force_; 202 203 public: 204 explicit AutoStartIonFreeTask(jit::JitRuntime* jitRuntime, bool force = false) 205 : jitRuntime_(jitRuntime), force_(force) {} 206 ~AutoStartIonFreeTask(); 207 208 [[nodiscard]] bool addIonCompileToFreeTaskBatch(jit::IonCompileTask* task); 209 }; 210 211 struct ZonesInState { 212 JSRuntime* runtime; 213 JS::shadow::Zone::GCState state; 214 }; 215 216 using CompilationSelector = 217 mozilla::Variant<JSScript*, JS::Zone*, ZonesInState, JSRuntime*>; 218 219 /* 220 * Cancel scheduled or in progress Ion compilations. 221 */ 222 void CancelOffThreadIonCompile(const CompilationSelector& selector); 223 224 inline void CancelOffThreadIonCompile(JSScript* script) { 225 CancelOffThreadIonCompile(CompilationSelector(script)); 226 } 227 228 inline void CancelOffThreadIonCompile(JS::Zone* zone) { 229 CancelOffThreadIonCompile(CompilationSelector(zone)); 230 } 231 232 inline void CancelOffThreadIonCompile(JSRuntime* runtime, 233 JS::shadow::Zone::GCState state) { 234 CancelOffThreadIonCompile(CompilationSelector(ZonesInState{runtime, state})); 235 } 236 237 inline void CancelOffThreadIonCompile(JSRuntime* runtime) { 238 CancelOffThreadIonCompile(CompilationSelector(runtime)); 239 } 240 241 #ifdef DEBUG 242 bool HasOffThreadIonCompile(JS::Zone* zone); 243 #endif 244 245 /* 246 * Cancel scheduled or in progress Baseline compilations. 247 */ 248 void CancelOffThreadBaselineCompile(const CompilationSelector& selector); 249 250 inline void CancelOffThreadBaselineCompile(JSScript* script) { 251 CancelOffThreadBaselineCompile(CompilationSelector(script)); 252 } 253 254 inline void CancelOffThreadBaselineCompile(JS::Zone* zone) { 255 CancelOffThreadBaselineCompile(CompilationSelector(zone)); 256 } 257 258 inline void CancelOffThreadBaselineCompile(JSRuntime* runtime, 259 JS::shadow::Zone::GCState state) { 260 CancelOffThreadBaselineCompile( 261 CompilationSelector(ZonesInState{runtime, state})); 262 } 263 264 inline void CancelOffThreadBaselineCompile(JSRuntime* runtime) { 265 CancelOffThreadBaselineCompile(CompilationSelector(runtime)); 266 } 267 268 /* 269 * Cancel baseline and Ion compilations. 270 */ 271 inline void CancelOffThreadCompile(JSRuntime* runtime, 272 JS::shadow::Zone::GCState state) { 273 CancelOffThreadBaselineCompile( 274 CompilationSelector(ZonesInState{runtime, state})); 275 CancelOffThreadIonCompile(CompilationSelector(ZonesInState{runtime, state})); 276 } 277 278 inline void CancelOffThreadCompile(JSRuntime* runtime) { 279 CancelOffThreadBaselineCompile(runtime); 280 CancelOffThreadIonCompile(runtime); 281 } 282 283 /* 284 * Cancel all scheduled or in progress eager delazification phases for a 285 * runtime. 286 */ 287 void CancelOffThreadDelazify(JSRuntime* runtime); 288 289 /* 290 * Wait for all delazification to complete. 291 */ 292 void WaitForAllDelazifyTasks(JSRuntime* rt); 293 294 // Start off-thread delazification task, to race the delazification of inner 295 // functions. 296 void StartOffThreadDelazification( 297 JSContext* maybeCx, const JS::ReadOnlyCompileOptions& options, 298 frontend::InitialStencilAndDelazifications* stencils); 299 300 // Drain the task queues and wait for all helper threads to finish running. 301 // 302 // Note that helper threads are shared between runtimes and it's possible that 303 // another runtime could saturate the helper thread system and cause this to 304 // never return. 305 void WaitForAllHelperThreads(); 306 void WaitForAllHelperThreads(AutoLockHelperThreadState& lock); 307 308 // Start handling any compression tasks for this runtime. Called at the start of 309 // major GC. 310 void StartOffThreadCompressionsOnGC(JSRuntime* rt, bool isShrinkingGC); 311 312 // Cancel all scheduled, in progress, or finished compression tasks for 313 // runtime. 314 void CancelOffThreadCompressions(JSRuntime* runtime); 315 316 void AttachFinishedCompressions(JSRuntime* runtime, 317 AutoLockHelperThreadState& lock); 318 319 // Run all pending source compression tasks synchronously, for testing purposes 320 void RunPendingSourceCompressions(JSRuntime* runtime); 321 322 // False if the off-thread source compression mechanism isn't being used. This 323 // happens on low core count machines where we are concerned about blocking 324 // main-thread execution. 325 bool IsOffThreadSourceCompressionEnabled(); 326 327 void AttachFinishedBaselineCompilations(JSContext* cx, 328 AutoLockHelperThreadState& lock); 329 330 } // namespace js 331 332 #endif /* vm_HelperThreads_h */