Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
1398 lines (1081 sloc) 40.7 KB
#
# Collective Knowledge (ARM workload automation)
#
# See CK-WA LICENSE for licensing details
# See CK-WA COPYRIGHT for copyright details
#
# Developer: dividiti, grigori@dividiti.com, http://dividiti.com
#
cfg={} # Will be updated by CK (meta description of this module)
work={} # Will be updated by CK (temporal data)
ck=None # Will be updated by CK (initialized CK kernel)
# Local settings
line='*************************************************************************************'
ffstat='ck-stat-flat-characteristics.json'
##############################################################################
# Initialize module
def init(i):
"""
Input: {}
Output: {
return - return code = 0, if successful
> 0, if error
(error) - error text if return > 0
}
"""
return {'return':0}
##############################################################################
# list workloads (using module "program" with tags "wa")
def list_wa(i):
"""
Input: {
(data_uoa) - workload names (can have wild cards)
(repo_uoa) - repository
}
Output: {
return - return code = 0, if successful
> 0, if error
(error) - error text if return > 0
}
"""
o=i.get('out','')
oo=''
if o=='con': oo=o
duoa=i.get('data_uoa','')
if duoa!='':
duoa='wa-'+duoa
ruoa=i.get('repo_uoa','')
ii={'action':'search',
'module_uoa':cfg['module_deps']['program'],
'tags':'wa',
'data_uoa':duoa,
'repo_uoa':ruoa,
'add_meta':'yes'}
rr=ck.access(ii)
if rr['return']>0: return rr
if o=='con':
lst=rr['lst']
for x in lst:
duoa=x['data_uoa']
if duoa.startswith('wa-'):
duoa=duoa[3:]
duid=x['data_uid']
meta=x['meta']
desc=meta.get('wa_desc','')
x=duoa+' ('+duid+')'
if desc!='':
x+=' - '+desc
ck.out(x)
return rr
##############################################################################
# run workload via CK pipeline
def run(i):
"""
Input: {
(data_uoa) - workload to run (see "ck list wa").
(target) - machine UOA (see "ck list machine")
(record) - if 'yes', record result in repository in 'experiment' standard
(skip-record-raw) - if 'yes', skip record raw results
(overwrite) - if 'yes', do not record date and time in result directory, but overwrite wa-results
(repetitions) - statistical repetitions (default=1), for now statistical analysis is not used (TBD)
(config) - customize config
(runtime_parameters) - runtime_parameters
(params) - workload params
(scenario) - use pre-defined scenario (see ck list wa-scenario)
(keep) - if 'yes', keep tmp file in workload (program) directory
(cache) - if 'yes', cache params (to automate runs)
(cache_repo_uoa) - repo UOA where to cache params
(share) - if 'yes', share benchmarking results with public cknowledge.org/repo server
(our crowd-benchmarking demo)
(exchange_repo) - which repo to record/update info (remote-ck by default)
(exchange_subrepo) - if remote, remote repo UOA
(scenario_module_uoa) - UOA of the scenario (to share results)
}
Output: {
return - return code = 0, if successful
> 0, if error
(error) - error text if return > 0
}
"""
import os
import copy
import time
import shutil
o=i.get('out','')
oo=''
if o=='con': oo=o
try:
cur_dir=os.getcwd()
except OSError:
os.chdir('..')
cur_dir=os.getcwd()
# Check if any input has . and convert to dict
for k in list(i.keys()):
if k.find('.')>0:
v=i[k]
kk='##'+k.replace('.','#')
del(i[k])
r=ck.set_by_flat_key({'dict':i, 'key':kk, 'value':v})
if r['return']>0: return r
# Check if share
share=i.get('share','')
user=i.get('user','')
smuoa=i.get('scenario_module_uoa','')
if smuoa=='': smuoa=cfg['module_deps']['experiment.bench.workload.android']
er=i.get('exchange_repo','')
if er=='': er=ck.cfg['default_exchange_repo_uoa']
esr=i.get('exchange_subrepo','')
if esr=='': esr=ck.cfg['default_exchange_subrepo_uoa']
# Get device and workload params
config=i.get('config',{})
params=i.get('params',{})
# Check scenarios
scenario=i.get('scenario','')
if scenario=='': scenario='-'
if scenario!='' and scenario!='-':
r=ck.access({'action':'load',
'module_uoa':cfg['module_deps']['wa-scenario'],
'data_uoa':scenario})
if r['return']>0: return r
d=r['dict']
r=ck.merge_dicts({'dict1':config, 'dict2':d.get('config',{})})
if r['return']>0: return r
r=ck.merge_dicts({'dict1':params, 'dict2':d.get('params',{})})
if r['return']>0: return r
# Check workload(s)
duoa=i.get('data_uoa','')
if duoa!='':
duoa='wa-'+duoa
r=ck.access({'action':'search',
'module_uoa':cfg['module_deps']['program'],
'add_meta':'yes',
'data_uoa':duoa,
'tags':'wa'})
if r['return']>0: return r
lst=r['lst']
if len(lst)==0:
return {'return':1, 'error':'workload is not specified or found'}
record=i.get('record','')
skip_record_raw=i.get('skip-record-raw','')
overwrite=i.get('overwrite','')
repetitions=i.get('repetitions','')
if repetitions=='': repetitions=3
repetitions=int(repetitions)
cache=i.get('cache','')
# Get target features
target=i.get('target','')
if target=='':
# Check and possibly select target machines
r=ck.search({'module_uoa':cfg['module_deps']['machine'], 'data_uoa':target, 'add_meta':'yes'})
if r['return']>0: return r
dlst=r['lst']
# Prune search by only required devices
rdat=['wa_linux', 'wa_android']
xlst=[]
if len(rdat)==0:
xlst=dlst
else:
for q in dlst:
if q.get('meta',{}).get('access_type','') in rdat:
xlst.append(q)
if len(xlst)==0:
return {'return':1, 'error':'no suitable target devices found (use "ck add machine" to register new target device)'}
elif len(xlst)==1:
target=xlst[0]['data_uoa']
else:
# SELECTOR *************************************
ck.out('')
ck.out('Please select target device to run your workloads on:')
ck.out('')
r=ck.select_uoa({'choices':xlst})
if r['return']>0: return r
target=r['choice']
if target=='':
return {'return':1, 'error':'--target machine is not specified (see "ck list machine")'}
ck.out('')
ck.out('Selected target machine: '+target)
ck.out('')
# Load target machine description
r=ck.access({'action':'load',
'module_uoa':cfg['module_deps']['machine'],
'data_uoa':target})
if r['return']>0: return r
target_uoa=r['data_uoa']
target_uid=r['data_uid']
features=r['dict']['features']
device_id=r['dict'].get('device_id','')
fplat=features.get('platform',{})
fos=features.get('os',{})
fcpu=features.get('cpu',{})
fgpu=features.get('gpu',{})
plat_name=fplat.get('name','')
os_name=fos.get('name','')
cpu_name=fcpu.get('name','')
if cpu_name=='': cpu_name='unknown-'+fcpu.get('cpu_abi','')
gpu_name=fgpu.get('name','')
sn=fos.get('serial_number','')
# Make sure our wa environment has the CK Resource Getter
# expand plugin dir
gp = os.path.expanduser('~/.workload_automation/resource_getters/ck_apk_getter.py')
ii={'action':'load',
'module_uoa':'module',
'data_uoa':'wa'}
r=ck.access(ii)
if r['return']>0: return r
pp=r['path']
sp = os.path.join(pp,'ck_apk_getter.py')
# We can't be certain the isn't file is out of date if it is there, so always copy
shutil.copyfile(sp,gp)
# Iterate over workloads
rrr={}
cparams=copy.deepcopy(params)
for wa in lst:
# Reset dir
os.chdir(cur_dir)
# Reset params
params=copy.deepcopy(cparams)
duoa=wa['data_uoa']
duid=wa['data_uid']
dw=wa['meta']
dp=wa['path']
apk_name=dw.get('apk',{}).get('name','')
ww=dw['wa_alias']
# If cache, check if params already exist
if cache=='yes':
# Check extra
cruoa=i.get('cache_repo_uoa','')
# Attempt to load
r=ck.access({'action':'load',
'module_uoa':cfg['module_deps']['wa-params'],
'data_uoa':duoa,
'repo_uoa':cruoa})
if r['return']>0 and r['return']!=16:
return r
if r['return']==0:
cruoa=r['repo_uid']
rx=ck.merge_dicts({'dict1':params, 'dict2':r['dict'].get('params',{})})
if rx['return']>0: return rx
# Check params here (there is another place in pre-processing scripts
# to be able to run WA via program pipeline directly)
dparams=dw.get('params',{})
if len(dparams)>0:
ck.out('Parameters needed for this workload:')
ck.out('')
for k in sorted(dparams):
x=dparams[k]
ds=x.get('desc','')
dv=params.get(k,None)
if dv==None:
dv=x.get('default',None)
if dv!=None:
ck.out(k+': '+str(dv))
elif x.get('mandatory',False):
r=ck.inp({'text':k+' ('+ds+'): '})
if r['return']>0: return r
dv=r['string'].strip()
if dv=='':
dv=None
if dv!=None:
params[k]=dv
# Cache params if required
if cache=='yes':
r=ck.access({'action':'update',
'module_uoa':cfg['module_deps']['wa-params'],
'data_uoa':duoa,
'repo_uoa':cruoa,
'dict':{'params':params},
'sort_keys':'yes',
'substitute':'yes',
'ignore_update':'yes'})
if r['return']>0:
return r
if o=='con':
ck.out('')
ck.out('Parameters were cached in '+r['path']+' ...')
# Prepare high-level experiment meta
meta={'program_uoa':duoa,
'program_uid':duid,
'workload_name':ww,
'cpu_name':cpu_name,
'os_name':os_name,
'plat_name':plat_name,
'gpu_name':gpu_name,
'scenario':scenario,
'serial_number':sn}
mmeta=copy.deepcopy(meta)
mmeta['local_target_uoa']=target_uoa
mmeta['local_target_uid']=target_uid
if o=='con':
ck.out(line)
ck.out('Running workload '+ww+' (CK UOA='+duoa+') ...')
time.sleep(1)
aggregated_stats={} # Pre-load statistics ...
result_path=''
result_path0=''
if skip_record_raw!='yes':
if o=='con':
ck.out(' Preparing wa_result entry to store raw results ...')
ddd={'meta':mmeta}
ii={'action':'search',
'module_uoa':cfg['module_deps']['wa-result'],
'search_dict':{'meta':meta}}
rx=ck.access(ii)
if rx['return']>0: return rx
lst=rx['lst']
if len(lst)==0:
rx=ck.access({'action':'add',
'module_uoa':cfg['module_deps']['wa-result'],
'dict':ddd,
'sort_keys':'yes'})
if rx['return']>0: return rx
result_uid=rx['data_uid']
result_path=rx['path']
else:
result_uid=lst[0]['data_uid']
result_path=lst[0]['path']
# Load entry
rx=ck.access({'action':'load',
'module_uoa':cfg['module_deps']['wa-result'],
'data_uoa':result_uid})
if rx['return']>0: return rx
ddd=rx['dict']
# Possible directory extension (date-time)
result_path0=result_path
if overwrite!='yes':
rx=ck.get_current_date_time({})
if rx['return']>0: return rx
aa=rx['array']
ady=str(aa['date_year'])
adm=str(aa['date_month'])
adm=('0'*(2-len(adm)))+adm
add=str(aa['date_day'])
add=('0'*(2-len(add)))+add
ath=str(aa['time_hour'])
ath=('0'*(2-len(ath)))+ath
atm=str(aa['time_minute'])
atm=('0'*(2-len(atm)))+atm
ats=str(aa['time_second'])
ats=('0'*(2-len(ats)))+ats
pe=ady+adm+add+'-'+ath+atm+ats
result_path=os.path.join(result_path,pe)
if not os.path.isdir(result_path):
os.makedirs(result_path)
# Record input
finp=os.path.join(result_path,'ck-input.json')
r=ck.save_json_to_file({'json_file':finp, 'dict':i})
if r['return']>0: return r
ff=os.path.join(result_path,'ck-platform-features.json')
r=ck.save_json_to_file({'json_file':ff, 'dict':features})
if r['return']>0: return r
# Check stats ...
fstat=os.path.join(result_path0,ffstat)
if overwrite!='yes':
# Check if file already exists (no check for parallel runs)
if os.path.isfile(fstat):
r=ck.load_json_file({'json_file':fstat})
if r['return']==0:
aggregated_stats=r['dict']
# Prepare CK pipeline for a given workload
ii={'action':'pipeline',
'module_uoa':cfg['module_deps']['program'],
'data_uoa':duid,
'target':target,
'device_id':device_id,
'prepare':'yes',
'params':{'config':config,
'params':params},
'no_state_check':'yes',
'no_compiler_description':'yes',
'skip_info_collection':'yes',
'skip_calibration':'yes',
'cpu_freq':'',
'gpu_freq':'',
'env_speed':'yes',
'energy':'no',
'skip_print_timers':'yes',
'generate_rnd_tmp_dir':'yes',
'env':{'CK_WA_RAW_RESULT_PATH':result_path},
'out':oo}
rr=ck.access(ii)
if rr['return']>0: return rr
fail=rr.get('fail','')
if fail=='yes':
return {'return':10, 'error':'pipeline failed ('+rr.get('fail_reason','')+')'}
ready=rr.get('ready','')
if ready!='yes':
return {'return':11, 'error':'couldn\'t prepare universal CK program workflow'}
state=rr['state']
tmp_dir=state['tmp_dir']
# Clean pipeline
if 'ready' in rr: del(rr['ready'])
if 'fail' in rr: del(rr['fail'])
if 'return' in rr: del(rr['return'])
pipeline=copy.deepcopy(rr)
# Save pipeline
if skip_record_raw!='yes':
fpip=os.path.join(result_path,'ck-pipeline-in.json')
r=ck.save_json_to_file({'json_file':fpip, 'dict':pipeline})
if r['return']>0: return r
# Run CK pipeline *****************************************************
ii={'action':'autotune',
'module_uoa':cfg['module_deps']['pipeline'],
'data_uoa':cfg['module_deps']['program'],
'device_id':device_id,
'iterations':1,
'repetitions':repetitions,
'collect_all':'yes',
'process_multi_keys':['##characteristics#*'],
'tmp_dir':tmp_dir,
'pipeline':pipeline,
'stat_flat_dict':aggregated_stats,
'record':record,
'meta':meta,
'tags':'wa',
"features_keys_to_process":["##choices#*"],
"record_params": {
"search_point_by_features":"yes"
},
"record_dict":{"subview_uoa":"3d9a4f4b03b1b257"},
'out':oo}
rrr=ck.access(ii)
if rrr['return']>0: return rrr
ls=rrr.get('last_iteration_output',{})
state=ls.get('state',{})
xchoices=copy.deepcopy(ls.get('choices',{}))
lsa=rrr.get('last_stat_analysis',{})
lsad=lsa.get('dict_flat',{})
# Not very clean - trying to remove passes ...
xparams=xchoices.get('params','').get('params',{})
to_be_deleted=[]
for k in xparams:
if k.find('pass')>=0:
to_be_deleted.append(k)
for k in to_be_deleted:
del(xparams[k])
ddd['choices']=xchoices
features=ls.get('features',{})
apk_ver=''
if apk_name!='':
apk_ver=features.get('apk',{}).get(apk_name,{}).get('versionName','')
deps=ls.get('dependencies',{})
wa_ver=deps.get('wa',{}).get('cus',{}).get('version','')
# Update meta
ddd['meta']['apk_name']=apk_name
ddd['meta']['apk_version']=apk_ver
ddd['meta']['wa_version']=wa_ver
# Clean tmp dir
tmp_dir=state.get('tmp_dir','')
if dp!='' and tmp_dir!='' and i.get('keep','')!='yes':
shutil.rmtree(os.path.join(dp,tmp_dir))
fail=ls.get('fail','')
fail_reason=ls.get('fail_reason','')
ch=ls.get('characteristics',{})
# tet=ch.get('run',{}).get('total_execution_time',0)
# Save pipeline
ddd['state']={'fail':fail, 'fail_reason':fail_reason}
ddd['characteristics']=ch
if skip_record_raw!='yes':
fpip=os.path.join(result_path,'ck-pipeline-out.json')
r=ck.save_json_to_file({'json_file':fpip, 'dict':rrr})
if r['return']>0: return r
# Write stats ...
r=ck.save_json_to_file({'json_file':fstat, 'dict':lsad})
if r['return']>0: return r
# Update meta
rx=ck.access({'action':'update',
'module_uoa':cfg['module_deps']['wa-result'],
'data_uoa':result_uid,
'dict':ddd,
'substitute':'yes',
'sort_keys':'yes'})
if rx['return']>0: return rx
# Share results if crowd-benchmarking
if share=='yes':
ddd['user']=user
if o=='con':
ck.out('')
ck.out('Saving results to the remote public repo ...')
ck.out('')
# Find remote entry
rduid=''
ii={'action':'search',
'module_uoa':smuoa,
'repo_uoa':er,
'remote_repo_uoa':esr,
'search_dict':{'meta':meta}}
rx=ck.access(ii)
lst=rx['lst']
if len(lst)==1:
rduid=lst[0]['data_uid']
else:
rx=ck.gen_uid({})
if rx['return']>0: return rx
rduid=rx['data_uid']
# Update meta
rx=ck.access({'action':'update',
'module_uoa':smuoa,
'data_uoa':rduid,
'repo_uoa':er,
'remote_repo_uoa':esr,
'dict':ddd,
'substitute':'yes',
'sort_keys':'yes'})
if rx['return']>0: return rx
# Push statistical characteristics
if os.path.isfile(fstat):
rx=ck.access({'action':'push',
'module_uoa':smuoa,
'data_uoa':rduid,
'repo_uoa':er,
'remote_repo_uoa':esr,
'filename':fstat,
'overwrite':'yes'})
if rx['return']>0: return rx
# Push latest results
fx=os.path.join(result_path,'wa-output','results.json')
if os.path.isfile(fx):
rx=ck.access({'action':'push',
'module_uoa':smuoa,
'data_uoa':rduid,
'repo_uoa':er,
'remote_repo_uoa':esr,
'filename':fx,
'extra_path':'wa-output',
'overwrite':'yes'})
if rx['return']>0: return rx
# Info
if o=='con':
ck.out('Succesfully recorded results in the remote repo (Entry UID='+rduid+')')
return rrr
##############################################################################
# ARM workload automation dashboard
def dashboard(i):
"""
Input: {
(host) - Internal web server host
(port) - Internal web server port
(wfe_host) - External web server host
(wfe_port) - External web server port
(extra_url) - extra URL
}
Output: {
return - return code = 0, if successful
> 0, if error
(error) - error text if return > 0
}
"""
# Old style
# i['action']='browser'
# i['cid']=''
# i['module_uoa']=''
# i['template']='arm-wa'
i['action']='start'
i['module_uoa']='web'
i['browser']='yes'
i['template']='arm-wa'
i['cid']=''
return ck.access(i)
##############################################################################
# import workloads from original WA
def import_wa(i):
"""
Input: {
(workload) or (data_uoa) - import only this workload
(target_repo_uoa) - where to record imported workloads
(extra_target_repo_uoa) - where to record imported tools and devices
}
Output: {
return - return code = 0, if successful
> 0, if error
(error) - error text if return > 0
}
"""
import os
import copy
import shutil
import inspect
o=i.get('out','')
oo=''
if o=='con': oo=o
ruoa=i.get('target_repo_uoa','')
eruoa=i.get('extra_target_repo_uoa','')
if eruoa=='':
eruoa=ruoa
# Get platform params
target=i.get('target','')
hos=i.get('host_os','')
tos=i.get('target_os', '')
tdid=i.get('device_id', '')
ck.out('Detecting host and target platform info ...')
ck.out('')
ii={'action':'detect',
'module_uoa':cfg['module_deps']['platform'],
'out':oo,
'host_os':hos,
'target':target,
'target_os':tos,
'target_device_id':tdid}
rpp=ck.access(ii)
if rpp['return']>0: return rpp
hos=rpp['host_os_uoa']
hosd=rpp['host_os_dict']
tos=rpp['os_uoa']
tosd=rpp['os_dict']
tbits=tosd.get('bits','')
remote=tosd.get('remote','')
tdid=rpp['device_id']
if hos=='':
return {'return':1, 'error':'"host_os" is not defined or detected'}
if tos=='':
return {'return':1, 'error':'"target_os" is not defined or detected'}
# Various host and target vars
bbp=hosd.get('batch_bash_prefix','')
rem=hosd.get('rem','')
eset=hosd.get('env_set','')
etset=tosd.get('env_set','')
svarb=hosd.get('env_var_start','')
svarb1=hosd.get('env_var_extra1','')
svare=hosd.get('env_var_stop','')
svare1=hosd.get('env_var_extra2','')
scall=hosd.get('env_call','')
sdirs=hosd.get('dir_sep','')
sdirsx=tosd.get('remote_dir_sep','')
if sdirsx=='': sdirsx=sdirs
stdirs=tosd.get('dir_sep','')
sext=hosd.get('script_ext','')
sexe=hosd.get('set_executable','')
se=tosd.get('file_extensions',{}).get('exe','')
sbp=hosd.get('bin_prefix','')
stbp=tosd.get('bin_prefix','')
sqie=hosd.get('quit_if_error','')
evs=hosd.get('env_var_separator','')
envsep=hosd.get('env_separator','')
envtsep=tosd.get('env_separator','')
eifs=hosd.get('env_quotes_if_space','')
eifsc=hosd.get('env_quotes_if_space_in_call','')
eifsx=tosd.get('remote_env_quotes_if_space','')
if eifsx=='': eifsx=eifsc
wb=tosd.get('windows_base','')
stro=tosd.get('redirect_stdout','')
stre=tosd.get('redirect_stderr','')
ubtr=hosd.get('use_bash_to_run','')
no=tosd.get('no_output','')
bex=hosd.get('batch_exit','')
md5sum=hosd.get('md5sum','')
# Set environment for WA
ck.out('')
ck.out('Setting CK environment for ARM workload automation ...')
ii={'action':'set',
'module_uoa':cfg['module_deps']['env'],
'host_os':hos,
'target_os':tos,
'target_device_id':tdid,
'tags':'wa'}
r=ck.access(ii)
if r['return']>0: return r
pwlauto=r['env']['CK_ENV_TOOL_ARM_WA_WLAUTO']
bat=r['bat']
# Prepare tmp bat file
rx=ck.gen_tmp_file({'prefix':'tmp-', 'suffix':sext})
if rx['return']>0: return rx
fbat=rx['file_name']
rx=ck.gen_tmp_file({'prefix':'tmp-', 'suffix':'.tmp'})
if rx['return']>0: return rx
ftmp=rx['file_name']
# Prepare cmd
bat+='\n'
bat+='wa list workloads > '+ftmp
# Write bat file
rx=ck.save_text_file({'text_file':fbat, 'string':bat})
if rx['return']>0: return rx
y=''
if sexe!='':
y+=sexe+' '+fbat+envsep
y+=' '+scall+' '+fbat
if ubtr!='': y=ubtr.replace('$#cmd#$',y)
ck.out('')
ck.out('Executing '+bat+' ...')
os.system(y)
# Read and delete tmp file with WA description
rz=ck.load_text_file({'text_file':ftmp, 'split_to_list':'yes', 'delete_after_read':'yes'})
if rz['return']>0: return rz
lst=rz['lst']
# Delete fbat (temp)
if os.path.isfile(fbat):
os.remove(fbat)
# Parse descriptions
workload=i.get('workload','')
if workload=='':
workload=i.get('data_uoa','')
wa={}
wk=''
wv=''
##############################################################################
ck.out('Importing WA workloads to CK:')
ck.out('')
for l in lst:
if l!='':
j=l.find(': ')
if j>0:
if wk!='':
if workload=='' or workload==wk:
wa[wk]=wv
wk=''
wv=''
wk=l[:j].strip()
wv=l[j+2:].strip()
else:
wv+=' '+l.strip()
if wk!='':
if workload=='' or workload==wk: wa[wk]=wv
# Load WA template
wt=os.path.join(work['path'],'templates','wa-template.json')
r=ck.load_json_file({'json_file':wt})
if r['return']>0: return r
wtd=r['dict']
# Add entries
ck.out('')
for w in wa:
xruoa=ruoa
ww='wa-'+w
wd=wa[w]
duid=''
d={}
# First check, if such program exists
s='Adding new'
ii={'action':'load',
'module_uoa':cfg['module_deps']['program'],
'data_uoa':ww}
r=ck.access(ii)
if r['return']==0:
duid=r['data_uid']
d=r['dict']
s='Updating'
xruoa=r['repo_uid']
else:
rx=ck.gen_uid({})
if rx['return']>0: return rx
duid=rx['data_uid']
d=copy.deepcopy(wtd)
# Adding/updating entry
ck.out(' '+s+' entry "'+ww+'" ...')
d["backup_data_uid"]=duid
d["data_name"]='WA workload: '+w
d["wa_alias"]=w
# Trying to find workload in WA (if installed from GitHub ia CK):
pw=os.path.join(pwlauto,'workloads',w)
# Check __init__.py - scary hacking - would be much simpler if WA used CK format directly
cs=None
rxx=ck.load_module_from_path({'path':pw, 'module_code_name':'__init__', 'skip_init':'yes'})
if rxx['return']==0:
cs=rxx['code']
cuid=rxx['cuid']
ck.out(' Obtaining params from __init__.py ...')
wa_name=''
pp=None
pname=None
imported_params={}
# Only examine classes
for name, obj in inspect.getmembers(cs, predicate=inspect.isclass):
# And only classes defined in this module
if cuid == obj.__module__:
# And only classes that inherit from wl.auto.core.Workload
is_workload = False
def hunt_workload(obj):
fullname = obj.__module__ +'.'+ obj.__name__
if obj == object:
return False
elif fullname == "wlauto.core.workload.Workload":
is_workload = True
return True
else:
is_workload = False
for o in obj.__bases__:
is_workload |= hunt_workload(o)
return is_workload
is_workload = hunt_workload(obj)
# if name!='AndroidUxPerfWorkload' and inspect.isclass(obj):
if is_workload:
try:
addr=getattr(cs, name)
pp=addr.parameters
if type(addr.package) == str:
pname=addr.package
else:
# Cannot determine package name statically, so
# let wa ask for named resource later
# via a resourceGetter
pname=None
except Exception as e:
# Warn about problems scanning
print(e)
pass
if pp!=None:
wa_name=name
break
if pname!=None:
if 'apk' not in d: d['apk']={}
d['apk']['name']=pname
if 'android-sdk' in d['deps']: del(d['deps']['android-sdk'])
if wa_name!='':
ck.out(' WA class: '+wa_name)
for p in pp:
for name, obj in inspect.getmembers(p):
if type(obj)==dict:
pn=obj['name']
pd=obj['default']
pk=obj['kind']
pm=obj['mandatory']
pdesc=obj['description'].replace('\n','').replace(' ','').strip()
pa=obj['allowed_values']
imported_params[pn]={'default':pd, 'desc':pdesc, 'allowed_values':pa, 'type':str(pk.__name__), 'mandatory':pm}
break
if len(imported_params)>0:
d['params']=imported_params
# Cleaning up wd
if wd.endswith('.'): wd=wd[:-1]
if wd.startswith('Runs the '): wd=wd[9:]
d["wa_desc"]=wd
x=d["print_files_after_run"]
xx=[]
for y in x:
xx.append(y.replace('$#wa_name#$',w))
d["print_files_after_run"]=xx
x=d["run_cmds"]["default"]["run_time"]["run_cmd_main"]
d["run_cmds"]["default"]["run_time"]["run_cmd_main"]=x.replace('$#wa_name#$',w)
x=d["tags"]
xx=[]
for y in x:
xx.append(y.replace('$#wa_name#$',w))
d["tags"]=xx
ii={'action':'update',
'module_uoa':cfg['module_deps']['program'],
'data_uoa':ww,
'data_uid':duid,
'repo_uoa':xruoa,
'dict':d}
r=ck.access(ii)
if r['return']>0: return r
pnew=r['path']
if os.path.isdir(pw):
# Copying files to CK entry
if o=='con':
ck.out(' Copying files ...')
r=ck.list_all_files({'path':pw})
if r['return']>0: return r
lst=r['list']
for fn in lst:
p1=os.path.join(pw,fn)
p2=os.path.join(pnew,fn)
pd2=os.path.dirname(p2)
if not os.path.isdir(pd2):
os.makedirs(pd2)
shutil.copy2(p1,p2)
# If src, add Android SDK dep
p3=os.path.join(pnew,'src')
if os.path.isdir(p3):
ck.out(' Seems like sources - adding dependency on Android SDK!')
d['deps']['android-sdk']={
"local": "yes",
"name": "Android SDK",
"sort": 5,
"tags": "android,sdk"
}
############################################################################
ck.out('')
ck.out('Importing WA tools to CK:')
ck.out('')
pd=os.path.join(pwlauto,'instrumentation')
if os.path.isdir(pd):
for px in os.listdir(pd):
pdd=os.path.join(pd,px)
if os.path.isdir(pdd):
ck.out(' '+px)
r=ck.access({'action':'update',
'module_uoa':cfg['module_deps']['wa-tool'],
'data_uoa':px,
'repo_uoa':eruoa})
if r['return']>0: return r
pnew=r['path']
ck.out(' Path to CK entry: '+pnew)
# Copying files to CK entry
r=ck.list_all_files({'path':pdd})
if r['return']>0: return r
lst=r['list']
for fn in lst:
p1=os.path.join(pdd,fn)
p2=os.path.join(pnew,fn)
pd2=os.path.dirname(p2)
if not os.path.isdir(pd2):
os.makedirs(pd2)
shutil.copy2(p1,p2)
############################################################################
ck.out('')
ck.out('Importing WA devices to CK:')
ck.out('')
devs=['android','linux']
for dv in devs:
pd=os.path.join(pwlauto,'devices',dv)
if os.path.isdir(pd):
for px in os.listdir(pd):
pdd=os.path.join(pd,px)
if os.path.isdir(pdd):
ck.out(' '+px)
r=ck.access({'action':'update',
'module_uoa':cfg['module_deps']['wa-device'],
'data_uoa':dv+'-'+px,
'repo_uoa':eruoa})
if r['return']>0: return r
pnew=r['path']
ck.out(' Path to CK entry: '+pnew)
# Copying files to CK entry
r=ck.list_all_files({'path':pdd})
if r['return']>0: return r
lst=r['list']
for fn in lst:
p1=os.path.join(pdd,fn)
p2=os.path.join(pnew,fn)
pd2=os.path.dirname(p2)
if not os.path.isdir(pd2):
os.makedirs(pd2)
shutil.copy2(p1,p2)
return {'return':0}
##############################################################################
# replay a given experiment
# TBD: not finished!
def replay(i):
"""
Input: {
data_uoa - experiment UID (see "ck list wa-result")
(target) - force target machine
}
Output: {
return - return code = 0, if successful
> 0, if error
(error) - error text if return > 0
}
"""
import os
o=i.get('out','')
oo=''
if o=='con': oo=o
duoa=i.get('data_uoa','')
target=i.get('target','')
# Help
if (duoa==''):
ck.out('Usage:')
ck.out(' ck replay wa:{experiment UID}')
ck.out('')
ck.out('Notes:')
ck.out(' * You can list available experiments via "ck list wa-result"')
ck.out(' * You can view experiments via web-based WA dashboard "ck dashboard wa"')
return {'return':0}
# Load meta
r=ck.access({'action':'load',
'module_uoa':cfg['module_deps']['wa-result'],
'data_uoa':duoa})
if r['return']>0: return r
p=r['path']
d=r['dict']
dm=d.get('meta',{})
program_uoa=dm.get('program_uoa','')
if target=='':
target=dm.get('local_target_uoa','')
ii={'data_uoa':program_uoa,
'target':target,
'out':oo}
r=run(ii)
if r['return']>0: return r
return r
##############################################################################
# configure device for WA
def configure(i):
"""
Input: {
(wa_device) - device name (obtained via "wa list devices")
(wa_device_default) - default device
(device_id) - device ID (if via adb)
}
Output: {
return - return code = 0, if successful
> 0, if error
(error) - error text if return > 0
}
"""
import os
o=i.get('out','')
tdid=i.get('device_id','')
ddevice=i.get('wa_device_default','')
if ddevice=='': ddevice='generic_android'
# Load default config (in CK JSON)
pm=work['path']
p=os.path.join(pm, 'templates',cfg['default_device_cfg_file'])
r=ck.load_json_file({'json_file':p})
if r['return']>0: return r
dcfg=r['dict']
# Select WA device
device=i.get('wa_device','')
if device=='' and o=='con':
ck.out('')
ck.out('Available WA devices:')
ck.out('')
os.system('wa list devices')
ck.out('')
r=ck.inp({'text':'Enter WA device name from above list or press Enter to select "'+ddevice+'": '})
device=r['string'].strip()
if device=='': device=ddevice
dcfg['device']=device
if tdid!='':
dcfg['device_config']['adb_name']=tdid
# Extra params
if device in cfg['linux_based_wa_devices']:
device_config=dcfg.get('device_config',{})
ck.out('')
r=ck.inp({'text':'Enter hostname (or press Enter for localhost): '})
host=r['string'].strip()
if host=='': host='localhost'
device_config['host']=host
ck.out('')
r=ck.inp({'text':'Enter username (or press Enter for root): '})
username=r['string'].strip()
if username=='': username='root'
device_config['username']=username
ck.out('')
r=ck.inp({'text':'Enter full path to public keyfile: '})
keyfile=r['string'].strip()
if keyfile!='':
device_config['keyfile']=keyfile
dcfg['device_config']=device_config
# Generating config.py
s='# WA config file automatically generated by CK\n'
for k in sorted(dcfg):
s+=k+' = '
v=dcfg[k]
if type(v)==list or type(v)==dict:
r=ck.dump_json({'dict':v, 'sort_keys':'yes'})
if r['return']>0: return r
# s+=json.dumps(v, indent=2, sort_keys=True)+'\n'
s+=r['string']+'\n'
elif type(v)==int or type(v)==float:
s+=str(v)+'\n'
else:
s+='"'+str(v)+'"\n'
# Trick (not clean) to replace true with True for python
s=s.replace(' true', ' True')
return {'return':0, 'files':{cfg['device_cfg_file']:s}, 'cfg':dcfg}
##############################################################################
# crowd benchmark Android workloads via CK public repository (cknowledge.org/repo)
def crowdbench(i):
"""
Input: {
will be passed to "ck crowdsource experiment.bench.workload.android"
}
Output: {
return - return code = 0, if successful
> 0, if error
(error) - error text if return > 0
}
"""
i['module_uoa']=cfg['module_deps']['experiment.bench.workload.android']
i['action']='crowdsource'
return ck.access(i)