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('--tools-type', default='dev', nargs='?', help='tools type') 62 parser.add_argument('--boundary-value', default=-10, nargs='?', 63 help='inferior boundary value') 64 parser.add_argument('--run-count', default='10', nargs='?', 65 help='Compile all cases, execute the case count') 66 parser.add_argument('--code-v', default='', nargs='?', help='Compile weekly_workload') 67 parser.add_argument('--swift-tools-path', default='', nargs='?', help='swift tools path') 68 parser.add_argument('--Ninja-ReleaseAssert', default='', nargs='?', help='Ninja ReleaseAssert') 69 return parser.parse_args() 70 71 72def execute_shell_command(command: str): 73 process = subprocess.Popen(command, shell=False) 74 process.wait() 75 76 77def execute_shell_command_add(command: list): 78 for file in glob.glob(command[-1]): 79 command[-1] = file 80 process = subprocess.Popen(command, shell=False) 81 process.wait() 82 83 84def git_clone(repository_url: str, destination_path: str): 85 command = ['git', 'clone', repository_url, destination_path] 86 if platform.system() == "Windows": 87 subprocess.run(command, check=True, shell=False) 88 else: 89 subprocess.run(command, check=True) 90 91 92def git_checkout(commit_hash: str, destination_path: str): 93 command = ['git', 'checkout', commit_hash] 94 subprocess.run(command, cwd=destination_path) 95 96 97def git_pull(check_out_dir=os.getcwd()): 98 cmds = ['git', 'pull', '--rebase'] 99 with subprocess.Popen(cmds, cwd=check_out_dir) as proc: 100 proc.wait() 101 102 103def git_clean(clean_dir=os.getcwd()): 104 cmds = ['git', 'checkout', '--', '.'] 105 with subprocess.Popen(cmds, cwd=clean_dir) as proc: 106 proc.wait() 107 108 109def execute_shell_script(script_path, args): 110 command = ['bash', script_path] + args 111 process = subprocess.Popen(command, stdout=subprocess.PIPE, 112 stderr=subprocess.PIPE, universal_newlines=True) 113 while True: 114 try: 115 text_data = process.stdout.readline() 116 sys.stdout.flush() 117 if len(text_data.strip()) != 0: 118 print(text_data.strip()) 119 except OSError as error: 120 if error == errno.ENOENT: 121 print("no such file") 122 elif error == errno.EPERM: 123 print("permission denied") 124 break 125 if not text_data: 126 break 127 process.wait() 128 return_code = process.returncode 129 if return_code != 0: 130 error_output = process.stderr.read().strip() 131 if error_output: 132 print(error_output) 133 134 135def configure_environment(args, code_v, tools_type): 136 swift_tools_path = '~/tools/swift-5.7.3-RELEASE-ubuntu22.04/usr/bin' 137 if args.swift_tools_path: 138 swift_tools_path = args.swift_tools_path 139 ninja_releaseAssert = '~/apple/build/Ninja-ReleaseAssert' 140 if args.Ninja_ReleaseAssert: 141 ninja_releaseAssert = args.Ninja_ReleaseAssert 142 text = f"--case-path {code_v}\n" \ 143 f"--ts-tools-path {args.code_path}\n" \ 144 f"--tools-type {tools_type}\n" \ 145 f"--swift-tools-path {swift_tools_path}\n" \ 146 "--android-ndk ~/apple/android-ndk-r25c\n" \ 147 f"--Ninja-ReleaseAssert {ninja_releaseAssert}\n" \ 148 "end" 149 args = os.O_RDWR | os.O_CREAT 150 file_descriptor = os.open('toolspath.txt', args, stat.S_IRUSR | stat.S_IWUSR) 151 file_object = os.fdopen(file_descriptor, "w+") 152 file_object.write(text) 153 154 155def write_to_txt(file_path, text): 156 args = os.O_RDWR | os.O_CREAT | os.O_APPEND 157 file_descriptor = os.open(file_path, args, stat.S_IRUSR | stat.S_IWUSR) 158 file_object = os.fdopen(file_descriptor, "w+") 159 file_object.write(text) 160 161 162def prepare_workload_code(path): 163 data_dir = os.path.join("arkcompiler/ets_runtime/test/workloadtest/", "data") 164 if path: 165 data_dir = os.path.join(path, data_dir) 166 if not os.path.isdir(os.path.join(data_dir, '.git')): 167 git_clone(WorkLoadConfig.TEST_WORKLOAD_GIT_URL, data_dir) 168 os.chdir(data_dir) 169 else: 170 os.chdir(data_dir) 171 git_clean(data_dir) 172 git_pull(data_dir) 173 execute_shell_command_add(['chmod', '+x', '*.sh']) 174 execute_shell_command_add(['chmod', '+x', '*.py']) 175 try: 176 importlib.import_module('openpyxl') 177 except ImportError: 178 execute_shell_command(['pip', 'install', 'openpyxl']) 179 180 181def report(boundary_value: int): 182 del_out_file() 183 file_paths = glob.glob(os.path.join("./", "pgo_data_*.xlsx")) 184 red_fill = PatternFill(start_color='FF0000', end_color='FF0000', fill_type='solid') 185 file_paths.sort(key=lambda x: datetime.datetime.strptime( 186 x[WorkLoadConfig.START_INDEX:WorkLoadConfig.END_INDEX], 187 "%Y%m%d%H%M%S"), reverse=True) 188 max_two_files = file_paths[:2] 189 boundary_num = 0 190 if len(max_two_files) == 2: 191 wb_one = load_workbook(max_two_files[0]) 192 sheet_one = wb_one.active 193 wb_two = load_workbook(max_two_files[1]) 194 sheet_two = wb_two.active 195 data_one = [] 196 data_two = [] 197 for row in sheet_one.iter_rows(min_row=2, values_only=True): 198 data_one.append(row) 199 for row in sheet_two.iter_rows(min_row=2, values_only=True): 200 data_two.append(row) 201 print('generate report dependent files:', max_two_files) 202 result_data = [] 203 write_to_txt('../out/pgo_daily.txt', 'case:percentage\n') 204 build_data(data_one, data_two, result_data) 205 result_wb = Workbook() 206 result_sheet = result_wb.active 207 result_sheet.append(['case', 'percentage']) 208 for row in result_data: 209 result_sheet.append(row) 210 cell = result_sheet.cell(row=result_sheet.max_row, column=2) 211 if cell.value and float(cell.value.strip('%')) < boundary_value: 212 cell.fill = red_fill 213 boundary_num += 1 214 now = datetime.datetime.now() 215 name = "".join([now.strftime("%Y%m%d%H%M%S") + "_pgo_daily.xlsx"]) 216 result_sheet.append(['Total_Case', str(len(result_data))]) 217 result_sheet.append(['Boundary_Total_Case', str(boundary_num)]) 218 write_to_txt('../out/pgo_daily.txt', ''.join(["Total_Case", ":", str(len(result_data)), '\n'])) 219 write_to_txt('../out/pgo_daily.txt', ''.join(["Boundary_Total_Case", ":", str(boundary_num), '\n'])) 220 result_wb.save(os.path.join("../out", name)) 221 print('generate report {} success.'.format(name)) 222 223 224def build_data(data_one, data_two, result_data): 225 for row_one in data_one: 226 for row_two in data_two: 227 if row_one[0] == row_two[0]: 228 append_data(row_one, row_two, result_data) 229 230 231def append_data(row_one, row_two, result_data): 232 case = row_one[0] 233 average_one = convert_to_num(row_one[-1]) 234 average_two = convert_to_num(row_two[-1]) 235 if average_one != 0 and average_one != -1 and average_two != -1: 236 difference = (average_one - average_two) / average_one * 100 237 percentage = "{:.2f}%".format(difference) 238 result_data.append([case, percentage]) 239 write_to_txt('../out/pgo_daily.txt', ''.join([case, ":", percentage, '\n'])) 240 241 242def convert_to_num(str_num): 243 try: 244 double_num = float(str_num) 245 return double_num 246 except ValueError: 247 return -1 248 249 250def del_out_file(): 251 destination_dir = '../out/' 252 os.makedirs(destination_dir, exist_ok=True) 253 file_list = os.listdir(destination_dir) 254 for file_name in file_list: 255 file_path = os.path.join(destination_dir, file_name) 256 if os.path.isfile(file_path): 257 os.remove(file_path) 258 259 260def main(args): 261 print("\nWait a moment..........\n") 262 start_time = datetime.datetime.now() 263 prepare_workload_code(args.code_path) 264 print("run_interpreter: " + str(args.run_interpreter)) 265 tools_type = 'dev' 266 if args.tools_type: 267 tools_type = args.tools_type 268 boundary_value = -10 269 if args.boundary_value: 270 boundary_value = args.boundary_value 271 run_count = '10' 272 if args.run_count: 273 run_count = args.run_count 274 code_v = 'weekly_workload' 275 if args.code_v: 276 code_v = args.code_v 277 if args.run_aot: 278 print('execute run_aot.sh is currently not supported') 279 else: 280 configure_environment(args, code_v, tools_type) 281 execute_args = ['--build', '--excel'] 282 if code_v: 283 execute_args.append('--code-v') 284 execute_args.append(code_v) 285 if args.run_interpreter: 286 execute_args.append('--run-interpreter') 287 execute_args.append('--run') 288 execute_args.append('--run-count') 289 execute_args.append(run_count) 290 execute_shell_script("run_pgo.sh", execute_args) 291 end_time = datetime.datetime.now() 292 print(f"used time is: {str(end_time - start_time)}") 293 if args.report: 294 try: 295 report(int(args.boundary_value)) 296 except ValueError: 297 print('args.boundary_value value should be a number') 298 299 300if __name__ == "__main__": 301 sys.exit(main(parse_args())) 302