15f9996aaSopenharmony_ci#!/usr/bin/env python 25f9996aaSopenharmony_ci# -*- coding: utf-8 -*- 35f9996aaSopenharmony_ci# Copyright (c) 2021 Huawei Device Co., Ltd. 45f9996aaSopenharmony_ci# Licensed under the Apache License, Version 2.0 (the "License"); 55f9996aaSopenharmony_ci# you may not use this file except in compliance with the License. 65f9996aaSopenharmony_ci# You may obtain a copy of the License at 75f9996aaSopenharmony_ci# 85f9996aaSopenharmony_ci# http://www.apache.org/licenses/LICENSE-2.0 95f9996aaSopenharmony_ci# 105f9996aaSopenharmony_ci# Unless required by applicable law or agreed to in writing, software 115f9996aaSopenharmony_ci# distributed under the License is distributed on an "AS IS" BASIS, 125f9996aaSopenharmony_ci# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 135f9996aaSopenharmony_ci# See the License for the specific language governing permissions and 145f9996aaSopenharmony_ci# limitations under the License. 155f9996aaSopenharmony_ci 165f9996aaSopenharmony_ciimport os 175f9996aaSopenharmony_ciimport sys 185f9996aaSopenharmony_ciimport fnmatch 195f9996aaSopenharmony_ciimport argparse 205f9996aaSopenharmony_ciimport json 215f9996aaSopenharmony_ci 225f9996aaSopenharmony_ci 235f9996aaSopenharmony_cidef is_combine_jars(contents: dict): 245f9996aaSopenharmony_ci if contents.get('deps_info').get('combine_target'): 255f9996aaSopenharmony_ci return True 265f9996aaSopenharmony_ci else: 275f9996aaSopenharmony_ci return False 285f9996aaSopenharmony_ci 295f9996aaSopenharmony_ci 305f9996aaSopenharmony_cidef get_sources_file(build_config: str): 315f9996aaSopenharmony_ci if not fnmatch.fnmatch(build_config, "*java*.build_config"): 325f9996aaSopenharmony_ci return None 335f9996aaSopenharmony_ci with open(build_config, 'r') as config_f: 345f9996aaSopenharmony_ci contents = json.load(config_f) 355f9996aaSopenharmony_ci if is_combine_jars(contents): 365f9996aaSopenharmony_ci return None 375f9996aaSopenharmony_ci return contents.get('deps_info').get('java_sources_file') 385f9996aaSopenharmony_ci 395f9996aaSopenharmony_ci 405f9996aaSopenharmony_cidef read_file(sources_file: str): 415f9996aaSopenharmony_ci contents = [] 425f9996aaSopenharmony_ci if not os.path.exists(sources_file): 435f9996aaSopenharmony_ci return [] 445f9996aaSopenharmony_ci with open(sources_file, 'r') as this: 455f9996aaSopenharmony_ci contents = [line.strip() for line in this.readlines()] 465f9996aaSopenharmony_ci return contents 475f9996aaSopenharmony_ci 485f9996aaSopenharmony_ci 495f9996aaSopenharmony_cidef get_subsystem_paths(file: str, root_dir: str): 505f9996aaSopenharmony_ci paths = { 515f9996aaSopenharmony_ci 'common': 'build', 525f9996aaSopenharmony_ci 'thirdparty': 'third_party', 535f9996aaSopenharmony_ci 'test': 'test', 545f9996aaSopenharmony_ci 'mcl': 'mcl' 555f9996aaSopenharmony_ci } 565f9996aaSopenharmony_ci with open(file, 'r') as jfile: 575f9996aaSopenharmony_ci data = json.load(jfile) 585f9996aaSopenharmony_ci for key in data.keys(): 595f9996aaSopenharmony_ci path = data.get(key).get('path') 605f9996aaSopenharmony_ci if os.path.exists(os.path.join(root_dir, path)): 615f9996aaSopenharmony_ci paths[key] = path 625f9996aaSopenharmony_ci 635f9996aaSopenharmony_ci return paths 645f9996aaSopenharmony_ci 655f9996aaSopenharmony_ci 665f9996aaSopenharmony_cidef overlap_rate_key(element): 675f9996aaSopenharmony_ci return element['overlap_rate'] 685f9996aaSopenharmony_ci 695f9996aaSopenharmony_ci 705f9996aaSopenharmony_cidef compute_overlap_rate_by_subsystem(options, paths: str, program_language: str): 715f9996aaSopenharmony_ci objs = [] 725f9996aaSopenharmony_ci if program_language == 'c': 735f9996aaSopenharmony_ci pattern = '*.o' 745f9996aaSopenharmony_ci if program_language == 'java': 755f9996aaSopenharmony_ci pattern = '*.build_config' 765f9996aaSopenharmony_ci for root, _, files in os.walk(options.build_out_dir): 775f9996aaSopenharmony_ci for file in fnmatch.filter(files, pattern): 785f9996aaSopenharmony_ci if program_language == 'c': 795f9996aaSopenharmony_ci splits = os.path.join(root, file).split('/obj/') 805f9996aaSopenharmony_ci obj = ''.join(splits[1:]) 815f9996aaSopenharmony_ci if obj == '': 825f9996aaSopenharmony_ci continue 835f9996aaSopenharmony_ci if obj.find('/gen/') != -1: 845f9996aaSopenharmony_ci splits = obj.split('/gen/') 855f9996aaSopenharmony_ci obj = ''.join(splits[1:]) 865f9996aaSopenharmony_ci objs.append(obj) 875f9996aaSopenharmony_ci if program_language == 'java': 885f9996aaSopenharmony_ci sources_file = get_sources_file(os.path.join(root, file)) 895f9996aaSopenharmony_ci if not sources_file: 905f9996aaSopenharmony_ci continue 915f9996aaSopenharmony_ci for java_file in read_file( 925f9996aaSopenharmony_ci os.path.join(options.build_out_dir, sources_file)): 935f9996aaSopenharmony_ci if fnmatch.fnmatch(java_file, "*/generated_java/*"): 945f9996aaSopenharmony_ci continue 955f9996aaSopenharmony_ci objs.append(java_file) 965f9996aaSopenharmony_ci 975f9996aaSopenharmony_ci total_builds = len(objs) 985f9996aaSopenharmony_ci total_files = len(set(objs)) 995f9996aaSopenharmony_ci if total_builds == 0 or total_files == 0: 1005f9996aaSopenharmony_ci return 1015f9996aaSopenharmony_ci 1025f9996aaSopenharmony_ci statistics = [] 1035f9996aaSopenharmony_ci for subsystem in sorted(paths.keys()): 1045f9996aaSopenharmony_ci path = paths.get(subsystem) 1055f9996aaSopenharmony_ci if program_language == 'c': 1065f9996aaSopenharmony_ci pattern = '{}*'.format(path) 1075f9996aaSopenharmony_ci if program_language == 'java': 1085f9996aaSopenharmony_ci pattern = '../../{}*'.format(path) 1095f9996aaSopenharmony_ci 1105f9996aaSopenharmony_ci sub_objs = [] 1115f9996aaSopenharmony_ci for obj in fnmatch.filter(objs, pattern): 1125f9996aaSopenharmony_ci sub_objs.append(obj) 1135f9996aaSopenharmony_ci builds = len(sub_objs) 1145f9996aaSopenharmony_ci files = len(set(sub_objs)) 1155f9996aaSopenharmony_ci if files == 0: 1165f9996aaSopenharmony_ci continue 1175f9996aaSopenharmony_ci overlap_rate = float(builds) / float(files) 1185f9996aaSopenharmony_ci sub_stat = { 1195f9996aaSopenharmony_ci "builds": builds, 1205f9996aaSopenharmony_ci "builds_percentage": 100 * float(builds) / float(total_builds), 1215f9996aaSopenharmony_ci "files": files, 1225f9996aaSopenharmony_ci "files_percentage": 100 * float(files) / float(total_files), 1235f9996aaSopenharmony_ci "overlap_rate": overlap_rate, 1245f9996aaSopenharmony_ci "subsystem": subsystem, 1255f9996aaSopenharmony_ci } 1265f9996aaSopenharmony_ci statistics.append(sub_stat) 1275f9996aaSopenharmony_ci print('{} targets overlap rate statistics'.format(program_language)) 1285f9996aaSopenharmony_ci print('{:16}\t{:8}\t{:5}\t{:8}\t{:5}\t{:4}'.format( 1295f9996aaSopenharmony_ci 'subsystem', 'files NO.', 'percentage', 'builds NO.', 'percentage', 1305f9996aaSopenharmony_ci 'overlap rate')) 1315f9996aaSopenharmony_ci 1325f9996aaSopenharmony_ci for item in sorted(statistics, key=overlap_rate_key, reverse=True): 1335f9996aaSopenharmony_ci print('{:16}\t{:8}\t{:2.1f}%\t{:8}\t{:2.1f}%\t{:.2f}'.format( 1345f9996aaSopenharmony_ci item.get('subsystem'), item.get('files'), 1355f9996aaSopenharmony_ci item.get('files_percentage'), item.get('builds'), 1365f9996aaSopenharmony_ci item.get('builds_percentage'), item.get('overlap_rate'))) 1375f9996aaSopenharmony_ci print('\n{} overall build overlap rate: {:.2f}\n\n'.format( 1385f9996aaSopenharmony_ci program_language, 1395f9996aaSopenharmony_ci float(total_builds) / float(total_files))) 1405f9996aaSopenharmony_ci 1415f9996aaSopenharmony_ci 1425f9996aaSopenharmony_cidef main(): 1435f9996aaSopenharmony_ci parser = argparse.ArgumentParser() 1445f9996aaSopenharmony_ci parser.add_argument('--build-out-dir', help='base directory to analyze.') 1455f9996aaSopenharmony_ci parser.add_argument('--root-source-dir', help='source root directory.') 1465f9996aaSopenharmony_ci parser.add_argument( 1475f9996aaSopenharmony_ci '--subsystem-config-file', help='path to subsystem java targets.') 1485f9996aaSopenharmony_ci parser.add_argument( 1495f9996aaSopenharmony_ci '--subsystem-config-overlay-file', help='path to subsystem overlay java targets.') 1505f9996aaSopenharmony_ci 1515f9996aaSopenharmony_ci options = parser.parse_args() 1525f9996aaSopenharmony_ci 1535f9996aaSopenharmony_ci paths = get_subsystem_paths(options.subsystem_config_file, 1545f9996aaSopenharmony_ci os.path.realpath(options.root_source_dir)) 1555f9996aaSopenharmony_ci compute_overlap_rate_by_subsystem(options, paths, 'c') 1565f9996aaSopenharmony_ci compute_overlap_rate_by_subsystem(options, paths, 'java') 1575f9996aaSopenharmony_ci 1585f9996aaSopenharmony_ci 1595f9996aaSopenharmony_ciif __name__ == '__main__': 1605f9996aaSopenharmony_ci sys.exit(main()) 161