1f3411616SLang Hames //===------------ TaskDispatch.cpp - ORC task dispatch utils --------------===// 2f3411616SLang Hames // 3f3411616SLang Hames // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4f3411616SLang Hames // See https://llvm.org/LICENSE.txt for license information. 5f3411616SLang Hames // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6f3411616SLang Hames // 7f3411616SLang Hames //===----------------------------------------------------------------------===// 8f3411616SLang Hames 9f3411616SLang Hames #include "llvm/ExecutionEngine/Orc/TaskDispatch.h" 1089e6a288SDaniil Fukalov #include "llvm/Config/llvm-config.h" // for LLVM_ENABLE_THREADS 117da63426SLang Hames #include "llvm/ExecutionEngine/Orc/Core.h" 12f3411616SLang Hames 13f3411616SLang Hames namespace llvm { 14f3411616SLang Hames namespace orc { 15f3411616SLang Hames 16f3411616SLang Hames char Task::ID = 0; 17f3411616SLang Hames char GenericNamedTask::ID = 0; 18*2d10b7b7SLang Hames char IdleTask::ID = 0; 19*2d10b7b7SLang Hames 20f3411616SLang Hames const char *GenericNamedTask::DefaultDescription = "Generic Task"; 21f3411616SLang Hames 22f3411616SLang Hames void Task::anchor() {} 23*2d10b7b7SLang Hames void IdleTask::anchor() {} 24*2d10b7b7SLang Hames 253a3cb929SKazu Hirata TaskDispatcher::~TaskDispatcher() = default; 26f3411616SLang Hames 27f3411616SLang Hames void InPlaceTaskDispatcher::dispatch(std::unique_ptr<Task> T) { T->run(); } 28f3411616SLang Hames 29f3411616SLang Hames void InPlaceTaskDispatcher::shutdown() {} 30f3411616SLang Hames 31f3411616SLang Hames #if LLVM_ENABLE_THREADS 32f3411616SLang Hames void DynamicThreadPoolTaskDispatcher::dispatch(std::unique_ptr<Task> T) { 33*2d10b7b7SLang Hames 34*2d10b7b7SLang Hames enum { Normal, Materialization, Idle } TaskKind; 35*2d10b7b7SLang Hames 36*2d10b7b7SLang Hames if (isa<MaterializationTask>(*T)) 37*2d10b7b7SLang Hames TaskKind = Materialization; 38*2d10b7b7SLang Hames else if (isa<IdleTask>(*T)) 39*2d10b7b7SLang Hames TaskKind = Idle; 40*2d10b7b7SLang Hames else 41*2d10b7b7SLang Hames TaskKind = Normal; 427da63426SLang Hames 43f3411616SLang Hames { 44f3411616SLang Hames std::lock_guard<std::mutex> Lock(DispatchMutex); 457da63426SLang Hames 4683128762SLang Hames // Reject new tasks if they're dispatched after a call to shutdown. 4783128762SLang Hames if (Shutdown) 4883128762SLang Hames return; 4983128762SLang Hames 50*2d10b7b7SLang Hames if (TaskKind == Materialization) { 517da63426SLang Hames 527da63426SLang Hames // If this is a materialization task and there are too many running 537da63426SLang Hames // already then queue this one up and return early. 54*2d10b7b7SLang Hames if (!canRunMaterializationTaskNow()) 55*2d10b7b7SLang Hames return MaterializationTaskQueue.push_back(std::move(T)); 567da63426SLang Hames 577da63426SLang Hames // Otherwise record that we have a materialization task running. 587da63426SLang Hames ++NumMaterializationThreads; 59*2d10b7b7SLang Hames } else if (TaskKind == Idle) { 60*2d10b7b7SLang Hames if (!canRunIdleTaskNow()) 61*2d10b7b7SLang Hames return IdleTaskQueue.push_back(std::move(T)); 627da63426SLang Hames } 637da63426SLang Hames 64f3411616SLang Hames ++Outstanding; 65f3411616SLang Hames } 66f3411616SLang Hames 67*2d10b7b7SLang Hames std::thread([this, T = std::move(T), TaskKind]() mutable { 687da63426SLang Hames while (true) { 697da63426SLang Hames 707da63426SLang Hames // Run the task. 71f3411616SLang Hames T->run(); 727da63426SLang Hames 7383128762SLang Hames // Reset the task to free any resources. We need this to happen *before* 7483128762SLang Hames // we notify anyone (via Outstanding) that this thread is done to ensure 7583128762SLang Hames // that we don't proceed with JIT shutdown while still holding resources. 7683128762SLang Hames // (E.g. this was causing "Dangling SymbolStringPtr" assertions). 7783128762SLang Hames T.reset(); 7883128762SLang Hames 7983128762SLang Hames // Check the work queue state and either proceed with the next task or 8083128762SLang Hames // end this thread. 81f3411616SLang Hames std::lock_guard<std::mutex> Lock(DispatchMutex); 82*2d10b7b7SLang Hames 83*2d10b7b7SLang Hames if (TaskKind == Materialization) 84*2d10b7b7SLang Hames --NumMaterializationThreads; 85*2d10b7b7SLang Hames --Outstanding; 86*2d10b7b7SLang Hames 87*2d10b7b7SLang Hames if (!MaterializationTaskQueue.empty() && canRunMaterializationTaskNow()) { 887da63426SLang Hames // If there are any materialization tasks running then steal that work. 897da63426SLang Hames T = std::move(MaterializationTaskQueue.front()); 907da63426SLang Hames MaterializationTaskQueue.pop_front(); 91*2d10b7b7SLang Hames TaskKind = Materialization; 927da63426SLang Hames ++NumMaterializationThreads; 93*2d10b7b7SLang Hames ++Outstanding; 94*2d10b7b7SLang Hames } else if (!IdleTaskQueue.empty() && canRunIdleTaskNow()) { 95*2d10b7b7SLang Hames T = std::move(IdleTaskQueue.front()); 96*2d10b7b7SLang Hames IdleTaskQueue.pop_front(); 97*2d10b7b7SLang Hames TaskKind = Idle; 98*2d10b7b7SLang Hames ++Outstanding; 997da63426SLang Hames } else { 1002b3aff8fSLang Hames if (Outstanding == 0) 101f3411616SLang Hames OutstandingCV.notify_all(); 1027da63426SLang Hames return; 1037da63426SLang Hames } 1047da63426SLang Hames } 105f3411616SLang Hames }).detach(); 106f3411616SLang Hames } 107f3411616SLang Hames 108f3411616SLang Hames void DynamicThreadPoolTaskDispatcher::shutdown() { 109f3411616SLang Hames std::unique_lock<std::mutex> Lock(DispatchMutex); 11083128762SLang Hames Shutdown = true; 111f3411616SLang Hames OutstandingCV.wait(Lock, [this]() { return Outstanding == 0; }); 112f3411616SLang Hames } 113*2d10b7b7SLang Hames 114*2d10b7b7SLang Hames bool DynamicThreadPoolTaskDispatcher::canRunMaterializationTaskNow() { 115*2d10b7b7SLang Hames return !MaxMaterializationThreads || 116*2d10b7b7SLang Hames (NumMaterializationThreads < *MaxMaterializationThreads); 117*2d10b7b7SLang Hames } 118*2d10b7b7SLang Hames 119*2d10b7b7SLang Hames bool DynamicThreadPoolTaskDispatcher::canRunIdleTaskNow() { 120*2d10b7b7SLang Hames return !MaxMaterializationThreads || 121*2d10b7b7SLang Hames (Outstanding < *MaxMaterializationThreads); 122*2d10b7b7SLang Hames } 123*2d10b7b7SLang Hames 124f3411616SLang Hames #endif 125f3411616SLang Hames 126f3411616SLang Hames } // namespace orc 127f3411616SLang Hames } // namespace llvm 128