added utility to compute the scheduling window. Right now there's only criteria on which this is determined -- fillNextOfferCycle. So, the schedWindow is the max number of tasks, that aren't yet scheduled, whose aggregate resource requirement is as close as possible to the resource available in the next round of resource offers. To be able to make the most use of the next offer cycle, one would need to perform a non-polynomial search of the TaskQueue and as this is computationally expensive, a linear search is performed on the TaskQueue. Retrofitted scheduling policies to also call utilities.schedUtils#schedWindowResizingStrategy#Apply before switching to a new scheduling policy.
This commit is contained in:
parent
6f0f3788b9
commit
3ebd7b0c7e
12 changed files with 115 additions and 15 deletions
63
utilities/schedUtils/schedUtils.go
Normal file
63
utilities/schedUtils/schedUtils.go
Normal file
|
@ -0,0 +1,63 @@
|
|||
package schedUtils
|
||||
|
||||
import (
|
||||
"bitbucket.org/sunybingcloud/elektron/def"
|
||||
"bitbucket.org/sunybingcloud/elektron/utilities"
|
||||
)
|
||||
|
||||
// Criteria for resizing the scheduling window.
|
||||
type SchedulingWindowResizingCriteria string
|
||||
|
||||
var SchedWindowResizingCritToStrategy = map[SchedulingWindowResizingCriteria]schedWindowResizingStrategy{
|
||||
"fillNextOfferCycle": &fillNextOfferCycle{},
|
||||
}
|
||||
|
||||
// Interface for a scheduling window resizing strategy.
|
||||
type schedWindowResizingStrategy interface {
|
||||
// Apply the window resizing strategy and return the news scheduling window size.
|
||||
Apply(func() interface{}) int
|
||||
}
|
||||
|
||||
// Scheduling window resizing strategy that attempts to resize the scheduling window
|
||||
// to include as many tasks as possible so as to make the most use of the next offer cycle.
|
||||
type fillNextOfferCycle struct{}
|
||||
|
||||
func (s *fillNextOfferCycle) Apply(getArgs func() interface{}) int {
|
||||
return s.apply(getArgs().([]def.Task))
|
||||
}
|
||||
|
||||
// Loop over the unscheduled tasks, in submission order, and determine the maximum
|
||||
// number of tasks that can be scheduled in the next offer cycle.
|
||||
// As the offers get smaller and smaller, this approach might lead to an increase in internal fragmentation.
|
||||
//
|
||||
// Note: To be able to make the most use of the next offer cycle, one would need to perform a non-polynomial search
|
||||
// which is computationally expensive.
|
||||
func (s *fillNextOfferCycle) apply(taskQueue []def.Task) int {
|
||||
clusterwideResourceCount := utilities.GetClusterwideResourceAvailability()
|
||||
newSchedWindow := 0
|
||||
filledCPU := 0.0
|
||||
filledRAM := 0.0
|
||||
|
||||
// Can we schedule another task.
|
||||
canSchedule := func(t def.Task) bool {
|
||||
if ((filledCPU + t.CPU) <= clusterwideResourceCount.UnusedCPU) &&
|
||||
((filledRAM + t.RAM) <= clusterwideResourceCount.UnusedRAM) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
for _, task := range taskQueue {
|
||||
for i := *task.Instances; i > 0; i-- {
|
||||
if canSchedule(task) {
|
||||
filledCPU += task.CPU
|
||||
filledRAM += task.RAM
|
||||
newSchedWindow++
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
return newSchedWindow
|
||||
}
|
Reference in a new issue