#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ 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()))