The Fennel execution stream resource governor is responsible for globally allocating resources across all execution stream graphs running within a single Fennel instantiation. As background, please read the ExecStreamDesign first.
The resource governor decides how much of each resource to allocate to each stream graph, as well as how much to allocate to each execution stream within the graph. Criteria for deciding how to allocate resources include:
Resource knob settings are stored in an ExecStreamResourceKnobs structure. Currently, two knobs are supported:
When the resource governor is initialized, it is provided with default settings for these knobs, as well as the current resource availability. The resource governor will utilize this information in its allocation policy. The knobs can be dynamically modified at runtime.
As described in ExecStreamHowTo, if a stream requires heavyweight resources, it must override the ExecStream::getResourceRequirements method. There are two versions of this method. The first specifies two parameters -- minimum and optimum resource requirements. Both are represented using ExecStreamResourceQuantity structures that the stream's getResourceRequirements method will set and pass back to the caller. The structure allows the number of threads and cache pages to be specified. The minimum requirement setting indicates the minimum resources the stream needs to run to completion without errors, whereas the optimum represents the amount the stream needs to run efficiently. For example, if a stream implements sorting, an efficient execution would do a full in-memory sort. But you do not necessarily need to do a full in-memory sort for the sort to run to completion if the stream supports writing temporary results to disk. Therefore, the minimum setting, in this case, would be some lower value.
In some cases, it may not be possible for the stream to specify an exact number for its optimum requirement. For example, the stream may have access to statistics that will allow it to estimate a value for its optimum requirement. However, the estimate may not be completely trustworthy if it is based on out-dated statistics. Or even worse, if no statistics are available, the stream may not even be able to come up with any estimate at all.
In these cases, the stream should use the second version of ExecStream::getResourceRequirements, which has a third parameter. That third parameter receives an ExecStreamResourceSettingType. An ExecStreamResourceSettingType is an enumerated type that has one of the following values:
In the case of an estimate setting, the resource governor will try to allocate extra resources above the optimum setting. In the case of an unbounded setting, the resource governor will allocate as much as possible to the stream. In both cases, the amount to be allocated is subject to the amount available to the overall stream graph and the amount required by other streams in the graph. Greater weight will be given to the streams with unbounded settings. Therefore, memory intensive streams that cannot set an optimum requirement should use the unbounded setting. Less memory intensive streams that cannot set an optimum should use the estimate setting with a reasonable guess for the optimum setting.
Using the resource requirement settings provided by each stream, the resource governor can decide how much to allocate to each stream. Once it has decided, it calls ExecStream::setResourceAllocation to let each stream know much it has been allocated.
The ExecStreamGovernor class supports the following public methods:
Both ExecStreamGovernor::requestResources and ExecStreamGovernor::returnResources are polymorphic. Therefore, different implementations of resource governors can be built, supporting different allocation policies.
A reference implementation of the ExecStreamGovernor interface is provided by the SimpleExecStreamGovernor class. As its name implies, it is a basic implementation. It has the following characteristics:
Using the total number of cache pages available, the resource governor will set aside a reserve based on ExecStreamResourceKnobs::cacheReservePercentage. The remainder will be divided by ExecStreamResourceKnobs::expectedConcurrentStatements to yield ExecStreamGovernor::perGraphAllocation. This computed value serves as a reference amount in determining how many cache pages to assign to each graph. If during the course of execution, fewer pages than ExecStreamGovernor::perGraphAllocation are available, then the total remaining number of cache pages becomes the reference amount for allocation.
When SimpleExecStreamGovernor::requestResources is called, the resource governor will total both the minimum and optimum requirements of each stream in the graph. In the case where the optimum setting is EXEC_RESOURCE_UNBOUNDED, the resource governor sets the optimum requirement for the stream to the minimum requirement plus the reference amount. As you will see further below, this ensures that priority is given to these streams. These numbers are used by the SimpleExecStreamGovernor as follows:
number of pages to allocate to stream X = minimum for X + (reference amount - total minimum) * (sqrt((optimum for X) - (minimum for X)) / sum of the sqrt of the differences between the optimum and minimum settings for each stream
Note that it is not possible to encounter a stream with an EXEC_RESOURCE_UNBOUNDED setting in this case because of how the resource governor has assigned an optimum requirement to those streams.
The following diagram summarizes the policy. The topmost horizontal line represents the range of possible reference amounts, relative to the total minimum and total optimum for a stream graph. Depending on where the reference amount falls, either one of the five cases applies, corresponding to the descriptions above.
More sophisticated resource governors could support one or more of the following:
Definition at line 330 of file ResourceGovernorDesign.cpp.