This repository has been archived by the owner on Jan 24, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 14
/
main.xsh
executable file
·327 lines (285 loc) · 11.3 KB
/
main.xsh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
#!/usr/bin/env xonsh
$RAISE_SUBPROC_ERROR = True
$XONSH_SHOW_TRACEBACK = True
import sys; sys.path.insert(0, '')
import _config
from _config import pjoin
from utils import PathRecover, log
import persistence as pst
import os
import repo
import argparse
import traceback
import time
import json
import shutil
$ceroot=_config.workspace
develop_evaluate=_config.develop_evaluate
os.environ['ceroot'] = _config.workspace
mode = os.environ.get('mode', 'evaluation')
specific_tasks = os.environ.get('specific_tasks', None)
specific_tasks = specific_tasks.split(',') if specific_tasks else []
case_type = os.environ.get('case_type', None)
tasks_env = os.environ.get('tasks_env', None)
def parse_args():
parser= argparse.ArgumentParser("Tool for running CE models")
parser.add_argument(
'--modified',
action='store_true',
help='if set, we will just run modified models.')
args = parser.parse_args()
return args
def main():
#try_start_mongod()
args = parse_args()
suc, exception_task = evaluate_tasks(args)
if suc:
display_success_info()
if mode == "evaluation" and (not args.modified) and (not specific_tasks):
update_baseline()
exit 0
else:
if (not args.modified) and (not specific_tasks):
display_fail_info(exception_task)
sys.exit(-1)
def update_baseline():
''' update the baseline in a git repo using current base. '''
log.warn('updating baseline')
commit = repo.get_commit(_config.paddle_path)
with PathRecover():
message = "evalute [%s]" % commit
for task_name in get_tasks():
task_dir = pjoin(_config.baseline_path, task_name)
cd @(task_dir)
print('task_dir', task_dir)
if os.path.isdir('latest_kpis'):
# update baseline if the latest kpi is better than history
tracking_kpis = get_kpi_tasks(task_name)
for kpi in tracking_kpis:
# if the kpi is not actived, do not update baseline.
if not kpi.actived: continue
kpi.root = task_dir
better_ratio = kpi.compare_with(kpi.cur_data, kpi.baseline_data)
if better_ratio > _config.kpi_update_threshold:
log.warn('current kpi %s better than history by %f, update baseline' % (kpi.out_file, better_ratio))
cp @(kpi.out_file) @(kpi.his_file)
if $(git diff):
log.warn('update github baseline')
'''
due to the selected update controled by `_config.kpi_update_threshold`, if one task passed, there might be no baselines to update.
'''
git pull origin master
git commit -a -m @(message)
git push
else:
log.warn('no baseline need to update')
def refresh_baseline_workspace():
''' download baseline. '''
if mode != "baseline_test":
# ssh from home is not very stable, can be solved by retry.
max_retry = 10
for cnt in range(max_retry):
try:
# production mode, clean baseline and rerun
rm -rf @(_config.baseline_path)
git clone @(_config.baseline_repo_url) @(_config.baseline_path)
log.info("git clone %s suc" % _config.baseline_repo_url)
break
except Exception as e:
if cnt == max_retry - 1:
raise Exception("git clone failed %s " % e)
else:
log.warn('git clone failed %d, %s' % (cnt, e))
time.sleep(3)
def evaluate_tasks(args):
'''
Evaluate all the tasks. It will continue to run all the tasks even
if any task is failed to get a summary.
'''
cd @(_config.workspace)
print("_config.workspace", _config.workspace)
paddle_commit = repo.get_commit(_config.paddle_path)
commit_time = repo.get_commit_date(_config.paddle_path)
log.warn('commit', paddle_commit)
all_passed = True
exception_task = {}
# get tasks that need to evaluate
if specific_tasks:
tasks = specific_tasks
log.warn('run specific tasks', tasks)
elif args.modified:
tasks = [v for v in get_changed_tasks()]
log.warn('run changed tasks', tasks)
else:
tasks = [v for v in get_tasks()]
log.warn('run all tasks', tasks)
#get develop kpis of all tasks and write to develop_kpis
if develop_evaluate == 'True':
prepare_develop_kpis(tasks)
for task in tasks:
try:
passed, eval_infos, kpis, kpi_values, kpi_types, detail_infos, develop_infos = evaluate(task)
if mode != "baseline_test":
log.warn('add evaluation %s result to mongodb' % task)
kpi_objs = get_kpi_tasks(task)
if (not args.modified) and (not specific_tasks):
pst.add_evaluation_record(commitid = paddle_commit,
date = commit_time,
task = "%s_%s" % (tasks_env, task) if tasks_env else task,
passed = passed,
infos = eval_infos,
kpis = kpis,
kpi_values = kpi_values,
kpi_types = kpi_types,
kpi_objs = kpi_objs,
detail_infos = detail_infos,
develop_infos = develop_infos)
if not passed:
all_passed = False
except Exception as e:
exception_task[task] = traceback.format_exc()
all_passed = False
return all_passed, exception_task
def prepare_develop_kpis(tasks):
'''
'''
# get develop kpis from db
develop_kpis = pst.get_kpis_from_db(tasks)
# save kpi to file
for task in tasks:
try:
if task not in develop_kpis:
continue
kpis = develop_kpis[task]
kpis_keys = kpis['kpis-keys']
kpis_values = json.loads(kpis['kpis-values'])
assert len(kpis_keys)==len(kpis_values)
for i in range(len(kpis_keys)):
save_kpis(task, kpis_keys[i], kpis_values[i])
except Exception as e:
log.warn(e)
def save_kpis(task_name, kpi_name, kpi_value):
'''
'''
develop_dir = "develop_kpis"
task_dir = pjoin(_config.baseline_path, task_name)
with PathRecover():
os.chdir(task_dir)
if not os.path.exists(develop_dir):
os.makedirs(develop_dir)
os.chdir(develop_dir)
file_name = kpi_name + "_factor.txt"
with open(file_name, 'w') as fout:
for item in kpi_value:
fout.write(str(item) + '\n')
def evaluate(task_name):
'''
task_name: str
name of a task directory.
returns:
passed: bool
whether this task passes the evaluation.
eval_infos: list of str
human-readable evaluations result for all the kpis of this task.
kpis: dict of (kpi_name, list_of_float)
'''
task_dir = pjoin(_config.baseline_path, task_name)
log.warn('evaluating model', task_name)
with PathRecover():
try:
cd @(task_dir)
./run.xsh
except Exception as e:
print(e)
tracking_kpis = get_kpi_tasks(task_name)
# evaluate all the kpis
eval_infos = []
detail_infos = []
develop_infos = []
kpis = []
kpi_values = []
kpi_types = []
passed = True
for kpi in tracking_kpis:
suc = kpi.evaluate(task_dir)
if (not suc) and kpi.actived:
''' Only if the kpi is actived, its evaluation result would affect the overall tasks's result. '''
passed = False
log.error("Task [%s] failed!" % task_name)
log.error("details:", kpi.fail_info)
kpis.append(kpi.name)
kpi_values.append(kpi.cur_data)
kpi_types.append(kpi.__class__.__name__)
# if failed, still continue to evaluate the other kpis to get full statistics.
eval_infos.append(kpi.fail_info if not suc else kpi.success_info)
detail_infos.append(kpi.detail_info)
develop_infos.append(kpi.develop_info)
if develop_evaluate == 'False':
develop_infos = []
log.info("evaluation kpi info: %s %s %s" % (passed, eval_infos, kpis))
return passed, eval_infos, kpis, kpi_values, kpi_types, detail_infos, develop_infos
def get_tasks():
with PathRecover():
cd @(_config.workspace)
subdirs = $(ls @(_config.baseline_path)).split()
if case_type:
return filter(lambda x : x.startswith('%s_' % case_type), subdirs)
else:
return filter(lambda x : not (x.startswith('__') or x.startswith('model_')
or x.endswith('.md') or x.startswith('models')), subdirs)
def display_fail_info(exception_task):
paddle_commit = repo.get_commit(_config.paddle_path)
infos = pst.db.finds(_config.table_name, {'commitid': paddle_commit, 'type': 'kpi' })
log.error('Evaluate [%s] failed!' % paddle_commit)
log.warn('The details:')
detail_info = ''
for info in infos:
if not info['passed']:
log.warn('task:', info['task'])
detail_info += info['task'] + ' '
log.warn('passed: ', info['passed'])
log.warn('infos', '\n'.join(info['infos']))
log.warn('kpis keys', info['kpis-keys'])
log.warn('kpis values', info['kpis-values'])
if exception_task:
for task, info in exception_task.items():
detail_info += task + ' '
log.error("%s %s" %(task, info))
with open("fail_models", 'w') as f:
f.write(detail_info)
def display_success_info():
paddle_commit = repo.get_commit(_config.paddle_path)
log.warn('Evaluate [%s] successed!' % paddle_commit)
def try_start_mongod():
out = $(ps ax | grep mongod).strip().split('\n')
print('out', out)
if len(out) < 1: # there are no mongod service
log.warn('starting mongodb')
mkdir -p /chunwei/ce_mongo.db
mongod --dbpath /chunwei/ce_mongo.db &
def get_kpi_tasks(task_name):
with PathRecover():
cd @(_config.workspace)
env = {}
try:
exec('from tasks.%s.continuous_evaluation import tracking_kpis'
% task_name, env)
log.info("import from continuous_evaluation suc.")
except Exception as e:
exec('from tasks.%s._ce import tracking_kpis'
% task_name, env)
tracking_kpis = env['tracking_kpis']
print(tracking_kpis)
return tracking_kpis
def get_changed_tasks():
tasks = []
cd @(_config.baseline_path)
out = $(git diff master | grep "diff --git")
out = out.strip()
for item in out.split('\n'):
task = item.split()[3].split('/')[1]
if task not in tasks:
tasks.append(task)
log.warn("changed tasks: %s" % tasks)
return tasks
main()