• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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    TEST_WORKLOAD_GIT_HASH = '90236fa3aa853db7af56d80cc6391432a51a1601'
38    START_INDEX = -19
39    END_INDEX = -5
40
41
42def str_to_bool(value):
43    if isinstance(value, bool):
44        return value
45    if value.lower() in ('true', '1'):
46        return True
47    elif value.lower() in ('false', '0'):
48        return False
49    else:
50        raise argparse.ArgumentTypeError('Invalid boolean value: {}'.format(value))
51
52
53def parse_args():
54    parser = argparse.ArgumentParser()
55    parser.add_argument('--code-path', metavar='DIR',
56                        help='code root path')
57    parser.add_argument('--run-aot', default=False, nargs='?', type=str_to_bool,
58                        help='Default Run run_pgo.sh, run-aot is true run run_aot.sh')
59    parser.add_argument('--report', default=False, nargs='?', type=str_to_bool,
60                        help='Support daily care performance results and script '
61                             'preliminary analysis of performance data.')
62    parser.add_argument('--tools-type', default='dev', nargs='?', help='tools type')
63    parser.add_argument('--boundary-value', default=-10, nargs='?',
64                        help='inferior boundary value')
65    parser.add_argument('--run-count', default='10', nargs='?',
66                        help='Compile all cases, execute the case count')
67    return parser.parse_args()
68
69
70def execute_shell_command(command: str):
71    process = subprocess.Popen(command, shell=False)
72    process.wait()
73
74
75def execute_shell_command_add(command: list):
76    for file in glob.glob(command[-1]):
77        command[-1] = file
78        process = subprocess.Popen(command, shell=False)
79        process.wait()
80
81
82def git_clone(repository_url: str, destination_path: str):
83    command = ['git', 'clone', repository_url, destination_path]
84    if platform.system() == "Windows":
85        subprocess.run(command, check=True, shell=False)
86    else:
87        subprocess.run(command, check=True)
88
89
90def git_checkout(commit_hash: str, destination_path: str):
91    command = ['git', 'checkout', commit_hash]
92    subprocess.run(command, cwd=destination_path)
93
94
95def git_pull(check_out_dir=os.getcwd()):
96    cmds = ['git', 'pull', '--rebase']
97    with subprocess.Popen(cmds, cwd=check_out_dir) as proc:
98        proc.wait()
99
100
101def git_clean(clean_dir=os.getcwd()):
102    cmds = ['git', 'checkout', '--', '.']
103    with subprocess.Popen(cmds, cwd=clean_dir) as proc:
104        proc.wait()
105
106
107def execute_shell_script(script_path, args):
108    command = ['sh', script_path] + args
109    process = subprocess.Popen(command, stdout=subprocess.PIPE,
110                               stderr=subprocess.PIPE, universal_newlines=True)
111    while True:
112        try:
113            text_data = process.stdout.readline()
114            sys.stdout.flush()
115            if len(text_data.strip()) != 0:
116                print(text_data.strip())
117        except OSError as error:
118            if error == errno.ENOENT:
119                print("no such file")
120            elif error == errno.EPERM:
121                print("permission denied")
122            break
123        if not text_data:
124            break
125    process.wait()
126    return_code = process.returncode
127    if return_code != 0:
128        error_output = process.stderr.read().strip()
129        if error_output:
130            print(error_output)
131
132
133def configure_environment(path, file_path, tools_type):
134    text = "--case-path ts-swift-workload\n" \
135           f"--ts-tools-path {path}\n" \
136           f"--tools-type {tools_type}\n" \
137           "--swift-tools-path ~/tools/swift-5.7.3-RELEASE-ubuntu22.04/usr/bin\n" \
138           "--android-ndk ~/apple/android-ndk-r25c\n" \
139           "--Ninja-ReleaseAssert ~/apple/build/Ninja-ReleaseAssert\n" \
140           "end"
141    args = os.O_RDWR | os.O_CREAT
142    file_descriptor = os.open(file_path, args, stat.S_IRUSR | stat.S_IWUSR)
143    file_object = os.fdopen(file_descriptor, "w+")
144    file_object.write(text)
145
146
147def write_to_txt(file_path, text):
148    args = os.O_RDWR | os.O_CREAT | os.O_APPEND
149    file_descriptor = os.open(file_path, args, stat.S_IRUSR | stat.S_IWUSR)
150    file_object = os.fdopen(file_descriptor, "w+")
151    file_object.write(text)
152
153
154def prepare_workload_code(path):
155    data_dir = os.path.join("arkcompiler/ets_runtime/test/workloadtest/", "data")
156    if path:
157        data_dir = os.path.join(path, data_dir)
158    if not os.path.isdir(os.path.join(data_dir, '.git')):
159        git_clone(WorkLoadConfig.TEST_WORKLOAD_GIT_URL, data_dir)
160        os.chdir(data_dir)
161        git_checkout(WorkLoadConfig.TEST_WORKLOAD_GIT_HASH, './')
162    else:
163        os.chdir(data_dir)
164        git_clean(data_dir)
165        git_pull(data_dir)
166        git_checkout(WorkLoadConfig.TEST_WORKLOAD_GIT_HASH, './')
167    execute_shell_command_add(['chmod', '+x', '*.sh'])
168    execute_shell_command_add(['chmod', '+x', '*.py'])
169    try:
170        importlib.import_module('openpyxl')
171    except ImportError:
172        execute_shell_command(['pip', 'install', 'openpyxl'])
173
174
175def report(boundary_value: int):
176    del_out_file()
177    folder_path = "./"
178    file_pattern = "pgo_data_*.xlsx"
179    file_paths = glob.glob(os.path.join(folder_path, file_pattern))
180    red_fill = PatternFill(start_color='FF0000', end_color='FF0000', fill_type='solid')
181    file_paths.sort(key=lambda x: datetime.datetime.strptime(
182        x[WorkLoadConfig.START_INDEX:WorkLoadConfig.END_INDEX],
183        "%Y%m%d%H%M%S"), reverse=True)
184    max_two_files = file_paths[:2]
185    if len(max_two_files) == 2:
186        wb_one = load_workbook(max_two_files[0])
187        sheet_one = wb_one.active
188        wb_two = load_workbook(max_two_files[1])
189        sheet_two = wb_two.active
190        data_one = []
191        data_two = []
192        for row in sheet_one.iter_rows(min_row=2, values_only=True):
193            data_one.append(row)
194        for row in sheet_two.iter_rows(min_row=2, values_only=True):
195            data_two.append(row)
196        if len(data_one) != len(data_two):
197            return
198        print('generate report dependent files:', max_two_files)
199        result_data = []
200        write_to_txt('../out/pgo_daily.txt', 'case:percentage\n')
201        for row_one, row_two in zip(data_one, data_two):
202            case = row_one[0]
203            average_one = row_one[-1]
204            average_two = row_two[-1]
205            difference = (average_one - average_two) / average_one * 100
206            percentage = "{:.2f}%".format(difference)
207            result_data.append([case, percentage])
208            write_to_txt('../out/pgo_daily.txt', case + percentage + '\n')
209        result_wb = Workbook()
210        result_sheet = result_wb.active
211        result_sheet.append(['case', 'percentage'])
212        for row in result_data:
213            result_sheet.append(row)
214            cell = result_sheet.cell(row=result_sheet.max_row, column=2)
215            if cell.value and float(cell.value.strip('%')) < boundary_value:
216                cell.fill = red_fill
217        now = datetime.datetime.now()
218        formatted_date = now.strftime("%Y%m%d%H%M%S")
219        daily_excel_name = "pgo_daily_" + formatted_date + ".xlsx"
220        daily_excel_out = "../out/pgo_daily.xlsx"
221        result_wb.save(daily_excel_name)
222        result_wb.save(daily_excel_out)
223
224
225def del_out_file():
226    destination_dir = '../out/'
227    os.makedirs(destination_dir, exist_ok=True)
228    file_list = os.listdir(destination_dir)
229    for file_name in file_list:
230        file_path = os.path.join(destination_dir, file_name)
231        if os.path.isfile(file_path):
232            os.remove(file_path)
233
234
235def main(args):
236    print("\nWait a moment..........\n")
237    start_time = datetime.datetime.now()
238    prepare_workload_code(args.code_path)
239    tools_type = 'dev'
240    if args.tools_type:
241        tools_type = args.tools_type
242    boundary_value = -10
243    if args.boundary_value:
244        boundary_value = args.boundary_value
245    run_count = '10'
246    if args.run_count:
247        run_count = args.run_count
248    if args.run_aot:
249        print('execute run_aot.sh is currently not supported')
250    else:
251        configure_environment(args.code_path, 'toolspath.txt', tools_type)
252        execute_args = ['--build', '--excel', '--run-count']
253        execute_args.append(run_count)
254        execute_shell_script("run_pgo.sh", execute_args)
255    end_time = datetime.datetime.now()
256    print(f"used time is: {str(end_time - start_time)}")
257    if args.report:
258        try:
259            report(int(args.boundary_value))
260        except ValueError:
261            print('args.boundary_value value should be a number')
262
263
264if __name__ == "__main__":
265    sys.exit(main(parse_args()))
266