optimizer.go 7.9 KB
Newer Older
D
dogsheng 已提交
1 2
/*
 * Copyright (c) 2019 Huawei Technologies Co., Ltd.
3 4 5
 * A-Tune is licensed under the Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
6
 *     http://license.coscl.org.cn/MulanPSL2
D
dogsheng 已提交
7 8 9
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
 * PURPOSE.
10
 * See the Mulan PSL v2 for more details.
D
dogsheng 已提交
11 12 13 14 15 16 17 18 19 20
 * Create: 2019-10-29
 */

package tuning

import (
	PB "atune/api/profile"
	"atune/common/config"
	"atune/common/http"
	"atune/common/log"
Z
Zhipeng Xie 已提交
21
	"atune/common/models"
D
dogsheng 已提交
22
	"atune/common/project"
Z
Zhipeng Xie 已提交
23
	"atune/common/utils"
D
dogsheng 已提交
24
	"fmt"
25
	"io/ioutil"
26
	"os"
27
	"path"
28
	"path/filepath"
Z
Zhipeng Xie 已提交
29
	"strconv"
30
	"strings"
31
	"time"
D
dogsheng 已提交
32 33
)

Z
Zhipeng Xie 已提交
34 35
// Optimizer : the type implement the bayes serch service
type Optimizer struct {
36 37 38 39 40 41 42 43 44
	Prj             *project.YamlPrjSvr
	Content         []byte
	Iter            int
	MaxIter         int
	OptimizerPutURL string
	FinalEval       string
	MinEvalSum      float64
	RespPutIns      *models.RespPutBody
	StartIterTime   string
D
dogsheng 已提交
45 46
}

47 48 49 50 51 52
// InitTuned method for init tuning
func (o *Optimizer) InitTuned(ch chan *PB.AckCheck) error {
	clientIter, err := strconv.Atoi(string(o.Content))
	if err != nil {
		return err
	}
D
dogsheng 已提交
53

54 55
	log.Infof("begin to dynamic optimizer search, client ask iterations:%d", clientIter)
	ch <- &PB.AckCheck{Name: fmt.Sprintf("begin to dynamic optimizer search")}
D
dogsheng 已提交
56

Z
Zhipeng Xie 已提交
57
	//dynamic profle setting
58 59 60
	o.MaxIter = clientIter
	if o.MaxIter > o.Prj.Maxiterations {
		o.MaxIter = o.Prj.Maxiterations
Z
Zhipeng Xie 已提交
61 62 63
		log.Infof("project:%s max iterations:%d", o.Prj.Project, o.Prj.Maxiterations)
		ch <- &PB.AckCheck{Name: fmt.Sprintf("server project %s max iterations %d\n",
			o.Prj.Project, o.Prj.Maxiterations)}
D
dogsheng 已提交
64 65
	}

66
	if err := utils.CreateDir(config.DefaultTempPath, 0750); err != nil {
67 68 69 70 71 72 73 74 75 76 77
		return err
	}

	projectName := fmt.Sprintf("project %s\n", o.Prj.Project)
	err = utils.WriteFile(config.TuningFile, projectName, config.FilePerm,
		os.O_WRONLY|os.O_CREATE|os.O_TRUNC)
	if err != nil {
		log.Error(err)
		return err
	}

78
	initConfigure := make([]string, 0)
Z
Zhipeng Xie 已提交
79
	optimizerBody := new(models.OptimizerPostBody)
80
	optimizerBody.MaxEval = o.MaxIter
Z
Zhipeng Xie 已提交
81
	optimizerBody.Knobs = make([]models.Knob, 0)
D
dogsheng 已提交
82
	for _, item := range o.Prj.Object {
Z
Zhipeng Xie 已提交
83
		knob := new(models.Knob)
D
dogsheng 已提交
84 85 86 87 88 89 90
		knob.Dtype = item.Info.Dtype
		knob.Name = item.Name
		knob.Type = item.Info.Type
		knob.Ref = item.Info.Ref
		knob.Range = item.Info.Scope
		knob.Items = item.Info.Items
		knob.Step = item.Info.Step
Z
Zhipeng Xie 已提交
91
		knob.Options = item.Info.Options
D
dogsheng 已提交
92
		optimizerBody.Knobs = append(optimizerBody.Knobs, *knob)
93 94 95

		out, err := project.ExecCommand(item.Info.GetScript)
		if err != nil {
H
hanxinke 已提交
96
			return fmt.Errorf("failed to exec %s, err: %v", item.Info.GetScript, err)
97
		}
98
		initConfigure = append(initConfigure, strings.TrimSpace(knob.Name+"="+string(out)))
99 100 101
	}

	err = utils.WriteFile(path.Join(config.DefaultTempPath,
102
		o.Prj.Project+config.TuningRestoreConfig), strings.Join(initConfigure, ","),
103 104 105 106
		config.FilePerm, os.O_WRONLY|os.O_CREATE|os.O_TRUNC)
	if err != nil {
		log.Error(err)
		return err
D
dogsheng 已提交
107 108 109 110 111 112
	}

	respPostIns, err := optimizerBody.Post()
	if err != nil {
		return err
	}
Z
Zhipeng Xie 已提交
113
	if respPostIns.Status != "OK" {
114 115 116
		err := fmt.Errorf("create task failed: %s", respPostIns.Status)
		log.Errorf(err.Error())
		return err
Z
Zhipeng Xie 已提交
117
	}
D
dogsheng 已提交
118

Z
Zhipeng Xie 已提交
119
	url := config.GetURL(config.OptimizerURI)
120 121
	o.OptimizerPutURL = fmt.Sprintf("%s/%s", url, respPostIns.TaskID)
	log.Infof("optimizer put url is: %s", o.OptimizerPutURL)
D
dogsheng 已提交
122

123 124
	o.Content = nil
	if err := o.DynamicTuned(ch); err != nil {
Z
Zhipeng Xie 已提交
125 126 127 128 129 130 131 132 133
		return err
	}

	return nil
}

/*
DynamicTuned method using bayes algorithm to search the best performance parameters
*/
134
func (o *Optimizer) DynamicTuned(ch chan *PB.AckCheck) error {
135
	var evalValue string
Z
Zhipeng Xie 已提交
136
	var err error
137 138
	if o.Content != nil {
		evalValue, err = o.evalParsing(ch)
D
dogsheng 已提交
139
		if err != nil {
140
			return err
D
dogsheng 已提交
141
		}
Z
Zhipeng Xie 已提交
142
	}
D
dogsheng 已提交
143

144
	os.Setenv("ITERATION", strconv.Itoa(o.Iter))
145

Z
Zhipeng Xie 已提交
146
	optPutBody := new(models.OptimizerPutBody)
147
	optPutBody.Iterations = o.Iter
148
	optPutBody.Value = evalValue
149
	o.RespPutIns, err = optPutBody.Put(o.OptimizerPutURL)
Z
Zhipeng Xie 已提交
150 151
	if err != nil {
		log.Errorf("get setting parameter error: %v", err)
152
		return err
Z
Zhipeng Xie 已提交
153 154
	}

155 156
	log.Infof("setting params is: %s", o.RespPutIns.Param)
	if err := o.Prj.RunSet(o.RespPutIns.Param); err != nil {
Z
Zhipeng Xie 已提交
157
		log.Error(err)
158
		return err
Z
Zhipeng Xie 已提交
159 160
	}
	log.Info("set the parameter success")
161 162

	if err := o.Prj.RestartProject(); err != nil {
Z
Zhipeng Xie 已提交
163
		log.Error(err)
164
		return err
D
dogsheng 已提交
165
	}
Z
Zhipeng Xie 已提交
166
	log.Info("restart project success")
D
dogsheng 已提交
167

168
	o.StartIterTime = time.Now().Format(config.DefaultTimeFormat)
169

170 171
	if o.Iter == o.MaxIter {
		finalEval := strings.Replace(o.FinalEval, "=-", "=", -1)
172
		optimizationTerm := fmt.Sprintf("\n The final optimization result is: %s\n"+
173
			" The final evaluation value is: %s", o.RespPutIns.Param, finalEval)
174
		log.Info(optimizationTerm)
175
		ch <- &PB.AckCheck{Name: optimizationTerm}
176

177
		if err = deleteTask(o.OptimizerPutURL); err != nil {
Z
Zhipeng Xie 已提交
178 179 180 181
			log.Error(err)
		}
	}

182 183 184 185
	o.Iter++
	ch <- &PB.AckCheck{Status: utils.SUCCESS}

	return nil
Z
Zhipeng Xie 已提交
186 187
}

188
//restore tuning config
189
func (o *Optimizer) RestoreConfigTuned(ch chan *PB.AckCheck) error {
190 191 192 193 194 195
	tuningRestoreConf := path.Join(config.DefaultTempPath, o.Prj.Project+config.TuningRestoreConfig)
	exist, err := utils.PathExist(tuningRestoreConf)
	if err != nil {
		return err
	}
	if !exist {
196 197 198 199
		err := fmt.Errorf("%s project has not been executed "+
			"the dynamic optimizer search", o.Prj.Project)
		log.Errorf(err.Error())
		return err
200 201 202 203 204 205 206 207 208 209 210 211 212 213
	}

	content, err := ioutil.ReadFile(tuningRestoreConf)
	if err != nil {
		log.Error(err)
		return err
	}

	log.Infof("restoring params is: %s", string(content))
	if err := o.Prj.RunSet(string(content)); err != nil {
		log.Error(err)
		return err
	}

214 215 216
	result := fmt.Sprintf("restore %s project params success", o.Prj.Project)
	ch <- &PB.AckCheck{Name: result, Status: utils.SUCCESS}
	log.Infof(result)
217 218 219
	return nil
}

220 221
func (o *Optimizer) evalParsing(ch chan *PB.AckCheck) (string, error) {
	eval := string(o.Content)
H
hanxinke 已提交
222
	positiveEval := strings.Replace(eval, "=-", "=", -1)
223
	optimizationTerm := fmt.Sprintf("The %dth optimization result is: %s\n"+
224
		" The %dth evaluation value is: %s", o.Iter, o.RespPutIns.Param, o.Iter, positiveEval)
225 226 227 228 229
	ch <- &PB.AckCheck{Name: optimizationTerm}
	log.Info(optimizationTerm)

	endIterTime := time.Now().Format(config.DefaultTimeFormat)
	iterInfo := make([]string, 0)
230 231
	iterInfo = append(iterInfo, strconv.Itoa(o.Iter), o.StartIterTime, endIterTime,
		positiveEval, o.RespPutIns.Param)
232 233 234 235 236 237 238 239 240
	output := strings.Join(iterInfo, "|")
	err := utils.WriteFile(config.TuningFile, output+"\n", config.FilePerm,
		os.O_APPEND|os.O_WRONLY)
	if err != nil {
		log.Error(err)
		return "", err
	}

	evalValue := make([]string, 0)
H
hanxinke 已提交
241
	evalSum := 0.0
242 243 244 245 246 247 248 249 250 251 252 253
	for _, benchStr := range strings.Split(eval, ",") {
		kvs := strings.Split(benchStr, "=")
		if len(kvs) < 2 {
			continue
		}

		floatEval, err := strconv.ParseFloat(kvs[1], 64)
		if err != nil {
			log.Error(err)
			return "", err
		}

H
hanxinke 已提交
254
		evalSum += floatEval
255 256
		evalValue = append(evalValue, kvs[1])
	}
H
hanxinke 已提交
257

258 259 260
	if o.Iter == 1 || evalSum < o.MinEvalSum {
		o.MinEvalSum = evalSum
		o.FinalEval = eval
H
hanxinke 已提交
261
	}
262 263 264
	return strings.Join(evalValue, ","), nil
}

Z
Zhipeng Xie 已提交
265 266
func deleteTask(url string) error {
	resp, err := http.Delete(url)
D
dogsheng 已提交
267
	if err != nil {
H
hanxinke 已提交
268
		log.Error("delete task failed:", err)
Z
Zhipeng Xie 已提交
269
		return err
D
dogsheng 已提交
270 271 272 273
	}
	defer resp.Body.Close()
	return nil
}
274 275 276 277 278 279 280 281

//check server prj
func CheckServerPrj(data string, optimizer *Optimizer) error {
	var prjs []*project.YamlPrjSvr
	err := filepath.Walk(config.DefaultTuningPath, func(path string, info os.FileInfo, err error) error {
		if !info.IsDir() {
			prj := new(project.YamlPrjSvr)
			if err := utils.ParseFile(path, "yaml", &prj); err != nil {
H
hanxinke 已提交
282
				return fmt.Errorf("load %s failed, err: %v", path, err)
283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303
			}
			log.Infof("project:%s load %s success", prj.Project, path)
			prjs = append(prjs, prj)
		}
		return nil
	})

	if err != nil {
		return err
	}

	for _, prj := range prjs {
		if data == prj.Project {
			log.Infof("find Project:%s", prj.Project)
			optimizer.Prj = prj
			return nil
		}
	}

	return fmt.Errorf("project:%s not found", data)
}