"""
Copyright (c) 2023 Huawei Device Co., Ltd.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Description: Use ark to execute workload test suite
"""
import argparse
import os
import subprocess
import platform
import errno
import sys
import importlib
import glob
import datetime
import stat
from openpyxl import load_workbook, Workbook
from openpyxl.styles import PatternFill
class WorkLoadConfig:
TEST_WORKLOAD_GIT_URL = 'https://gitee.com/xliu-huanwei/ark-workload.git'
START_INDEX = -19
END_INDEX = -5
def str_to_bool(value):
if isinstance(value, bool):
return value
if value.lower() in ('true', '1'):
return True
elif value.lower() in ('false', '0'):
return False
else:
raise argparse.ArgumentTypeError('Invalid boolean value: {}'.format(value))
def parse_args():
parser = argparse.ArgumentParser()
parser.add_argument('--code-path', metavar='DIR',
help='code root path')
parser.add_argument('--run-aot', default=False, nargs='?', type=str_to_bool,
help='Default Run run_pgo.sh, run-aot is true run run_aot.sh')
parser.add_argument('--report', default=False, nargs='?', type=str_to_bool,
help='Support daily care performance results and script '
'preliminary analysis of performance data.')
parser.add_argument('--run-interpreter', default=False, nargs='?', type=str_to_bool,
help='Run the interpreter if set to true')
parser.add_argument('--tools-type', default='dev', nargs='?', help='tools type')
parser.add_argument('--boundary-value', default=-10, nargs='?',
help='inferior boundary value')
parser.add_argument('--run-count', default='10', nargs='?',
help='Compile all cases, execute the case count')
parser.add_argument('--code-v', default='', nargs='?', help='Compile weekly_workload')
parser.add_argument('--swift-tools-path', default='', nargs='?', help='swift tools path')
parser.add_argument('--Ninja-ReleaseAssert', default='', nargs='?', help='Ninja ReleaseAssert')
return parser.parse_args()
def execute_shell_command(command: str):
process = subprocess.Popen(command, shell=False)
process.wait()
def execute_shell_command_add(command: list):
for file in glob.glob(command[-1]):
command[-1] = file
process = subprocess.Popen(command, shell=False)
process.wait()
def git_clone(repository_url: str, destination_path: str):
command = ['git', 'clone', repository_url, destination_path]
if platform.system() == "Windows":
subprocess.run(command, check=True, shell=False)
else:
subprocess.run(command, check=True)
def git_checkout(commit_hash: str, destination_path: str):
command = ['git', 'checkout', commit_hash]
subprocess.run(command, cwd=destination_path)
def git_pull(check_out_dir=os.getcwd()):
cmds = ['git', 'pull', '--rebase']
with subprocess.Popen(cmds, cwd=check_out_dir) as proc:
proc.wait()
def git_clean(clean_dir=os.getcwd()):
cmds = ['git', 'checkout', '--', '.']
with subprocess.Popen(cmds, cwd=clean_dir) as proc:
proc.wait()
def execute_shell_script(script_path, args):
command = ['bash', script_path] + args
process = subprocess.Popen(command, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, universal_newlines=True)
while True:
try:
text_data = process.stdout.readline()
sys.stdout.flush()
if len(text_data.strip()) != 0:
print(text_data.strip())
except OSError as error:
if error == errno.ENOENT:
print("no such file")
elif error == errno.EPERM:
print("permission denied")
break
if not text_data:
break
process.wait()
return_code = process.returncode
if return_code != 0:
error_output = process.stderr.read().strip()
if error_output:
print(error_output)
def configure_environment(args, code_v, tools_type):
swift_tools_path = '~/tools/swift-5.7.3-RELEASE-ubuntu22.04/usr/bin'
if args.swift_tools_path:
swift_tools_path = args.swift_tools_path
ninja_releaseAssert = '~/apple/build/Ninja-ReleaseAssert'
if args.Ninja_ReleaseAssert:
ninja_releaseAssert = args.Ninja_ReleaseAssert
text = f"--case-path {code_v}\n" \
f"--ts-tools-path {args.code_path}\n" \
f"--tools-type {tools_type}\n" \
f"--swift-tools-path {swift_tools_path}\n" \
"--android-ndk ~/apple/android-ndk-r25c\n" \
f"--Ninja-ReleaseAssert {ninja_releaseAssert}\n" \
"end"
args = os.O_RDWR | os.O_CREAT
file_descriptor = os.open('toolspath.txt', args, stat.S_IRUSR | stat.S_IWUSR)
file_object = os.fdopen(file_descriptor, "w+")
file_object.write(text)
def write_to_txt(file_path, text):
args = os.O_RDWR | os.O_CREAT | os.O_APPEND
file_descriptor = os.open(file_path, args, stat.S_IRUSR | stat.S_IWUSR)
file_object = os.fdopen(file_descriptor, "w+")
file_object.write(text)
def prepare_workload_code(path):
data_dir = os.path.join("arkcompiler/ets_runtime/test/workloadtest/", "data")
if path:
data_dir = os.path.join(path, data_dir)
if not os.path.isdir(os.path.join(data_dir, '.git')):
git_clone(WorkLoadConfig.TEST_WORKLOAD_GIT_URL, data_dir)
os.chdir(data_dir)
else:
os.chdir(data_dir)
git_clean(data_dir)
git_pull(data_dir)
execute_shell_command_add(['chmod', '+x', '*.sh'])
execute_shell_command_add(['chmod', '+x', '*.py'])
try:
importlib.import_module('openpyxl')
except ImportError:
execute_shell_command(['pip', 'install', 'openpyxl'])
def report(boundary_value: int):
del_out_file()
file_paths = glob.glob(os.path.join("./", "pgo_data_*.xlsx"))
red_fill = PatternFill(start_color='FF0000', end_color='FF0000', fill_type='solid')
file_paths.sort(key=lambda x: datetime.datetime.strptime(
x[WorkLoadConfig.START_INDEX:WorkLoadConfig.END_INDEX],
"%Y%m%d%H%M%S"), reverse=True)
max_two_files = file_paths[:2]
boundary_num = 0
if len(max_two_files) == 2:
wb_one = load_workbook(max_two_files[0])
sheet_one = wb_one.active
wb_two = load_workbook(max_two_files[1])
sheet_two = wb_two.active
data_one = []
data_two = []
for row in sheet_one.iter_rows(min_row=2, values_only=True):
data_one.append(row)
for row in sheet_two.iter_rows(min_row=2, values_only=True):
data_two.append(row)
print('generate report dependent files:', max_two_files)
result_data = []
write_to_txt('../out/pgo_daily.txt', 'case:percentage\n')
build_data(data_one, data_two, result_data)
result_wb = Workbook()
result_sheet = result_wb.active
result_sheet.append(['case', 'percentage'])
for row in result_data:
result_sheet.append(row)
cell = result_sheet.cell(row=result_sheet.max_row, column=2)
if cell.value and float(cell.value.strip('%')) < boundary_value:
cell.fill = red_fill
boundary_num += 1
now = datetime.datetime.now()
name = "".join([now.strftime("%Y%m%d%H%M%S") + "_pgo_daily.xlsx"])
result_sheet.append(['Total_Case', str(len(result_data))])
result_sheet.append(['Boundary_Total_Case', str(boundary_num)])
write_to_txt('../out/pgo_daily.txt', ''.join(["Total_Case", ":", str(len(result_data)), '\n']))
write_to_txt('../out/pgo_daily.txt', ''.join(["Boundary_Total_Case", ":", str(boundary_num), '\n']))
result_wb.save(os.path.join("../out", name))
print('generate report {} success.'.format(name))
def build_data(data_one, data_two, result_data):
for row_one in data_one:
for row_two in data_two:
if row_one[0] == row_two[0]:
append_data(row_one, row_two, result_data)
def append_data(row_one, row_two, result_data):
case = row_one[0]
average_one = convert_to_num(row_one[-1])
average_two = convert_to_num(row_two[-1])
if average_one != 0 and average_one != -1 and average_two != -1:
difference = (average_one - average_two) / average_one * 100
percentage = "{:.2f}%".format(difference)
result_data.append([case, percentage])
write_to_txt('../out/pgo_daily.txt', ''.join([case, ":", percentage, '\n']))
def convert_to_num(str_num):
try:
double_num = float(str_num)
return double_num
except ValueError:
return -1
def del_out_file():
destination_dir = '../out/'
os.makedirs(destination_dir, exist_ok=True)
file_list = os.listdir(destination_dir)
for file_name in file_list:
file_path = os.path.join(destination_dir, file_name)
if os.path.isfile(file_path):
os.remove(file_path)
def main(args):
print("\nWait a moment..........\n")
start_time = datetime.datetime.now()
prepare_workload_code(args.code_path)
print("run_interpreter: " + str(args.run_interpreter))
tools_type = 'dev'
if args.tools_type:
tools_type = args.tools_type
boundary_value = -10
if args.boundary_value:
boundary_value = args.boundary_value
run_count = '10'
if args.run_count:
run_count = args.run_count
code_v = 'weekly_workload'
if args.code_v:
code_v = args.code_v
if args.run_aot:
print('execute run_aot.sh is currently not supported')
else:
configure_environment(args, code_v, tools_type)
execute_args = ['--build', '--excel']
if code_v:
execute_args.append('--code-v')
execute_args.append(code_v)
if args.run_interpreter:
execute_args.append('--run-interpreter')
execute_args.append('--run')
execute_args.append('--run-count')
execute_args.append(run_count)
execute_shell_script("run_pgo.sh", execute_args)
end_time = datetime.datetime.now()
print(f"used time is: {str(end_time - start_time)}")
if args.report:
try:
report(int(args.boundary_value))
except ValueError:
print('args.boundary_value value should be a number')
if __name__ == "__main__":
sys.exit(main(parse_args()))