• 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    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