1#!/usr/bin/env python3 2# -*- coding: utf-8 -*- 3 4""" 5Copyright (c) 2023 Huawei Device Co., Ltd. 6Licensed under the Apache License, Version 2.0 (the "License"); 7you may not use this file except in compliance with the License. 8You may obtain a copy of the License at 9 10 http://www.apache.org/licenses/LICENSE-2.0 11 12Unless required by applicable law or agreed to in writing, software 13distributed under the License is distributed on an "AS IS" BASIS, 14WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15See the License for the specific language governing permissions and 16limitations under the License. 17 18Description: Use ark to execute workload test suite 19""" 20 21import argparse 22import os 23import subprocess 24import platform 25import errno 26import sys 27import importlib 28import glob 29import datetime 30import stat 31from openpyxl import load_workbook, Workbook 32from openpyxl.styles import PatternFill 33 34 35class WorkLoadConfig: 36 TEST_WORKLOAD_GIT_URL = 'https://gitee.com/xliu-huanwei/ark-workload.git' 37 START_INDEX = -19 38 END_INDEX = -5 39 40 41def str_to_bool(value): 42 if isinstance(value, bool): 43 return value 44 if value.lower() in ('true', '1'): 45 return True 46 elif value.lower() in ('false', '0'): 47 return False 48 else: 49 raise argparse.ArgumentTypeError('Invalid boolean value: {}'.format(value)) 50 51 52def parse_args(): 53 parser = argparse.ArgumentParser() 54 parser.add_argument('--code-path', metavar='DIR', 55 help='code root path') 56 parser.add_argument('--run-aot', default=False, nargs='?', type=str_to_bool, 57 help='Default Run run_pgo.sh, run-aot is true run run_aot.sh') 58 parser.add_argument('--report', default=False, nargs='?', type=str_to_bool, 59 help='Support daily care performance results and script ' 60 'preliminary analysis of performance data.') 61 parser.add_argument('--run-interpreter', default=False, nargs='?', type=str_to_bool, 62 help='Run the interpreter if set to true') 63 parser.add_argument('--tools-type', default='dev', nargs='?', help='tools type') 64 parser.add_argument('--boundary-value', default=-10, nargs='?', 65 help='inferior boundary value') 66 parser.add_argument('--run-count', default='10', nargs='?', 67 help='Compile all cases, execute the case count') 68 parser.add_argument('--code-v', default='', nargs='?', help='Compile weekly_workload') 69 parser.add_argument('--swift-tools-path', default='', nargs='?', help='swift tools path') 70 parser.add_argument('--Ninja-ReleaseAssert', default='', nargs='?', help='Ninja ReleaseAssert') 71 return parser.parse_args() 72 73 74def execute_shell_command(command: str): 75 process = subprocess.Popen(command, shell=False) 76 process.wait() 77 78 79def execute_shell_command_add(command: list): 80 for file in glob.glob(command[-1]): 81 command[-1] = file 82 process = subprocess.Popen(command, shell=False) 83 process.wait() 84 85 86def git_clone(repository_url: str, destination_path: str): 87 command = ['git', 'clone', repository_url, destination_path] 88 if platform.system() == "Windows": 89 subprocess.run(command, check=True, shell=False) 90 else: 91 subprocess.run(command, check=True) 92 93 94def git_checkout(commit_hash: str, destination_path: str): 95 command = ['git', 'checkout', commit_hash] 96 subprocess.run(command, cwd=destination_path) 97 98 99def git_pull(check_out_dir=os.getcwd()): 100 cmds = ['git', 'pull', '--rebase'] 101 with subprocess.Popen(cmds, cwd=check_out_dir) as proc: 102 proc.wait() 103 104 105def git_clean(clean_dir=os.getcwd()): 106 cmds = ['git', 'checkout', '--', '.'] 107 with subprocess.Popen(cmds, cwd=clean_dir) as proc: 108 proc.wait() 109 110 111def execute_shell_script(script_path, args): 112 command = ['bash', script_path] + args 113 process = subprocess.Popen(command, stdout=subprocess.PIPE, 114 stderr=subprocess.PIPE, universal_newlines=True) 115 while True: 116 try: 117 text_data = process.stdout.readline() 118 sys.stdout.flush() 119 if len(text_data.strip()) != 0: 120 print(text_data.strip()) 121 except OSError as error: 122 if error == errno.ENOENT: 123 print("no such file") 124 elif error == errno.EPERM: 125 print("permission denied") 126 break 127 if not text_data: 128 break 129 process.wait() 130 return_code = process.returncode 131 if return_code != 0: 132 error_output = process.stderr.read().strip() 133 if error_output: 134 print(error_output) 135 136 137def configure_environment(args, code_v, tools_type): 138 swift_tools_path = '~/tools/swift-5.7.3-RELEASE-ubuntu22.04/usr/bin' 139 if args.swift_tools_path: 140 swift_tools_path = args.swift_tools_path 141 ninja_releaseAssert = '~/apple/build/Ninja-ReleaseAssert' 142 if args.Ninja_ReleaseAssert: 143 ninja_releaseAssert = args.Ninja_ReleaseAssert 144 text = f"--case-path {code_v}\n" \ 145 f"--ts-tools-path {args.code_path}\n" \ 146 f"--tools-type {tools_type}\n" \ 147 f"--swift-tools-path {swift_tools_path}\n" \ 148 "--android-ndk ~/apple/android-ndk-r25c\n" \ 149 f"--Ninja-ReleaseAssert {ninja_releaseAssert}\n" \ 150 "end" 151 args = os.O_RDWR | os.O_CREAT 152 file_descriptor = os.open('toolspath.txt', args, stat.S_IRUSR | stat.S_IWUSR) 153 file_object = os.fdopen(file_descriptor, "w+") 154 file_object.write(text) 155 156 157def write_to_txt(file_path, text): 158 args = os.O_RDWR | os.O_CREAT | os.O_APPEND 159 file_descriptor = os.open(file_path, args, stat.S_IRUSR | stat.S_IWUSR) 160 file_object = os.fdopen(file_descriptor, "w+") 161 file_object.write(text) 162 163 164def prepare_workload_code(path): 165 data_dir = os.path.join("arkcompiler/ets_runtime/test/workloadtest/", "data") 166 if path: 167 data_dir = os.path.join(path, data_dir) 168 if not os.path.isdir(os.path.join(data_dir, '.git')): 169 git_clone(WorkLoadConfig.TEST_WORKLOAD_GIT_URL, data_dir) 170 os.chdir(data_dir) 171 else: 172 os.chdir(data_dir) 173 git_clean(data_dir) 174 git_pull(data_dir) 175 execute_shell_command_add(['chmod', '+x', '*.sh']) 176 execute_shell_command_add(['chmod', '+x', '*.py']) 177 try: 178 importlib.import_module('openpyxl') 179 except ImportError: 180 execute_shell_command(['pip', 'install', 'openpyxl']) 181 182 183def report(boundary_value: int): 184 del_out_file() 185 file_paths = glob.glob(os.path.join("./", "pgo_data_*.xlsx")) 186 red_fill = PatternFill(start_color='FF0000', end_color='FF0000', fill_type='solid') 187 file_paths.sort(key=lambda x: datetime.datetime.strptime( 188 x[WorkLoadConfig.START_INDEX:WorkLoadConfig.END_INDEX], 189 "%Y%m%d%H%M%S"), reverse=True) 190 max_two_files = file_paths[:2] 191 boundary_num = 0 192 if len(max_two_files) == 2: 193 wb_one = load_workbook(max_two_files[0]) 194 sheet_one = wb_one.active 195 wb_two = load_workbook(max_two_files[1]) 196 sheet_two = wb_two.active 197 data_one = [] 198 data_two = [] 199 for row in sheet_one.iter_rows(min_row=2, values_only=True): 200 data_one.append(row) 201 for row in sheet_two.iter_rows(min_row=2, values_only=True): 202 data_two.append(row) 203 print('generate report dependent files:', max_two_files) 204 result_data = [] 205 write_to_txt('../out/pgo_daily.txt', 'case:percentage\n') 206 build_data(data_one, data_two, result_data) 207 result_wb = Workbook() 208 result_sheet = result_wb.active 209 result_sheet.append(['case', 'percentage']) 210 for row in result_data: 211 result_sheet.append(row) 212 cell = result_sheet.cell(row=result_sheet.max_row, column=2) 213 if cell.value and float(cell.value.strip('%')) < boundary_value: 214 cell.fill = red_fill 215 boundary_num += 1 216 now = datetime.datetime.now() 217 name = "".join([now.strftime("%Y%m%d%H%M%S") + "_pgo_daily.xlsx"]) 218 result_sheet.append(['Total_Case', str(len(result_data))]) 219 result_sheet.append(['Boundary_Total_Case', str(boundary_num)]) 220 write_to_txt('../out/pgo_daily.txt', ''.join(["Total_Case", ":", str(len(result_data)), '\n'])) 221 write_to_txt('../out/pgo_daily.txt', ''.join(["Boundary_Total_Case", ":", str(boundary_num), '\n'])) 222 result_wb.save(os.path.join("../out", name)) 223 print('generate report {} success.'.format(name)) 224 225 226def build_data(data_one, data_two, result_data): 227 for row_one in data_one: 228 for row_two in data_two: 229 if row_one[0] == row_two[0]: 230 append_data(row_one, row_two, result_data) 231 232 233def append_data(row_one, row_two, result_data): 234 case = row_one[0] 235 average_one = convert_to_num(row_one[-1]) 236 average_two = convert_to_num(row_two[-1]) 237 if average_one != 0 and average_one != -1 and average_two != -1: 238 difference = (average_one - average_two) / average_one * 100 239 percentage = "{:.2f}%".format(difference) 240 result_data.append([case, percentage]) 241 write_to_txt('../out/pgo_daily.txt', ''.join([case, ":", percentage, '\n'])) 242 243 244def convert_to_num(str_num): 245 try: 246 double_num = float(str_num) 247 return double_num 248 except ValueError: 249 return -1 250 251 252def del_out_file(): 253 destination_dir = '../out/' 254 os.makedirs(destination_dir, exist_ok=True) 255 file_list = os.listdir(destination_dir) 256 for file_name in file_list: 257 file_path = os.path.join(destination_dir, file_name) 258 if os.path.isfile(file_path): 259 os.remove(file_path) 260 261 262def main(args): 263 print("\nWait a moment..........\n") 264 start_time = datetime.datetime.now() 265 prepare_workload_code(args.code_path) 266 print("run_interpreter: " + str(args.run_interpreter)) 267 tools_type = 'dev' 268 if args.tools_type: 269 tools_type = args.tools_type 270 boundary_value = -10 271 if args.boundary_value: 272 boundary_value = args.boundary_value 273 run_count = '10' 274 if args.run_count: 275 run_count = args.run_count 276 code_v = 'weekly_workload' 277 if args.code_v: 278 code_v = args.code_v 279 if args.run_aot: 280 print('execute run_aot.sh is currently not supported') 281 else: 282 configure_environment(args, code_v, tools_type) 283 execute_args = ['--build', '--excel'] 284 if code_v: 285 execute_args.append('--code-v') 286 execute_args.append(code_v) 287 if args.run_interpreter: 288 execute_args.append('--run-interpreter') 289 execute_args.append('--run') 290 execute_args.append('--run-count') 291 execute_args.append(run_count) 292 execute_shell_script("run_pgo.sh", execute_args) 293 end_time = datetime.datetime.now() 294 print(f"used time is: {str(end_time - start_time)}") 295 if args.report: 296 try: 297 report(int(args.boundary_value)) 298 except ValueError: 299 print('args.boundary_value value should be a number') 300 301 302if __name__ == "__main__": 303 sys.exit(main(parse_args())) 304