The goals of these policies are (in descending priority):
In previous versions of BOINC, the core client attempted to maintain at least one result for each attached project, and would do weighted round-robin CPU scheduling among all projects. In some scenarios (any combination of slow computer, lots of projects, and tight deadlines) a computer could miss the deadlines of all its results. The new policies solve this problem as follows:
Wall CPU time is the amount of wall-clock time a process has been runnable at the OS level. The actual CPU time may be less than this, e.g. if the process does a lot of paging, or if other (non-BOINC) processing jobs run at the same time.
BOINC uses wall CPU time as the measure of CPU resource usage. Wall CPU time is more fair than actual CPU time in the case of paging apps. In addition, the measurement of actual CPU time depends on apps to report it correctly, and they may not do this.
The normalized CPU time of a result is an estimate of the wall time it will take to complete, taking into account
The project-normalized CPU time of a result is an estimate of the wall time it will take to complete, taking into account the above factors plus the project's resource share relative to other potentially runnable projects.
The 'work_req' element of a scheduler RPC request is in units of project-normalized CPU time. In deciding how much work to send, the scheduler must take into account the project's resource share fraction, and the host's on-fraction and active-fraction.
For example, suppose a host has 1 GFLOP/sec CPUs, the project's resource share fraction is 0.5, the host's on-fraction is 0.8 and the host's active-fraction is 0.9. Then the expected processing rate per CPU is
(1 GFLOP/sec)*0.5*0.8*0.9 = 0.36 GFLOP/secIf the host requests 1000 project-normalized CPU seconds of work, the scheduler should send it at least 360 GFLOPs of work.
P is potentially runnable if
Long-term debt is used by the work-fetch policy. It is defined for all projects, and adjusted over the set of potentially runnable projects. It is normalized so that average long-term debt, over all project, is zero.
The CPU scheduling and work fetch policies use the results of a simulation of weighted round-robin scheduling applied to the set of nearly runnable results. The simulation takes into account on-fraction and active-fraction. It produces the following outputs:
In the example below, projects A and B have resource shares 2 and 1 respectively. A has results A1 and A2, and B has result B1. The computer has two CPUs. From time 0 to 4 all three results run with equal weighting. At time 4 result A2 finishes. From time 4 to 8, project A gets only a 0.5 share because it has only one result. At time 8, result A1 finishes.
In this case, shortfall(A) is 4, shortfall(B) is 0, and total_shortfall is 2.
The CPU scheduler uses an earliest-deadline-first (EDF) policy for results that are in danger of missing their deadline, and weighted round-robin among other projects if additional CPUs exist. This allows the client to meet deadlines that would otherwise be missed, while honoring resource shares over the long term. The scheduling policy is:
The CPU scheduler runs when a result is completed, when the end of the user-specified scheduling period is reached, when new results become runnable, or when the user performs a UI interaction (e.g. suspending or resuming a project or result).
The CPU scheduler decides what results should run, but it doesn't enforce this decision. This enforcement is done by a separate scheduler enforcement function, which is called by the CPU scheduler at its conclusion. Let X be the set of scheduled results that are not currently running, let Y be the set of running results that are not scheduled, and let T be the time the scheduler last ran. The enforcement policy is as follows:
A project P is overworked if
This condition occurs if P's results run in EDF mode (and in extreme cases, when a project with large negative LTD is detached). The work-fetch policy avoids getting work from overworked projects. This prevents a situation where a project with short deadlines gets more than its share of CPU time.
The work-fetch policy uses the functions
frs(project P)
P's fractional resource share among fetchable projects.
The work-fetch policy function is called every few minutes (or as needed) by the scheduler RPC polling function. It sets the variable P.work_request_size for each project P, which is the number of seconds of work to request if we do a scheduler RPC to P. This is computed as follows:
for each project P if P is suspended, deferred, overworked, or no-new-work P.work_request_size = 0 else P.work_request_size = shortfall(P) if total_shortfall > 0 if P.work_request_size==0 for all P for each project P if P is suspended, deferred, overworked, or no-new-work continue P.work_request_size = 1 if P.work_request_size==0 for all P for each project P if P is suspended, deferred, or no-new-work continue P.work_request_size = 1 if P.work_request_size>0 for some P Normalize P.work_request_size so that they sum to total_shortfall and are proportional to P.resource_share
For non-CPU-intensive projects, P.work_request_size is set to 1 if P has no nearly-runnable result, otherwise 0.
The scheduler RPC mechanism may select a project to contact because of a user request, an outstanding trickle-up message, or a result that is overdue for reporting. If it does so, it will also request work from that project. Otherwise, the RPC mechanism chooses the project P for which
P.work_request_size>0 and P.long_term_debt + shortfall(P) is greatestand requests work from that project. Note: P.work_request_size is in units of normalized CPU time, so the actual work request (which is in units of project-normalized CPU time) is P.work_request_size divided by P's resource share fraction relative to potentially runnable projects.
NOTE: the following has not been implemented, and is independent of the above policies.
The scheduler should avoid sending results whose deadlines are likely to be missed, or which are likely to cause existing results to miss their deadlines. This will be accomplished as follows:
We encourage the use of the following notation for describing scheduling scenarios (times are given in hours):
P(C, D, R)
This describes a project with
P1(1000, 2000, .5) P2(1, 10, .5) NCPUS=4
P1(0.1, 1, .5) P2(1, 24, .25) P3(1, 24, .25) NCPUS = 2 leave_in_memory = false cpu_scheduling_period = 1Typically one CPU will process 6-minute tasks for P1, and the other CPU will alternate between P2 and P3. It's critical that the scheduler run each task of P2 and P3 for the full CPU scheduling period. If we went strictly by debt, we'd end up switching between them every 6 minutes, and both P2 and P3 would have to resume from a checkpoint each time. For some apps (e.g. Einstein@home) resuming from a checking takes several minutes. So we'd end up wasting most of the time on one CPU. "; page_tail(); ?>