2018-10-06 20:03:14 -07:00
// Copyright (C) 2018 spdf
//
// This file is part of Elektron.
//
// Elektron is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Elektron is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Elektron. If not, see <http://www.gnu.org/licenses/>.
//
2017-09-26 13:17:47 -04:00
package schedulers
2018-01-19 21:20:43 +00:00
import (
2018-02-26 01:59:09 +00:00
"encoding/json"
"os"
2018-04-17 20:09:35 +00:00
"sort"
2018-09-30 18:23:38 -07:00
sched "github.com/mesos/mesos-go/api/v0/scheduler"
"github.com/pkg/errors"
"gitlab.com/spdf/elektron/utilities"
2018-01-19 21:20:43 +00:00
)
2017-09-26 13:17:47 -04:00
// Names of different scheduling policies.
const (
2018-01-31 19:00:31 -05:00
ff = "first-fit"
bp = "bin-packing"
mgm = "max-greedymins"
mm = "max-min"
2017-09-26 13:17:47 -04:00
)
2018-01-19 21:20:43 +00:00
// Scheduling policy factory
var SchedPolicies map [ string ] SchedPolicyState = map [ string ] SchedPolicyState {
2018-01-31 19:00:31 -05:00
ff : & FirstFit { } ,
bp : & BinPackSortedWatts { } ,
mgm : & MaxGreedyMins { } ,
mm : & MaxMin { } ,
2017-09-26 13:17:47 -04:00
}
2018-04-17 20:09:35 +00:00
// Scheduling policies to choose when switching
var schedPoliciesToSwitch map [ int ] struct {
spName string
sp SchedPolicyState
} = make ( map [ int ] struct {
spName string
sp SchedPolicyState
} )
2018-02-26 01:59:09 +00:00
// Initialize scheduling policy characteristics using the provided config file.
func InitSchedPolicyCharacteristics ( schedPoliciesConfigFilename string ) error {
var schedPolConfig map [ string ] baseSchedPolicyState
if file , err := os . Open ( schedPoliciesConfigFilename ) ; err != nil {
return errors . Wrap ( err , "Error opening file" )
} else {
err := json . NewDecoder ( file ) . Decode ( & schedPolConfig )
if err != nil {
return errors . Wrap ( err , "Error unmarshalling" )
}
// Initializing.
// TODO: Be able to unmarshal a schedPolConfig JSON into any number of scheduling policies.
for schedPolName , schedPolState := range SchedPolicies {
switch t := schedPolState . ( type ) {
case * FirstFit :
t . TaskDistribution = schedPolConfig [ schedPolName ] . TaskDistribution
t . VarianceCpuSharePerTask = schedPolConfig [ schedPolName ] . VarianceCpuSharePerTask
case * BinPackSortedWatts :
t . TaskDistribution = schedPolConfig [ schedPolName ] . TaskDistribution
t . VarianceCpuSharePerTask = schedPolConfig [ schedPolName ] . VarianceCpuSharePerTask
case * MaxMin :
t . TaskDistribution = schedPolConfig [ schedPolName ] . TaskDistribution
t . VarianceCpuSharePerTask = schedPolConfig [ schedPolName ] . VarianceCpuSharePerTask
case * MaxGreedyMins :
t . TaskDistribution = schedPolConfig [ schedPolName ] . TaskDistribution
t . VarianceCpuSharePerTask = schedPolConfig [ schedPolName ] . VarianceCpuSharePerTask
}
}
2018-04-17 20:09:35 +00:00
// Initialize schedPoliciesToSwitch to allow binary searching for scheduling policy switching.
spInformation := map [ string ] float64 { }
for spName , sp := range SchedPolicies {
spInformation [ spName ] = sp . GetInfo ( ) . taskDist
}
spInformationPairList := utilities . GetPairList ( spInformation )
// Sorting spInformationPairList in non-increasing order of taskDist.
sort . SliceStable ( spInformationPairList , func ( i , j int ) bool {
return spInformationPairList [ i ] . Value < spInformationPairList [ j ] . Value
} )
// Initializing scheduling policies that are setup for switching.
index := 0
for _ , spInformationPair := range spInformationPairList {
if spInformationPair . Value != 0 {
schedPoliciesToSwitch [ index ] = struct {
spName string
sp SchedPolicyState
} {
spName : spInformationPair . Key ,
sp : SchedPolicies [ spInformationPair . Key ] ,
}
index ++
}
}
2018-04-17 23:44:36 +00:00
// Initializing the next and previous policy based on the the round-robin ordering.
// The next policy for policy at N would correspond to the value at index N+1 in schedPoliciesToSwitch.
for curPolicyIndex := 0 ; curPolicyIndex < len ( schedPoliciesToSwitch ) ; curPolicyIndex ++ {
info := struct {
nextPolicyName string
prevPolicyName string
} { }
if curPolicyIndex == 0 {
info . prevPolicyName = schedPoliciesToSwitch [ len ( schedPoliciesToSwitch ) - 1 ] . spName
} else {
info . prevPolicyName = schedPoliciesToSwitch [ curPolicyIndex - 1 ] . spName
}
info . nextPolicyName = schedPoliciesToSwitch [ ( curPolicyIndex + 1 ) % len ( schedPoliciesToSwitch ) ] . spName
schedPoliciesToSwitch [ curPolicyIndex ] . sp . UpdateLinks ( info )
}
2018-02-26 01:59:09 +00:00
}
return nil
}
// build the scheduler with the options being applied
2018-10-04 19:24:16 -04:00
func buildScheduler ( s sched . Scheduler , opts ... SchedulerOptions ) {
2017-09-26 13:17:47 -04:00
s . ( ElectronScheduler ) . init ( opts ... )
}
2018-10-04 19:24:16 -04:00
func SchedFactory ( opts ... SchedulerOptions ) sched . Scheduler {
2018-01-30 14:12:37 -05:00
s := & BaseScheduler { }
2018-01-19 21:20:43 +00:00
buildScheduler ( s , opts ... )
2017-09-26 13:17:47 -04:00
return s
}