| 328 | } // namespace |
| 329 | |
| 330 | void VirtualMachine::ScheduleLoop(const std::function<void()>& Initializer) { |
| 331 | SyncVmModeGuard guard(SyncVmMode::kEnable); |
| 332 | Initializer(); |
| 333 | MultiThreadScheduleCtx schedule_ctx{}; |
| 334 | while (pending_notifier_.WaitAndClearNotifiedCnt() == kNotifierStatusSuccess) { |
| 335 | OF_PROFILER_RANGE_GUARD("VirtualMachine::ScheduleLoop"); |
| 336 | auto start = std::chrono::steady_clock::now(); |
| 337 | static constexpr int kWorkingMicroseconds = 1000; |
| 338 | // Every time this thread wakes up, engine_ is scheduled for about `kWorkingMicroseconds`. |
| 339 | // The cost of os thread switching is about 5-10 microseconds. Doing more scheduling in |
| 340 | // a single waiting up can reach higher performance. |
| 341 | do { |
| 342 | // Use SchedulerThreadUnsafeEmpty to avoid acquiring mutex lock. |
| 343 | // It's safe to use SchedulerThreadUnsafeEmpty here. pending_notifier_.notified_cnt_ will be |
| 344 | // greater than zero when inconsistency between |
| 345 | // engine_->pending_instruction_list.list_head_.list_head_.container_ and |
| 346 | // engine_->pending_instruction_list.list_head_.list_head_.size_ occured. hence the pending |
| 347 | // instructions |
| 348 | // will get handled in the next iteration. |
| 349 | // VirtualMachine::Receive may be less effiencient if the thread safe version |
| 350 | // `engine_->SchedulerEmpty()` |
| 351 | // used |
| 352 | // here, because VirtualMachine::ScheduleLoop is more likely to get the mutex lock. |
| 353 | do { |
| 354 | const size_t total_inserted = engine_->total_inserted_instruction_cnt(); |
| 355 | const size_t total_erased = engine_->total_erased_instruction_cnt(); |
| 356 | engine_->Schedule(schedule_ctx); |
| 357 | if (ThreadLocalEnvBool<ONEFLOW_VM_ENABLE_SCHEDULE_YIELD>() |
| 358 | && total_inserted == engine_->total_inserted_instruction_cnt() |
| 359 | && total_erased == engine_->total_erased_instruction_cnt()) { // nothing handled. |
| 360 | std::this_thread::yield(); |
| 361 | } |
| 362 | } while (!engine_->SchedulerThreadUnsafeEmpty()); |
| 363 | } while (MicrosecondsFrom(start) < kWorkingMicroseconds); |
| 364 | } |
| 365 | ScheduleUntilVMEmpty(engine_.Mutable(), schedule_ctx); |
| 366 | CHECK_JUST(CloseWorkerThreads()); |
| 367 | scheduler_stopped_ = true; |
| 368 | } |
| 369 | |
| 370 | intrusive::shared_ptr<vm::Dependence> VirtualMachine::FindOrCreateScheduleDependence( |
| 371 | Symbol<Stream> stream) { |
nothing calls this directly
no test coverage detected