-
Type: Task
-
Resolution: Fixed
-
Priority: Major - P3
-
Affects Version/s: None
-
Component/s: None
-
Query Execution
-
Fully Compatible
-
156
The way we currently interact with it seems to cost us around 2-3% of query execution time to just check if we should yield or not (the overhead comes from just calling PlanYieldPolicy::shouldYieldOrInterrupt).
Instead we should always use simple time check to minimize the frequency of interaction with YieldPolicy virtualized internals.
The suggested approach is to refactor the YieldPolicy to look like:
class YieldPolicy { virtual void doMaybeYieldOrInterrupt(OperationContext* opCtx, std::function<void()> whileYieldingFn, Ticks* nextYieldCheckInterval)=0; inline bool maybeYieldOrInterrupt(OperationContext* opCtx) { if (MONGO_unlikely(elapsedTicks() >= _nextYieldCheckInterval)) { // here we use opCtx->getServiceContext()->getTickSource() to get elapsed tick yieldPolicy->doMaybeYieldOrInterrupt(..., &_nextYieldCheckInterval) // obtain a new timestamp for check and optionally do the yielding logic } } Ticks* _nextYieldCheckInterval; }
that ideally should result in just few machine instructions being added to the hot code path code path, and then the call code yieldPolicy->doMaybeYieldOrInterrupt should also end up at the end of the method, hopefully out of the way of i-cache.
This would allow for doMaybeYieldOrInterrupt to do whatever pointer chases or switch-cases it needs to figure out if and how to do yielding without worrying about impacting the caller.
But to get that benefit would come at a price of making the time-based check a requirement for all yield policies and moving it to the base class so that it becomes inlinable.
- is related to
-
SERVER-88886 Anna perf tiger tracking ticket
- In Progress