@philips @uwedeportivo On reflection, it may be necessary for the scheduler to adopt the cgroups model of cpu allocation rather than trying to abstract it away. The current MachineSpec/JobSpec abstraction is incompatible with cgroups (assuming I understand cgroups correctly) in that candidates() can decide a machine can handle a job, when that job's cpu resources can't really be allocated.

Here's an example. Say I have a cluster consisting of a single dual-core machine, and three classes of jobs: quarter-core, half-core and full-core. It's up to my code to actually impose resource constraints on jobs, and most of the time I'll do it with cgroups. I decide ahead of time that I want 1024 cpu shares per core (it's arbitrary, search for "cpu.shares" [here](https://www.kernel.org/doc/Documentation/scheduler/sched-design-CFS.txt)). I get job requests in the following order:

0. quarter-core. I stick this on core 0 (using [cpuset](https://www.kernel.org/doc/Documentation/cgroups/cpusets.txt)) and give it 1024/4 shares.
1. quarter-core. I stick this on core 1, figuring there's no need to create unnecessary contention, and give it 1024/4 shares.
2. half-core. I stick this on core 0, and give it 1024/2 shares.
3. full-core. At this point there are a total of 1024 shares=one full cpu available on my machine, so candidates() will say that it can handle the job; but there's no way for me to place it. I need to give it access to both cpus 0 and 1, clearly; but if I give it more than 1024/4 shares then there are more than 1024 shares allocated on core 0 and it dilutes the allocations to jobs 0 and 2; but if I only give it 1024/4 shares then it has a total of half a core, which is less than it's supposed to get.

Arguably it wouldn't be a good idea to give job 3 1/4 of cpu 0 and 3/4 of cpu 1 anyway, since most multithreaded libraries assume that all cpus are about equally fast.


I can think of three ways to fix this:
- Only allow JobSpecs to request integer cores.
- Change JobSpecs to request number of cores and share per core, rather than just total share.
- Change MachineSpec to be explicit about the load on each core, and change candidates() to check whether a job can be placed as an equal share of n cores. In this case, fleet would need to somehow communicate the recommended cgroups parameters to implement the resource constraint, because the allocation needs to be implemented the same way as candidates() does it to avoid getting out of sync. It might also be a good idea to allow JobSpecs to request placement on a single core, so that single-threaded jobs get the resources they're expecting.