148f512ceSopenharmony_ci#!/usr/bin/env python
248f512ceSopenharmony_ci# -*- coding: utf-8 -*-
348f512ceSopenharmony_ci#   Copyright (c) 2021 Huawei Device Co., Ltd.
448f512ceSopenharmony_ci#   Licensed under the Apache License, Version 2.0 (the "License");
548f512ceSopenharmony_ci#   you may not use this file except in compliance with the License.
648f512ceSopenharmony_ci#   You may obtain a copy of the License at
748f512ceSopenharmony_ci#
848f512ceSopenharmony_ci#       http://www.apache.org/licenses/LICENSE-2.0
948f512ceSopenharmony_ci#
1048f512ceSopenharmony_ci#   Unless required by applicable law or agreed to in writing, software
1148f512ceSopenharmony_ci#   distributed under the License is distributed on an "AS IS" BASIS,
1248f512ceSopenharmony_ci#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1348f512ceSopenharmony_ci#   See the License for the specific language governing permissions and
1448f512ceSopenharmony_ci#   limitations under the License.
1548f512ceSopenharmony_ci
1648f512ceSopenharmony_ciimport sys
1748f512ceSopenharmony_ciimport subprocess
1848f512ceSopenharmony_ciimport argparse
1948f512ceSopenharmony_ciimport time
2048f512ceSopenharmony_ciimport os
2148f512ceSopenharmony_ciimport shutil
2248f512ceSopenharmony_ciimport platform
2348f512ceSopenharmony_cifrom ctypes import c_char_p
2448f512ceSopenharmony_cifrom ctypes import cdll
2548f512ceSopenharmony_ci
2648f512ceSopenharmony_ciIS_DEBUG = False
2748f512ceSopenharmony_ciHDC_NAME = "hdc"
2848f512ceSopenharmony_ciSYMBOL_FILES_DIR = '/data/local/tmp/local_libs/'
2948f512ceSopenharmony_ciBUILD_ID_FILE = "build_id_list"
3048f512ceSopenharmony_ciEXPECTED_TOOLS = {
3148f512ceSopenharmony_ci    HDC_NAME: {
3248f512ceSopenharmony_ci        'is_binutils': False,
3348f512ceSopenharmony_ci        'test_option': 'version',
3448f512ceSopenharmony_ci        'path_in_tool': '../platform-tools/hdc',
3548f512ceSopenharmony_ci    }
3648f512ceSopenharmony_ci}
3748f512ceSopenharmony_ci
3848f512ceSopenharmony_ci
3948f512ceSopenharmony_cidef get_lib():
4048f512ceSopenharmony_ci    script_dir = os.path.dirname(os.path.realpath(__file__))
4148f512ceSopenharmony_ci    system_type = platform.system().lower()
4248f512ceSopenharmony_ci    if system_type == "windows":
4348f512ceSopenharmony_ci        lib_path = os.path.join(script_dir, "bin", system_type,
4448f512ceSopenharmony_ci                                "x86_64", "libhiperf_report.dll")
4548f512ceSopenharmony_ci    elif system_type == "linux":
4648f512ceSopenharmony_ci        lib_path = os.path.join(script_dir, "bin", system_type,
4748f512ceSopenharmony_ci                                "x86_64", "libhiperf_report.so")
4848f512ceSopenharmony_ci    elif system_type == "darwin":
4948f512ceSopenharmony_ci        lib_path = os.path.join(script_dir, "bin", system_type,
5048f512ceSopenharmony_ci                                "x86_64", "libhiperf_report.dylib")
5148f512ceSopenharmony_ci    else:
5248f512ceSopenharmony_ci        print("Un Support System Platform")
5348f512ceSopenharmony_ci        raise RuntimeError
5448f512ceSopenharmony_ci    if not os.path.exists(lib_path):
5548f512ceSopenharmony_ci        print("{} does not exist!".format(lib_path))
5648f512ceSopenharmony_ci        raise RuntimeError
5748f512ceSopenharmony_ci    return cdll.LoadLibrary(lib_path)
5848f512ceSopenharmony_ci
5948f512ceSopenharmony_ci
6048f512ceSopenharmony_cidef remove(files):
6148f512ceSopenharmony_ci    if os.path.isfile(files):
6248f512ceSopenharmony_ci        os.remove(files)
6348f512ceSopenharmony_ci    elif os.path.isdir(files):
6448f512ceSopenharmony_ci        shutil.rmtree(files, ignore_errors=True)
6548f512ceSopenharmony_ci
6648f512ceSopenharmony_ci
6748f512ceSopenharmony_cidef is_elf_file(path):
6848f512ceSopenharmony_ci    if os.path.isfile(path):
6948f512ceSopenharmony_ci        with open(path, 'rb') as file_bin:
7048f512ceSopenharmony_ci            data = file_bin.read(4)
7148f512ceSopenharmony_ci            if len(data) == 4 and bytes_to_str(data) == '\x7fELF':
7248f512ceSopenharmony_ci                return True
7348f512ceSopenharmony_ci    return False
7448f512ceSopenharmony_ci
7548f512ceSopenharmony_ci
7648f512ceSopenharmony_cidef get_architecture(elf_path):
7748f512ceSopenharmony_ci    if is_elf_file(elf_path):
7848f512ceSopenharmony_ci        my_lib = get_lib()
7948f512ceSopenharmony_ci        my_lib.ReportGetElfArch.restype = c_char_p
8048f512ceSopenharmony_ci        ret = my_lib.ReportGetElfArch(elf_path.encode())
8148f512ceSopenharmony_ci        return ret.decode()
8248f512ceSopenharmony_ci    return 'unknown'
8348f512ceSopenharmony_ci
8448f512ceSopenharmony_ci
8548f512ceSopenharmony_cidef get_build_id(elf_path):
8648f512ceSopenharmony_ci    if is_elf_file(elf_path):
8748f512ceSopenharmony_ci        my_lib = get_lib()
8848f512ceSopenharmony_ci        my_lib.ReportGetBuildId.restype = c_char_p
8948f512ceSopenharmony_ci        ret = my_lib.ReportGetBuildId(elf_path.encode())
9048f512ceSopenharmony_ci        return ret.decode()
9148f512ceSopenharmony_ci    return ''
9248f512ceSopenharmony_ci
9348f512ceSopenharmony_ci
9448f512ceSopenharmony_cidef get_hiperf_binary_path(arch, binary_name):
9548f512ceSopenharmony_ci    if arch == 'aarch64':
9648f512ceSopenharmony_ci        arch = 'arm64'
9748f512ceSopenharmony_ci    script_dir = os.path.dirname(os.path.realpath(__file__))
9848f512ceSopenharmony_ci    arch_dir = os.path.join(script_dir, "bin", "ohos", arch)
9948f512ceSopenharmony_ci    if not os.path.isdir(arch_dir):
10048f512ceSopenharmony_ci        raise Exception("can't find arch directory: %s" % arch_dir)
10148f512ceSopenharmony_ci    binary_path = os.path.join(arch_dir, binary_name)
10248f512ceSopenharmony_ci    if not os.path.isfile(binary_path):
10348f512ceSopenharmony_ci        raise Exception("can't find binary: %s" % binary_path)
10448f512ceSopenharmony_ci    return binary_path
10548f512ceSopenharmony_ci
10648f512ceSopenharmony_ci
10748f512ceSopenharmony_cidef str_to_bytes(str_value):
10848f512ceSopenharmony_ci    if not (sys.version_info >= (3, 0)):
10948f512ceSopenharmony_ci        return str_value
11048f512ceSopenharmony_ci    return str_value.encode('utf-8')
11148f512ceSopenharmony_ci
11248f512ceSopenharmony_ci
11348f512ceSopenharmony_cidef bytes_to_str(bytes_value):
11448f512ceSopenharmony_ci    if not bytes_value:
11548f512ceSopenharmony_ci        return ''
11648f512ceSopenharmony_ci    if not (sys.version_info >= (3, 0)):
11748f512ceSopenharmony_ci        return bytes_value
11848f512ceSopenharmony_ci    return bytes_value.decode('utf-8')
11948f512ceSopenharmony_ci
12048f512ceSopenharmony_ci
12148f512ceSopenharmony_cidef executable_file_available(executable, option='--help'):
12248f512ceSopenharmony_ci    try:
12348f512ceSopenharmony_ci        print([executable, option])
12448f512ceSopenharmony_ci        subproc = subprocess.Popen([executable, option],
12548f512ceSopenharmony_ci                                   stdout=subprocess.PIPE,
12648f512ceSopenharmony_ci                                   stderr=subprocess.PIPE)
12748f512ceSopenharmony_ci        subproc.communicate(timeout=5)
12848f512ceSopenharmony_ci        return subproc.returncode == 0
12948f512ceSopenharmony_ci    except OSError:
13048f512ceSopenharmony_ci        return False
13148f512ceSopenharmony_ci
13248f512ceSopenharmony_ci
13348f512ceSopenharmony_cidef dir_check(arg):
13448f512ceSopenharmony_ci    path = os.path.realpath(arg)
13548f512ceSopenharmony_ci    if not os.path.isdir(path):
13648f512ceSopenharmony_ci        raise argparse.ArgumentTypeError('{} is not a directory.'.format(path))
13748f512ceSopenharmony_ci    return path
13848f512ceSopenharmony_ci
13948f512ceSopenharmony_ci
14048f512ceSopenharmony_cidef file_check(arg):
14148f512ceSopenharmony_ci    path = os.path.realpath(arg)
14248f512ceSopenharmony_ci    if not os.path.isfile(path):
14348f512ceSopenharmony_ci        raise argparse.ArgumentTypeError('{} is not a file.'.format(path))
14448f512ceSopenharmony_ci    return path
14548f512ceSopenharmony_ci
14648f512ceSopenharmony_ci
14748f512ceSopenharmony_cidef get_arg_list(arg_list):
14848f512ceSopenharmony_ci    res = []
14948f512ceSopenharmony_ci    if arg_list:
15048f512ceSopenharmony_ci        for arg in arg_list:
15148f512ceSopenharmony_ci            res += arg
15248f512ceSopenharmony_ci    return res
15348f512ceSopenharmony_ci
15448f512ceSopenharmony_ci
15548f512ceSopenharmony_cidef get_arch(arch):
15648f512ceSopenharmony_ci    if 'aarch64' in arch:
15748f512ceSopenharmony_ci        return 'arm64'
15848f512ceSopenharmony_ci    if 'arm' in arch:
15948f512ceSopenharmony_ci        return 'arm'
16048f512ceSopenharmony_ci    if 'x86_64' in arch or "amd64" in arch:
16148f512ceSopenharmony_ci        return 'x86_64'
16248f512ceSopenharmony_ci    if '86' in arch:
16348f512ceSopenharmony_ci        return 'x86'
16448f512ceSopenharmony_ci    raise Exception('unsupported architecture: %s' % arch.strip())
16548f512ceSopenharmony_ci
16648f512ceSopenharmony_ci
16748f512ceSopenharmony_cidef find_tool_path(tool, tool_path=None):
16848f512ceSopenharmony_ci    if tool not in EXPECTED_TOOLS:
16948f512ceSopenharmony_ci        return None
17048f512ceSopenharmony_ci    tool_info = EXPECTED_TOOLS[tool]
17148f512ceSopenharmony_ci    test_option = tool_info.get('test_option', '--help')
17248f512ceSopenharmony_ci    path_in_tool = tool_info['path_in_tool']
17348f512ceSopenharmony_ci    path_in_tool = path_in_tool.replace('/', os.sep)
17448f512ceSopenharmony_ci
17548f512ceSopenharmony_ci    # 1. Find tool in the given tool path.
17648f512ceSopenharmony_ci    if tool_path:
17748f512ceSopenharmony_ci        path = os.path.join(tool_path, path_in_tool)
17848f512ceSopenharmony_ci        if executable_file_available(path, test_option):
17948f512ceSopenharmony_ci            return path
18048f512ceSopenharmony_ci
18148f512ceSopenharmony_ci    # 2. Find tool in the tool directory containing hiperf scripts.
18248f512ceSopenharmony_ci    path = os.path.join('../..', path_in_tool)
18348f512ceSopenharmony_ci    if executable_file_available(path, test_option):
18448f512ceSopenharmony_ci        return path
18548f512ceSopenharmony_ci
18648f512ceSopenharmony_ci    # 3. Find tool in $PATH.
18748f512ceSopenharmony_ci    if executable_file_available(tool, test_option):
18848f512ceSopenharmony_ci        return tool
18948f512ceSopenharmony_ci
19048f512ceSopenharmony_ci    return None
19148f512ceSopenharmony_ci
19248f512ceSopenharmony_ci
19348f512ceSopenharmony_ciclass HdcInterface:
19448f512ceSopenharmony_ci    def __init__(self, root_authority=True):
19548f512ceSopenharmony_ci        hdc_path = find_tool_path(HDC_NAME)
19648f512ceSopenharmony_ci        if not hdc_path:
19748f512ceSopenharmony_ci            raise Exception("Can't find hdc in PATH environment.")
19848f512ceSopenharmony_ci        self.hdc_path = hdc_path
19948f512ceSopenharmony_ci        self.root_authority = root_authority
20048f512ceSopenharmony_ci
20148f512ceSopenharmony_ci    def run_hdc_cmd(self, hdc_args, log_output=True):
20248f512ceSopenharmony_ci        hdc_args = [self.hdc_path] + hdc_args
20348f512ceSopenharmony_ci        if IS_DEBUG:
20448f512ceSopenharmony_ci            print('run hdc cmd: %s' % hdc_args)
20548f512ceSopenharmony_ci        subproc = subprocess.Popen(hdc_args, stdout=subprocess.PIPE)
20648f512ceSopenharmony_ci        (out, _) = subproc.communicate()
20748f512ceSopenharmony_ci        out = bytes_to_str(out)
20848f512ceSopenharmony_ci        return_code = subproc.returncode
20948f512ceSopenharmony_ci        result = (return_code == 0)
21048f512ceSopenharmony_ci        if out and hdc_args[1] != 'file send' and \
21148f512ceSopenharmony_ci                hdc_args[1] != 'file recv':
21248f512ceSopenharmony_ci            if log_output:
21348f512ceSopenharmony_ci                print(out)
21448f512ceSopenharmony_ci        if IS_DEBUG:
21548f512ceSopenharmony_ci            print('run hdc cmd: %s  [result %s]' % (hdc_args, result))
21648f512ceSopenharmony_ci        return result, out
21748f512ceSopenharmony_ci
21848f512ceSopenharmony_ci    def check_run(self, hdc_args):
21948f512ceSopenharmony_ci        result, out = self.run_hdc_cmd(hdc_args)
22048f512ceSopenharmony_ci        if not result:
22148f512ceSopenharmony_ci            raise Exception('run "hdc %s" failed' % hdc_args)
22248f512ceSopenharmony_ci        return out
22348f512ceSopenharmony_ci
22448f512ceSopenharmony_ci    def _not_use_root(self):
22548f512ceSopenharmony_ci        result, out = self.run_hdc_cmd(['shell', 'whoami'])
22648f512ceSopenharmony_ci        if not result or 'root' not in out:
22748f512ceSopenharmony_ci            return
22848f512ceSopenharmony_ci        print('unroot hdc')
22948f512ceSopenharmony_ci        self.run_hdc_cmd(['unroot'])
23048f512ceSopenharmony_ci        time.sleep(1)
23148f512ceSopenharmony_ci        self.run_hdc_cmd(['wait-for-device'])
23248f512ceSopenharmony_ci
23348f512ceSopenharmony_ci    def switch_root(self):
23448f512ceSopenharmony_ci        if not self.root_authority:
23548f512ceSopenharmony_ci            self._not_use_root()
23648f512ceSopenharmony_ci            return False
23748f512ceSopenharmony_ci        result, out = self.run_hdc_cmd(['shell', 'whoami'])
23848f512ceSopenharmony_ci        if not result:
23948f512ceSopenharmony_ci            return False
24048f512ceSopenharmony_ci        if 'root' in out:
24148f512ceSopenharmony_ci            return True
24248f512ceSopenharmony_ci        build_type = self.get_attribute('ro.build.type')
24348f512ceSopenharmony_ci        if build_type == 'user':
24448f512ceSopenharmony_ci            return False
24548f512ceSopenharmony_ci        self.run_hdc_cmd(['root'])
24648f512ceSopenharmony_ci        time.sleep(1)
24748f512ceSopenharmony_ci        self.run_hdc_cmd(['wait-for-device'])
24848f512ceSopenharmony_ci        result, out = self.run_hdc_cmd(['shell', 'whoami'])
24948f512ceSopenharmony_ci        return result and 'root' in out
25048f512ceSopenharmony_ci
25148f512ceSopenharmony_ci    def get_attribute(self, name):
25248f512ceSopenharmony_ci        result, out = self.run_hdc_cmd(['shell', 'getprop',
25348f512ceSopenharmony_ci                                        name])
25448f512ceSopenharmony_ci        if result:
25548f512ceSopenharmony_ci            return out
25648f512ceSopenharmony_ci
25748f512ceSopenharmony_ci    def get_device_architecture(self):
25848f512ceSopenharmony_ci        output = self.check_run(['shell', 'uname', '-m'])
25948f512ceSopenharmony_ci        return get_arch(output)
26048f512ceSopenharmony_ci
26148f512ceSopenharmony_ci
26248f512ceSopenharmony_ciclass ElfStruct:
26348f512ceSopenharmony_ci    def __init__(self, path, lib_name):
26448f512ceSopenharmony_ci        self.path = path
26548f512ceSopenharmony_ci        self.name = lib_name
26648f512ceSopenharmony_ci
26748f512ceSopenharmony_ci
26848f512ceSopenharmony_ciclass LocalLibDownload:
26948f512ceSopenharmony_ci
27048f512ceSopenharmony_ci    def __init__(self, device_arch, hdc):
27148f512ceSopenharmony_ci        self.hdc = hdc
27248f512ceSopenharmony_ci        self.device_arch = device_arch
27348f512ceSopenharmony_ci
27448f512ceSopenharmony_ci        self.build_id_map_of_host = {}
27548f512ceSopenharmony_ci        self.build_id_map_of_device = {}
27648f512ceSopenharmony_ci        self.host_lib_count_map = {}
27748f512ceSopenharmony_ci        self.request_architectures = self.__get_need_architectures(device_arch)
27848f512ceSopenharmony_ci
27948f512ceSopenharmony_ci    def get_host_local_libs(self, local_lib_dir):
28048f512ceSopenharmony_ci        self.build_id_map_of_host.clear()
28148f512ceSopenharmony_ci        for root, dirs, files in os.walk(local_lib_dir):
28248f512ceSopenharmony_ci            for name in files:
28348f512ceSopenharmony_ci                if name.endswith('.so'):
28448f512ceSopenharmony_ci                    self.__append_host_local_lib(os.path.join(root, name),
28548f512ceSopenharmony_ci                                                 name)
28648f512ceSopenharmony_ci
28748f512ceSopenharmony_ci    def get_device_local_libs(self):
28848f512ceSopenharmony_ci        self.build_id_map_of_device.clear()
28948f512ceSopenharmony_ci        if os.path.exists(BUILD_ID_FILE):
29048f512ceSopenharmony_ci            remove(BUILD_ID_FILE)
29148f512ceSopenharmony_ci        self.hdc.check_run(['shell', 'mkdir', '-p', SYMBOL_FILES_DIR])
29248f512ceSopenharmony_ci        self.hdc.run_hdc_cmd(['file recv', SYMBOL_FILES_DIR + BUILD_ID_FILE])
29348f512ceSopenharmony_ci        if os.path.isfile(BUILD_ID_FILE):
29448f512ceSopenharmony_ci            with open(BUILD_ID_FILE, 'rb') as file_bin:
29548f512ceSopenharmony_ci                for line in file_bin.readlines():
29648f512ceSopenharmony_ci                    line = bytes_to_str(line).strip()
29748f512ceSopenharmony_ci                    items = line.split('=')
29848f512ceSopenharmony_ci                    if len(items) == 2:
29948f512ceSopenharmony_ci                        self.build_id_map_of_device[items[0]] = items[1]
30048f512ceSopenharmony_ci            remove(BUILD_ID_FILE)
30148f512ceSopenharmony_ci
30248f512ceSopenharmony_ci    def update_device_local_libs(self):
30348f512ceSopenharmony_ci        # Send local libs to device.
30448f512ceSopenharmony_ci        for build_id in self.build_id_map_of_host:
30548f512ceSopenharmony_ci            if build_id not in self.build_id_map_of_device:
30648f512ceSopenharmony_ci                elf_struct = self.build_id_map_of_host[build_id]
30748f512ceSopenharmony_ci                self.hdc.check_run(['file send', elf_struct.path,
30848f512ceSopenharmony_ci                                    SYMBOL_FILES_DIR + elf_struct.name])
30948f512ceSopenharmony_ci
31048f512ceSopenharmony_ci        # Remove Device lib while local libs not exist on host.
31148f512ceSopenharmony_ci        for build_id in self.build_id_map_of_device:
31248f512ceSopenharmony_ci            if build_id not in self.build_id_map_of_host:
31348f512ceSopenharmony_ci                name = self.build_id_map_of_device[build_id]
31448f512ceSopenharmony_ci                self.hdc.run_hdc_cmd(['shell', 'rm', SYMBOL_FILES_DIR + name])
31548f512ceSopenharmony_ci
31648f512ceSopenharmony_ci        # Send new build_id_list to device.
31748f512ceSopenharmony_ci        with open(BUILD_ID_FILE, 'wb') as file_bin:
31848f512ceSopenharmony_ci            for build_id in self.build_id_map_of_host:
31948f512ceSopenharmony_ci                str_bytes = str_to_bytes('%s=%s\n' % (build_id,
32048f512ceSopenharmony_ci                                          self.build_id_map_of_host[
32148f512ceSopenharmony_ci                                              build_id].name))
32248f512ceSopenharmony_ci                file_bin.write(str_bytes)
32348f512ceSopenharmony_ci
32448f512ceSopenharmony_ci        self.hdc.check_run(['file send', BUILD_ID_FILE,
32548f512ceSopenharmony_ci                            SYMBOL_FILES_DIR + BUILD_ID_FILE])
32648f512ceSopenharmony_ci        remove(BUILD_ID_FILE)
32748f512ceSopenharmony_ci
32848f512ceSopenharmony_ci    def __append_host_local_lib(self, path, name):
32948f512ceSopenharmony_ci        build_id = get_build_id(path)
33048f512ceSopenharmony_ci        if not build_id:
33148f512ceSopenharmony_ci            return
33248f512ceSopenharmony_ci        arch = get_architecture(path)
33348f512ceSopenharmony_ci        if arch not in self.request_architectures:
33448f512ceSopenharmony_ci            return
33548f512ceSopenharmony_ci
33648f512ceSopenharmony_ci        elf_struct = self.build_id_map_of_host.get(build_id)
33748f512ceSopenharmony_ci        if not elf_struct:
33848f512ceSopenharmony_ci            count = self.host_lib_count_map.get(name, 0)
33948f512ceSopenharmony_ci            self.host_lib_count_map[name] = count + 1
34048f512ceSopenharmony_ci            if count == 0:
34148f512ceSopenharmony_ci                unique_name = name
34248f512ceSopenharmony_ci            else:
34348f512ceSopenharmony_ci                unique_name = name + '_' + count
34448f512ceSopenharmony_ci            self.build_id_map_of_host[build_id] = ElfStruct(path,
34548f512ceSopenharmony_ci                                                            unique_name)
34648f512ceSopenharmony_ci        else:
34748f512ceSopenharmony_ci            elf_struct.path = path
34848f512ceSopenharmony_ci
34948f512ceSopenharmony_ci    @classmethod
35048f512ceSopenharmony_ci    def __get_need_architectures(self, device_arch):
35148f512ceSopenharmony_ci        if device_arch == 'x86_64':
35248f512ceSopenharmony_ci            return ['x86', 'x86_64']
35348f512ceSopenharmony_ci        if device_arch == 'x86':
35448f512ceSopenharmony_ci            return ['x86']
35548f512ceSopenharmony_ci        if device_arch == 'arm64':
35648f512ceSopenharmony_ci            return ['arm', 'arm64']
35748f512ceSopenharmony_ci        if device_arch == 'arm':
35848f512ceSopenharmony_ci            return ['arm']
35948f512ceSopenharmony_ci        return []
36048f512ceSopenharmony_ci
36148f512ceSopenharmony_ci
36248f512ceSopenharmony_ciclass PerformanceProfile:
36348f512ceSopenharmony_ci    """Class of all Profilers."""
36448f512ceSopenharmony_ci
36548f512ceSopenharmony_ci    def __init__(self, args, control_module=""):
36648f512ceSopenharmony_ci        self.args = args
36748f512ceSopenharmony_ci        self.hdc = HdcInterface(root_authority=not args.not_hdc_root)
36848f512ceSopenharmony_ci        self.device_root = self.hdc.switch_root()
36948f512ceSopenharmony_ci        self.device_arch = self.hdc.get_device_architecture()
37048f512ceSopenharmony_ci        self.record_subproc = None
37148f512ceSopenharmony_ci        self.is_control = bool(control_module)
37248f512ceSopenharmony_ci        self.control_mode = control_module
37348f512ceSopenharmony_ci
37448f512ceSopenharmony_ci    def profile(self):
37548f512ceSopenharmony_ci        if not self.is_control or self.control_mode == "prepare":
37648f512ceSopenharmony_ci            print('prepare profiling')
37748f512ceSopenharmony_ci            self.download()
37848f512ceSopenharmony_ci            print('start profiling')
37948f512ceSopenharmony_ci            if not self.combine_args():
38048f512ceSopenharmony_ci                return
38148f512ceSopenharmony_ci        else:
38248f512ceSopenharmony_ci            self.exec_control()
38348f512ceSopenharmony_ci        self.profiling()
38448f512ceSopenharmony_ci
38548f512ceSopenharmony_ci        if not self.is_control:
38648f512ceSopenharmony_ci            print('pull profiling data')
38748f512ceSopenharmony_ci            self.get_profiling_data()
38848f512ceSopenharmony_ci        if self.control_mode == "stop":
38948f512ceSopenharmony_ci            self.wait_data_generate_done()
39048f512ceSopenharmony_ci        print('profiling is finished.')
39148f512ceSopenharmony_ci
39248f512ceSopenharmony_ci    def download(self):
39348f512ceSopenharmony_ci        """Prepare recording. """
39448f512ceSopenharmony_ci        if self.args.local_lib_dir:
39548f512ceSopenharmony_ci            self.download_libs()
39648f512ceSopenharmony_ci
39748f512ceSopenharmony_ci    def download_libs(self):
39848f512ceSopenharmony_ci        executor = LocalLibDownload(self.device_arch, self.hdc)
39948f512ceSopenharmony_ci        executor.get_host_local_libs(self.args.local_lib_dir)
40048f512ceSopenharmony_ci        executor.get_device_local_libs()
40148f512ceSopenharmony_ci        executor.update_device_local_libs()
40248f512ceSopenharmony_ci
40348f512ceSopenharmony_ci    def combine_args(self):
40448f512ceSopenharmony_ci        if self.args.package_name:
40548f512ceSopenharmony_ci            if self.args.ability:
40648f512ceSopenharmony_ci                self.kill_process()
40748f512ceSopenharmony_ci            self.start_profiling(['--app', self.args.package_name])
40848f512ceSopenharmony_ci            if self.args.ability:
40948f512ceSopenharmony_ci                ability = self.args.package_name + '/' + self.args.ability
41048f512ceSopenharmony_ci                start_cmd = ['shell', 'aa', 'start', '-a', ability]
41148f512ceSopenharmony_ci                result = self.hdc.run_hdc_cmd(start_cmd)
41248f512ceSopenharmony_ci                if not result:
41348f512ceSopenharmony_ci                    self.record_subproc.terminate()
41448f512ceSopenharmony_ci                    print("Can't start ability %s" % ability)
41548f512ceSopenharmony_ci                    return False
41648f512ceSopenharmony_ci            # else: no need to start an ability.
41748f512ceSopenharmony_ci        elif self.args.local_program:
41848f512ceSopenharmony_ci            pid = self.hdc.check_run(['shell', 'pidof',
41948f512ceSopenharmony_ci                                      self.args.local_program])
42048f512ceSopenharmony_ci            if not pid:
42148f512ceSopenharmony_ci                print("Can't find pid of %s" % self.args.local_program)
42248f512ceSopenharmony_ci                return False
42348f512ceSopenharmony_ci            pid = int(pid)
42448f512ceSopenharmony_ci            self.start_profiling(['-p', str(pid)])
42548f512ceSopenharmony_ci        elif self.args.cmd:
42648f512ceSopenharmony_ci            cmds = self.args.cmd.split(' ')
42748f512ceSopenharmony_ci            cmd = [cmd.replace("'", "") for cmd in cmds]
42848f512ceSopenharmony_ci            self.start_profiling(cmd)
42948f512ceSopenharmony_ci        elif self.args.pid:
43048f512ceSopenharmony_ci            self.start_profiling(['-p', ','.join(self.args.pid)])
43148f512ceSopenharmony_ci        elif self.args.tid:
43248f512ceSopenharmony_ci            self.start_profiling(['-t', ','.join(self.args.tid)])
43348f512ceSopenharmony_ci        elif self.args.system_wide:
43448f512ceSopenharmony_ci            self.start_profiling(['-a'])
43548f512ceSopenharmony_ci        return True
43648f512ceSopenharmony_ci
43748f512ceSopenharmony_ci    def kill_process(self):
43848f512ceSopenharmony_ci        if self.get_app_process():
43948f512ceSopenharmony_ci            self.hdc.check_run(['shell', 'aa', 'force-stop', self.args.app])
44048f512ceSopenharmony_ci            count = 0
44148f512ceSopenharmony_ci            while True:
44248f512ceSopenharmony_ci                time.sleep(1)
44348f512ceSopenharmony_ci                pid = self.get_app_process()
44448f512ceSopenharmony_ci                if not pid:
44548f512ceSopenharmony_ci                    break
44648f512ceSopenharmony_ci                count += 1
44748f512ceSopenharmony_ci                # 3 seconds exec kill
44848f512ceSopenharmony_ci                if count >= 3:
44948f512ceSopenharmony_ci                    self.run_in_app_dir(['kill', '-9', str(pid)])
45048f512ceSopenharmony_ci
45148f512ceSopenharmony_ci    def get_app_process(self):
45248f512ceSopenharmony_ci        result, output = self.hdc.run_hdc_cmd(
45348f512ceSopenharmony_ci            ['shell', 'pidof', self.args.package_name])
45448f512ceSopenharmony_ci        return int(output) if result else None
45548f512ceSopenharmony_ci
45648f512ceSopenharmony_ci    def run_in_app_dir(self, args):
45748f512ceSopenharmony_ci        if self.device_root:
45848f512ceSopenharmony_ci            hdc_args = ['shell', 'cd /data/data/' + self.args.package_name +
45948f512ceSopenharmony_ci                        ' && ' + (' '.join(args))]
46048f512ceSopenharmony_ci        else:
46148f512ceSopenharmony_ci            hdc_args = ['shell', 'run-as', self.args.package_name] + args
46248f512ceSopenharmony_ci        return self.hdc.run_hdc_cmd(hdc_args, log_output=False)
46348f512ceSopenharmony_ci
46448f512ceSopenharmony_ci    def start_profiling(self, selected_args):
46548f512ceSopenharmony_ci        """Start hiperf reocrd process on device."""
46648f512ceSopenharmony_ci        record_options = self.args.record_options.split(' ')
46748f512ceSopenharmony_ci        record_options = [cmd.replace("'", "") for cmd in record_options]
46848f512ceSopenharmony_ci        if self.is_control:
46948f512ceSopenharmony_ci            args = ['hiperf', 'record',
47048f512ceSopenharmony_ci                    '--control', self.control_mode, '-o',
47148f512ceSopenharmony_ci                    '/data/local/tmp/perf.data'] + record_options
47248f512ceSopenharmony_ci        else:
47348f512ceSopenharmony_ci            args = ['hiperf', 'record', '-o',
47448f512ceSopenharmony_ci                    '/data/local/tmp/perf.data'] + record_options
47548f512ceSopenharmony_ci        if self.args.local_lib_dir and self.hdc.run_hdc_cmd(
47648f512ceSopenharmony_ci                ['shell', 'ls', SYMBOL_FILES_DIR]):
47748f512ceSopenharmony_ci            args += ['--symbol-dir', SYMBOL_FILES_DIR]
47848f512ceSopenharmony_ci        args += selected_args
47948f512ceSopenharmony_ci        hdc_args = [self.hdc.hdc_path, 'shell'] + args
48048f512ceSopenharmony_ci        print('run hdc cmd: %s' % hdc_args)
48148f512ceSopenharmony_ci        self.record_subproc = subprocess.Popen(hdc_args)
48248f512ceSopenharmony_ci
48348f512ceSopenharmony_ci    def profiling(self):
48448f512ceSopenharmony_ci        """
48548f512ceSopenharmony_ci        Wait until profiling finishes, or stop profiling when user
48648f512ceSopenharmony_ci        presses Ctrl-C.
48748f512ceSopenharmony_ci        """
48848f512ceSopenharmony_ci
48948f512ceSopenharmony_ci        try:
49048f512ceSopenharmony_ci            return_code = self.record_subproc.wait()
49148f512ceSopenharmony_ci        except KeyboardInterrupt:
49248f512ceSopenharmony_ci            self.end_profiling()
49348f512ceSopenharmony_ci            self.record_subproc = None
49448f512ceSopenharmony_ci            return_code = 0
49548f512ceSopenharmony_ci        print('profiling result [%s]' % (return_code == 0))
49648f512ceSopenharmony_ci        if return_code != 0:
49748f512ceSopenharmony_ci            raise Exception('Failed to record profiling data.')
49848f512ceSopenharmony_ci
49948f512ceSopenharmony_ci    def end_profiling(self):
50048f512ceSopenharmony_ci        """
50148f512ceSopenharmony_ci        Stop profiling by sending SIGINT to hiperf, and wait until it exits
50248f512ceSopenharmony_ci        to make sure perf.data is completely generated.
50348f512ceSopenharmony_ci        """
50448f512ceSopenharmony_ci        has_killed = False
50548f512ceSopenharmony_ci        while True:
50648f512ceSopenharmony_ci            (result, out) = self.hdc.run_hdc_cmd(
50748f512ceSopenharmony_ci                ['shell', 'pidof', 'hiperf'])
50848f512ceSopenharmony_ci            if not out:
50948f512ceSopenharmony_ci                break
51048f512ceSopenharmony_ci            if not has_killed:
51148f512ceSopenharmony_ci                has_killed = True
51248f512ceSopenharmony_ci                self.hdc.run_hdc_cmd(['shell', 'pkill',
51348f512ceSopenharmony_ci                                      '-l', '2', 'hiperf'])
51448f512ceSopenharmony_ci            time.sleep(1)
51548f512ceSopenharmony_ci
51648f512ceSopenharmony_ci    def get_profiling_data(self):
51748f512ceSopenharmony_ci        current_path = os.getcwd()
51848f512ceSopenharmony_ci        full_path = os.path.join(current_path, self.args.output_perf_data)
51948f512ceSopenharmony_ci        self.hdc.check_run(['file recv', '/data/local/tmp/perf.data',
52048f512ceSopenharmony_ci                            full_path])
52148f512ceSopenharmony_ci        self.hdc.run_hdc_cmd(['shell', 'rm',
52248f512ceSopenharmony_ci                              '/data/local/tmp/perf.data'])
52348f512ceSopenharmony_ci
52448f512ceSopenharmony_ci    def exec_control(self):
52548f512ceSopenharmony_ci        hdc_args = [self.hdc.hdc_path, 'shell',
52648f512ceSopenharmony_ci                    'hiperf', 'record',
52748f512ceSopenharmony_ci                    '--control', self.control_mode]
52848f512ceSopenharmony_ci        print('run hdc cmd: %s' % hdc_args)
52948f512ceSopenharmony_ci        self.record_subproc = subprocess.Popen(hdc_args)
53048f512ceSopenharmony_ci
53148f512ceSopenharmony_ci    def wait_data_generate_done(self):
53248f512ceSopenharmony_ci        last_size = 0
53348f512ceSopenharmony_ci        while True:
53448f512ceSopenharmony_ci            (result, out) = self.hdc.run_hdc_cmd(
53548f512ceSopenharmony_ci                ['shell', 'du', 'data/local/tmp/perf.data'])
53648f512ceSopenharmony_ci            if "du" not in out:
53748f512ceSopenharmony_ci                current_size = out.split(" ")[0]
53848f512ceSopenharmony_ci                if current_size == last_size:
53948f512ceSopenharmony_ci                    self.get_profiling_data()
54048f512ceSopenharmony_ci                    break
54148f512ceSopenharmony_ci                else:
54248f512ceSopenharmony_ci                    last_size = current_size
54348f512ceSopenharmony_ci            else:
54448f512ceSopenharmony_ci                print("not generate perf.data")
54548f512ceSopenharmony_ci                break
54648f512ceSopenharmony_ci
54748f512ceSopenharmony_ci            time.sleep(1)
548