diff --git a/plugins/ets/runtime_options.yaml b/plugins/ets/runtime_options.yaml index 31e907afa868bc0ba6ede4abd694258854876635..5fab82891099e9f8ead946e689e8481174c1d4c1 100644 --- a/plugins/ets/runtime_options.yaml +++ b/plugins/ets/runtime_options.yaml @@ -214,5 +214,5 @@ options: lang: - ets type: uint32_t - default: 2 + default: 3 description: Number of worker threads for the taskmanager. Option is used only for --worker-type=taskmanager diff --git a/runtime/compiler.cpp b/runtime/compiler.cpp index ecc736079e75765d29b5eadb7f62091c5a7d6e03..d937e7f7bf36ca9c06e3ca256214018692ce9fcd 100644 --- a/runtime/compiler.cpp +++ b/runtime/compiler.cpp @@ -773,7 +773,7 @@ bool Compiler::CompileMethod(Method *method, uintptr_t bytecode_offset, bool osr auto status = method->GetCompilationStatus(); for (; (status == Method::WAITING) || (status == Method::COMPILATION); status = method->GetCompilationStatus()) { - if (thread_pool_ == nullptr || !thread_pool_->IsActive()) { + if (jit_thread_joined_) { // JIT thread is destroyed, wait makes no sence return false; } @@ -797,6 +797,7 @@ void Compiler::CompileMethodLocked(const CompilerTask &&ctx) method->ResetHotnessCounter(); if (IsCompilationExpired(ctx)) { + ASSERT(!no_async_jit_); return; } @@ -826,11 +827,52 @@ void Compiler::CompileMethodLocked(const CompilerTask &&ctx) method->AtomicSetCompilationStatus(Method::COMPILATION, Method::COMPILED); } +void Compiler::AddTask(CompilerTask &&ctx, [[maybe_unused]] TaggedValue func) +{ + if (use_task_manager_) { + auto *ctx_ptr = internal_allocator_->New(std::move(ctx)); + auto task_runner = [this, ctx_ptr] { + if (ctx_ptr->GetMethod()->AtomicSetCompilationStatus(Method::WAITING, Method::COMPILATION)) { + CompileMethodLocked(std::move(*ctx_ptr)); + } + internal_allocator_->Delete(ctx_ptr); + { + os::memory::LockHolder lock(jit_worker_finalization_lock_); + --unprocessed_tasks_; + if (jit_thread_joined_ && (unprocessed_tasks_ == 0)) { + jit_tasks_processed_.Signal(); + } + } + }; + auto task = taskmanager::Task::Create(JIT_TASK_PROPERTIES, std::move(task_runner)); + { + os::memory::LockHolder lock(jit_worker_finalization_lock_); + if (!jit_thread_joined_) { + ++unprocessed_tasks_; + jit_task_queue_->AddTask(std::move(task)); + } + } + } else { + thread_pool_->PutTask(std::move(ctx)); + } +} + void Compiler::JoinWorker() { if (thread_pool_ != nullptr) { thread_pool_->Shutdown(true); } + + { + os::memory::LockHolder lock(jit_worker_finalization_lock_); + jit_thread_joined_ = true; + if (use_task_manager_) { + while (unprocessed_tasks_ != 0) { + jit_tasks_processed_.Wait(&jit_worker_finalization_lock_); + } + } + } + #ifdef PANDA_COMPILER_DEBUG_INFO if (!Runtime::GetOptions().IsArkAot() && compiler::OPTIONS.IsCompilerEmitDebugInfo()) { compiler::CleanJitDebugCode(); diff --git a/runtime/compiler.h b/runtime/compiler.h index 8e912d970ad037beebfba73f41b129f5efa128da..001f9d2385ab39086f71056ba90cbb734c697e23 100644 --- a/runtime/compiler.h +++ b/runtime/compiler.h @@ -642,13 +642,20 @@ public: return; } - queue_ = CreateJITTaskQueue(no_async_jit_ ? "simple" : options.GetCompilerQueueType(), - options.GetCompilerQueueMaxLength(), options.GetCompilerTaskLifeSpan(), - options.GetCompilerDeathCounterValue(), options.GetCompilerEpochDuration()); - if (queue_ == nullptr) { - // Because of problems (no memory) in allocator - LOG(ERROR, COMPILER) << "Cannot create a compiler queue"; - no_async_jit_ = true; + use_task_manager_ = Runtime::GetTaskScheduler() != nullptr; + if (use_task_manager_) { + jit_task_queue_ = internal_allocator_->New( + taskmanager::TaskType::JIT, taskmanager::VMType::STATIC_VM, taskmanager::TaskQueue::DEFAULT_PRIORITY); + ASSERT(jit_task_queue_ != nullptr); + } else { + queue_ = CreateJITTaskQueue(no_async_jit_ ? "simple" : options.GetCompilerQueueType(), + options.GetCompilerQueueMaxLength(), options.GetCompilerTaskLifeSpan(), + options.GetCompilerDeathCounterValue(), options.GetCompilerEpochDuration()); + if (queue_ == nullptr) { + // Because of problems (no memory) in allocator + LOG(ERROR, COMPILER) << "Cannot create a compiler queue"; + no_async_jit_ = true; + } } CreateWorker(); if (compiler::OPTIONS.WasSetCompilerDumpJitStatsCsv()) { @@ -673,6 +680,7 @@ public: internal_allocator_->Delete(thread_pool_); thread_pool_ = nullptr; } + jit_thread_joined_ = true; } void JoinWorker() override; @@ -687,15 +695,16 @@ public: queue_->Finalize(); internal_allocator_->Delete(queue_); } + if (jit_task_queue_ != nullptr) { + internal_allocator_->Delete(jit_task_queue_); + jit_task_queue_ = nullptr; + } internal_allocator_->Delete(jit_stats_); } bool CompileMethod(Method *method, uintptr_t bytecode_offset, bool osr, TaggedValue func) override; - virtual void AddTask(CompilerTask &&task, [[maybe_unused]] TaggedValue func) - { - thread_pool_->PutTask(std::move(task)); - } + virtual void AddTask(CompilerTask &&ctx, [[maybe_unused]] TaggedValue func); /// Basic method, which starts compilation. Do not use. void CompileMethodLocked(const CompilerTask &&ctx); @@ -768,10 +777,16 @@ private: void CreateWorker() { - if (thread_pool_ == nullptr) { - thread_pool_ = internal_allocator_->New>( - internal_allocator_, queue_, this, 1, "JIT Thread"); + if (use_task_manager_) { + [[maybe_unused]] taskmanager::TaskQueueId id = Runtime::GetTaskScheduler()->RegisterQueue(jit_task_queue_); + ASSERT(!(id == taskmanager::INVALID_TASKQUEUE_ID)); + } else { + if (thread_pool_ == nullptr) { + thread_pool_ = internal_allocator_->New>( + internal_allocator_, queue_, this, 1, "JIT Thread"); + } } + jit_thread_joined_ = false; } CodeAllocator *code_allocator_; @@ -782,9 +797,17 @@ private: compiler::RuntimeInterface *runtime_iface_; // The lock is used for compiler thread synchronization os::memory::Mutex compilation_lock_; + taskmanager::TaskQueue *jit_task_queue_ {nullptr}; + static constexpr taskmanager::TaskProperties JIT_TASK_PROPERTIES { + taskmanager::TaskType::JIT, taskmanager::VMType::STATIC_VM, taskmanager::TaskExecutionMode::BACKGROUND}; + os::memory::Mutex jit_worker_finalization_lock_; + size_t unprocessed_tasks_ {0}; + os::memory::ConditionVariable jit_tasks_processed_; // This queue is used only in ThreadPool. Do not use it from this class. CompilerQueueInterface *queue_ {nullptr}; bool no_async_jit_; + bool use_task_manager_ {false}; + bool jit_thread_joined_ {true}; ThreadPool *thread_pool_; compiler::JITStats *jit_stats_ {nullptr}; NO_COPY_SEMANTIC(Compiler); diff --git a/runtime/mem/gc/gc.cpp b/runtime/mem/gc/gc.cpp index 798a890f1d0655685aaf7df4227fd5c473f92cb7..a29792e4a6f5bd6e1ab8dade98feaea370b37e2b 100644 --- a/runtime/mem/gc/gc.cpp +++ b/runtime/mem/gc/gc.cpp @@ -488,7 +488,7 @@ void GC::JoinWorker(bool continue_run_gc) // where threads observe all modifications in the same order gc_running_.store(false, std::memory_order_seq_cst); // TODO(ipetrov, #13816): remove unnecessary second check - if (!gc_settings_.RunGCInPlace() && gc_settings_.UseThreadPoolForGCWorkers()) { + if (!gc_settings_.RunGCInPlace() && gc_settings_.UseThreadPoolForGCWorkers() && continue_run_gc) { ASSERT(worker_ != nullptr); } if (worker_ != nullptr && !gc_settings_.RunGCInPlace()) {