2020-04-12 03:14:53 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
log "github.com/sirupsen/logrus"
|
|
|
|
"sync"
|
2020-04-12 17:30:25 +00:00
|
|
|
"strings"
|
2020-05-02 12:55:46 +00:00
|
|
|
"io/ioutil"
|
|
|
|
"strconv"
|
|
|
|
"encoding/json"
|
2020-05-03 07:19:21 +00:00
|
|
|
"time"
|
2020-04-12 03:14:53 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type Optimizer struct {
|
|
|
|
scheduler Scheduler
|
|
|
|
killedFlag bool
|
2020-04-12 17:30:25 +00:00
|
|
|
|
2020-04-30 07:50:05 +00:00
|
|
|
predicts map[string]*OptimizerJobExecutionTime
|
2020-04-30 05:08:08 +00:00
|
|
|
|
2020-04-30 08:45:43 +00:00
|
|
|
jobUtilsGPU map[string]*OptimizerUtilGPU
|
2020-04-30 09:52:52 +00:00
|
|
|
|
2020-05-01 06:54:29 +00:00
|
|
|
cache map[string]*OptimizerJobExecutionTime
|
2020-04-12 03:14:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
var optimizerInstance *Optimizer
|
|
|
|
var OptimizerInstanceLock sync.Mutex
|
|
|
|
|
|
|
|
func InstanceOfOptimizer() *Optimizer {
|
|
|
|
defer OptimizerInstanceLock.Unlock()
|
|
|
|
OptimizerInstanceLock.Lock()
|
|
|
|
|
|
|
|
if optimizerInstance == nil {
|
|
|
|
optimizerInstance = &Optimizer{}
|
2020-04-30 07:50:05 +00:00
|
|
|
optimizerInstance.predicts = map[string]*OptimizerJobExecutionTime{}
|
2020-04-30 08:45:43 +00:00
|
|
|
optimizerInstance.jobUtilsGPU = map[string]*OptimizerUtilGPU{}
|
2020-05-01 06:54:29 +00:00
|
|
|
optimizerInstance.cache = map[string]*OptimizerJobExecutionTime{}
|
2020-04-12 03:14:53 +00:00
|
|
|
}
|
|
|
|
return optimizerInstance
|
|
|
|
}
|
|
|
|
|
2020-05-24 13:07:02 +00:00
|
|
|
func (optimizer *Optimizer) init(conf Configuration) {
|
|
|
|
log.Info("optimizer started")
|
|
|
|
}
|
|
|
|
|
2020-04-30 15:06:12 +00:00
|
|
|
func (optimizer *Optimizer) feed(job string, utils []UtilGPUTimeSeries) {
|
2020-04-12 03:14:53 +00:00
|
|
|
log.Info("optimizer feed")
|
2020-05-05 07:44:48 +00:00
|
|
|
//log.Info(job, utils)
|
2020-04-12 17:30:25 +00:00
|
|
|
|
2020-04-30 05:13:38 +00:00
|
|
|
if len(utils) == 0 {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-04-12 17:30:25 +00:00
|
|
|
go func() {
|
|
|
|
str := strings.Split(job, "-")
|
|
|
|
if len(str) == 2 {
|
2020-04-30 06:50:21 +00:00
|
|
|
jobName := str[0]
|
2020-04-30 05:08:08 +00:00
|
|
|
|
|
|
|
sum := 0
|
|
|
|
for i := 0; i < len(utils); i++ {
|
2020-04-30 15:06:12 +00:00
|
|
|
sum += utils[i].Util
|
2020-04-30 05:08:08 +00:00
|
|
|
}
|
2020-04-30 09:11:16 +00:00
|
|
|
sum /= len(utils)
|
|
|
|
if _, ok := optimizer.jobUtilsGPU[jobName]; !ok {
|
|
|
|
optimizer.jobUtilsGPU[jobName] = &OptimizerUtilGPU{}
|
2020-04-30 05:08:08 +00:00
|
|
|
}
|
2020-04-30 09:11:16 +00:00
|
|
|
t := optimizer.jobUtilsGPU[jobName]
|
|
|
|
t.Util = (t.Version*t.Util + sum) / (t.Version + 1)
|
|
|
|
t.Version++
|
2020-04-30 05:08:08 +00:00
|
|
|
|
2020-04-30 15:06:12 +00:00
|
|
|
preTime := 0
|
2020-04-12 17:30:25 +00:00
|
|
|
for i := 0; i < len(utils); i++ {
|
2020-04-30 15:06:12 +00:00
|
|
|
if utils[i].Util > 15 {
|
|
|
|
preTime = utils[i].Time - utils[0].Time
|
2020-04-12 17:30:25 +00:00
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-30 15:06:12 +00:00
|
|
|
postTime := 0
|
2020-04-30 05:08:08 +00:00
|
|
|
for i := len(utils) - 1; i >= 0; i-- {
|
2020-04-30 15:06:12 +00:00
|
|
|
if utils[i].Util > 15 {
|
|
|
|
postTime = utils[len(utils)-1].Time - utils[i].Time
|
2020-04-12 17:30:25 +00:00
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-30 07:50:05 +00:00
|
|
|
if _, ok := optimizer.predicts[jobName]; !ok {
|
|
|
|
optimizer.predicts[jobName] = &OptimizerJobExecutionTime{}
|
2020-04-12 17:30:25 +00:00
|
|
|
}
|
2020-04-30 15:06:12 +00:00
|
|
|
totalTime := utils[len(utils)-1].Time - utils[0].Time
|
2020-04-30 14:19:24 +00:00
|
|
|
|
2020-04-30 07:50:05 +00:00
|
|
|
predict := optimizer.predicts[jobName]
|
2020-05-01 06:12:28 +00:00
|
|
|
if predict.Version == 0 {
|
|
|
|
predict.Pre = preTime
|
|
|
|
predict.Post = postTime
|
|
|
|
predict.Total = totalTime
|
|
|
|
predict.Main = predict.Total - predict.Pre - predict.Post
|
|
|
|
if predict.Main < 0 {
|
|
|
|
predict.Main = 0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
predict.Pre = (predict.Pre*95 + preTime*5) / 100
|
|
|
|
predict.Post = (predict.Post*95 + postTime*5) / 100
|
|
|
|
predict.Total = (predict.Total*95 + totalTime*5) / 100
|
2020-04-30 05:08:08 +00:00
|
|
|
predict.Main = predict.Total - predict.Pre - predict.Post
|
2020-04-30 08:45:43 +00:00
|
|
|
if predict.Main < 0 {
|
|
|
|
predict.Main = 0
|
|
|
|
}
|
2020-04-12 17:30:25 +00:00
|
|
|
predict.Version++
|
2020-05-02 12:55:46 +00:00
|
|
|
|
|
|
|
optimizer.feedData(jobName, predict.Version, 0, 0, 0, predict.Total)
|
|
|
|
if predict.Version%10 == 0 && predict.Version > 30 {
|
|
|
|
optimizer.train(jobName)
|
|
|
|
}
|
2020-04-12 17:30:25 +00:00
|
|
|
}
|
|
|
|
}()
|
2020-04-12 03:14:53 +00:00
|
|
|
}
|
2020-04-30 05:08:08 +00:00
|
|
|
|
2020-04-30 06:04:40 +00:00
|
|
|
func (optimizer *Optimizer) predictUtilGPU(job string) (int, bool) {
|
2020-04-30 07:11:06 +00:00
|
|
|
str := strings.Split(job, "-")
|
|
|
|
if len(str) == 2 {
|
|
|
|
jobName := str[0]
|
2020-04-30 08:45:43 +00:00
|
|
|
if _, ok := optimizer.jobUtilsGPU[jobName]; ok {
|
|
|
|
return optimizer.jobUtilsGPU[jobName].Util, optimizer.jobUtilsGPU[jobName].Version >= 5
|
2020-04-30 07:11:06 +00:00
|
|
|
}
|
2020-04-30 05:08:08 +00:00
|
|
|
}
|
2020-04-30 07:11:06 +00:00
|
|
|
return 100, false
|
2020-04-30 05:08:08 +00:00
|
|
|
}
|
|
|
|
|
2020-04-30 07:50:05 +00:00
|
|
|
func (optimizer *Optimizer) predictTime(job string) (*OptimizerJobExecutionTime, bool) {
|
2020-04-30 07:11:06 +00:00
|
|
|
str := strings.Split(job, "-")
|
|
|
|
if len(str) == 2 {
|
|
|
|
jobName := str[0]
|
2020-05-03 07:19:21 +00:00
|
|
|
if est, ok := optimizer.cache[jobName]; ok && est.Version > (int)(time.Now().Unix())-300 {
|
2020-05-02 12:55:46 +00:00
|
|
|
return est, true
|
|
|
|
}
|
|
|
|
if est, ok := optimizer.predicts[jobName]; ok {
|
|
|
|
if est.Version > 40 {
|
|
|
|
if est2, ok := optimizer.predict(jobName, est.Version); ok {
|
|
|
|
est2.Pre = est.Pre * est2.Total / est.Total
|
|
|
|
est2.Main = est.Main * est2.Total / est.Total
|
|
|
|
est2.Post = est.Post * est2.Total / est.Total
|
2020-05-03 07:19:21 +00:00
|
|
|
est2.Version = (int)(time.Now().Unix())
|
2020-05-02 12:55:46 +00:00
|
|
|
optimizer.cache[jobName] = &est2
|
|
|
|
return &est2, true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return est, est.Version >= 5
|
2020-04-30 07:11:06 +00:00
|
|
|
}
|
2020-04-30 05:08:08 +00:00
|
|
|
}
|
2020-04-30 07:50:05 +00:00
|
|
|
return &OptimizerJobExecutionTime{}, false
|
2020-04-30 05:08:08 +00:00
|
|
|
}
|
2020-04-30 08:11:34 +00:00
|
|
|
|
|
|
|
func (optimizer *Optimizer) getAllPredicts() map[string]*OptimizerJobExecutionTime {
|
|
|
|
return optimizer.predicts
|
|
|
|
}
|
|
|
|
|
2020-04-30 08:45:43 +00:00
|
|
|
func (optimizer *Optimizer) getAllGPUUtils() map[string]*OptimizerUtilGPU {
|
2020-04-30 08:11:34 +00:00
|
|
|
return optimizer.jobUtilsGPU
|
|
|
|
}
|
2020-05-02 12:55:46 +00:00
|
|
|
|
|
|
|
func (optimizer *Optimizer) feedData(job string, seq int, pre int, main int, post int, total int) {
|
|
|
|
spider := Spider{}
|
|
|
|
spider.Method = "GET"
|
|
|
|
params := "job=" + job + "&seq=" + strconv.Itoa(seq) + "&value=" + strconv.Itoa(total)
|
|
|
|
spider.URL = "http://yao-optimizer:8080/feed?" + params
|
|
|
|
|
|
|
|
err := spider.do()
|
|
|
|
if err != nil {
|
2020-05-05 07:44:48 +00:00
|
|
|
log.Warn(err)
|
2020-05-02 12:55:46 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
resp := spider.getResponse()
|
|
|
|
if _, err := ioutil.ReadAll(resp.Body); err != nil {
|
|
|
|
log.Warn(err)
|
|
|
|
}
|
|
|
|
resp.Body.Close()
|
|
|
|
if err != nil {
|
2020-05-05 07:44:48 +00:00
|
|
|
log.Warn(err)
|
2020-05-02 12:55:46 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (optimizer *Optimizer) train(job string) {
|
|
|
|
spider := Spider{}
|
|
|
|
spider.Method = "GET"
|
|
|
|
params := "job=" + job
|
|
|
|
spider.URL = "http://yao-optimizer:8080/train?" + params
|
|
|
|
|
|
|
|
err := spider.do()
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
resp := spider.getResponse()
|
|
|
|
if _, err := ioutil.ReadAll(resp.Body); err != nil {
|
|
|
|
log.Warn(err)
|
|
|
|
}
|
|
|
|
resp.Body.Close()
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (optimizer *Optimizer) predict(job string, seq int) (OptimizerJobExecutionTime, bool) {
|
|
|
|
spider := Spider{}
|
|
|
|
spider.Method = "GET"
|
|
|
|
params := "job=" + job + "&seq=" + strconv.Itoa(seq)
|
|
|
|
spider.URL = "http://yao-optimizer:8080/predict?" + params
|
|
|
|
|
|
|
|
err := spider.do()
|
|
|
|
if err != nil {
|
|
|
|
return OptimizerJobExecutionTime{}, false
|
|
|
|
}
|
|
|
|
|
|
|
|
resp := spider.getResponse()
|
|
|
|
body, err := ioutil.ReadAll(resp.Body)
|
|
|
|
resp.Body.Close()
|
|
|
|
if err != nil {
|
|
|
|
log.Warn(err)
|
|
|
|
return OptimizerJobExecutionTime{}, false
|
|
|
|
}
|
|
|
|
|
|
|
|
var res MsgOptimizerPredict
|
|
|
|
err = json.Unmarshal([]byte(string(body)), &res)
|
2020-05-02 13:24:58 +00:00
|
|
|
if err == nil {
|
2020-05-02 12:55:46 +00:00
|
|
|
return OptimizerJobExecutionTime{Total: res.Total, Pre: res.Pre, Main: res.Main, Post: res.Post}, true
|
|
|
|
}
|
|
|
|
return OptimizerJobExecutionTime{}, false
|
|
|
|
}
|