1#!/usr/bin/env python 2# -*- coding: utf-8 -*- 3 4# 5# Copyright (c) 2020 Huawei Device Co., Ltd. 6# Licensed under the Apache License, Version 2.0 (the "License"); 7# you may not use this file except in compliance with the License. 8# You may obtain a copy of the License at 9# 10# http://www.apache.org/licenses/LICENSE-2.0 11# 12# Unless required by applicable law or agreed to in writing, software 13# distributed under the License is distributed on an "AS IS" BASIS, 14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15# See the License for the specific language governing permissions and 16# limitations under the License. 17# 18 19import os 20import subprocess 21from datetime import datetime 22from distutils.spawn import find_executable 23from hb_internal.common.utils import exec_command 24from hb_internal.common.utils import hb_warning 25 26 27class PreBuild: 28 def __init__(self, config): 29 self._root_path = config.root_path 30 self._out_path = config.out_path 31 self._log_path = config.log_path 32 33 def set_ccache(self): 34 ccache_base = os.environ.get('CCACHE_BASE') 35 if ccache_base is None: 36 ccache_base = os.path.join(self._root_path, '.ccache') 37 if not os.path.exists(ccache_base): 38 os.makedirs(ccache_base) 39 logfile = os.path.join(self._root_path, 'ccache.log') 40 if os.path.exists(logfile): 41 oldfile = os.path.join(self._root_path, 'ccache.log.old') 42 if os.path.exists(oldfile): 43 os.unlink(oldfile) 44 os.rename(logfile, oldfile) 45 46 ccache_path = find_executable('ccache') 47 if ccache_path is None: 48 hb_warning('Failed to find ccache, ccache disabled.') 49 return 50 os.environ['CCACHE_EXEC'] = ccache_path 51 os.environ['CCACHE_LOGFILE'] = logfile 52 os.environ['USE_CCACHE'] = '1' 53 os.environ['CCACHE_DIR'] = ccache_base 54 os.environ['CCACHE_MASK'] = '002' 55 56 cmd = ['ccache', '-M', '50G'] 57 exec_command(cmd, log_path=self._log_path) 58 59 def set_pycache(self): 60 pycache_dir = os.path.join(self._root_path, '.pycache') 61 os.environ['PYCACHE_DIR'] = pycache_dir 62 pyd_start_cmd = [ 63 'python3', 64 '{}/build/scripts/util/pyd.py'.format(self._root_path), 65 '--root', 66 pycache_dir, 67 '--start', 68 ] 69 cmd = ['/bin/bash', '-c', ' '.join(pyd_start_cmd), '&'] 70 subprocess.Popen(cmd) 71 72 def rename_last_logfile(self): 73 logfile = os.path.join(self._out_path, 'build.log') 74 if os.path.exists(logfile): 75 mtime = os.stat(logfile).st_mtime 76 os.rename(logfile, '{}/build.{}.log'.format(self._out_path, mtime)) 77 78 def prepare(self, args): 79 actions = [self.set_ccache, self.rename_last_logfile] 80 for action in actions: 81 action() 82 83 84class PostBuild: 85 def __init__(self, config): 86 self._root_path = config.root_path 87 self._out_path = config.out_path 88 self._log_path = config.log_path 89 90 def clean(self, start_time): 91 self.stat_ccache() 92 self.generate_ninja_trace(start_time) 93 self.get_warning_list() 94 self.compute_overlap_rate() 95 96 def stat_pycache(self): 97 cmd = [ 98 'python3', '{}/build/scripts/util/pyd.py'.format(self._root_path), 99 '--stat' 100 ] 101 exec_command(cmd, log_path=self._log_path) 102 103 def manage_cache_data(self): 104 cmd = [ 105 'python3', '{}/build/scripts/util/pyd.py'.format(self._root_path), 106 '--manage' 107 ] 108 exec_command(cmd, log_path=self._log_path) 109 110 def stop_pyd(self): 111 cmd = [ 112 'python3', '{}/build/scripts/util/pyd.py'.format(self._root_path), 113 '--stop' 114 ] 115 exec_command(cmd, log_path=self._log_path) 116 117 def stat_ccache(self): 118 ccache_path = find_executable('ccache') 119 if ccache_path is None: 120 return 121 cmd = [ 122 'python3', '{}/build/scripts/summary_ccache_hitrate.py'.format( 123 self._root_path), '{}/ccache.log'.format(self._root_path) 124 ] 125 exec_command(cmd, log_path=self._log_path) 126 127 def get_warning_list(self): 128 cmd = [ 129 'python3', 130 '{}/build/scripts/get_warnings.py'.format(self._root_path), 131 '--build-log-file', 132 '{}/build.log'.format(self._out_path), 133 '--warning-out-file', 134 '{}/packages/WarningList.txt'.format(self._out_path), 135 ] 136 exec_command(cmd, log_path=self._log_path) 137 138 def generate_ninja_trace(self, start_time): 139 def get_unixtime(dt): 140 epoch = datetime.utcfromtimestamp(0) 141 unixtime = '%f' % ((dt - epoch).total_seconds() * 10**9) 142 return str(unixtime) 143 144 cmd = [ 145 'python3', 146 '{}/build/scripts/ninja2trace.py'.format(self._root_path), 147 '--ninja-log', 148 '{}/.ninja_log'.format(self._out_path), 149 "--trace-file", 150 "{}/build.trace".format(self._out_path), 151 "--ninja-start-time", 152 get_unixtime(start_time), 153 "--duration-file", 154 "{}/sorted_action_duration.txt".format(self._out_path), 155 ] 156 exec_command(cmd, log_path=self._log_path) 157 158 def compute_overlap_rate(self): 159 cmd = [ 160 'python3', 161 '{}/build/ohos/statistics/build_overlap_statistics.py'.format( 162 self._root_path), "--build-out-dir", self._out_path, 163 "--subsystem-config-file", 164 "{}/build/subsystem_config.json".format(self._root_path), 165 "--root-source-dir", self._root_path 166 ] 167 exec_command(cmd, log_path=self._log_path) 168