• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3# Copyright (c) 2022 Huawei Device Co., Ltd.
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8#     http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
16# This file contains a RomAnalyzer for rom analyzation of standard device.
17
18import argparse
19import json
20import os
21import sys
22import typing
23from copy import deepcopy
24from typing import *
25
26from pkgs.basic_tool import BasicTool
27from pkgs.gn_common_tool import GnCommonTool
28from pkgs.simple_excel_writer import SimpleExcelWriter
29
30debug = bool(sys.gettrace())
31
32NOTFOUND = "NOTFOUND"
33
34
35class RomAnalyzer:
36    @classmethod
37    def __collect_product_info(cls, system_module_info_json: Text,
38                               project_path: Text) -> Dict[Text, Dict[Text, Text]]:
39        """
40        根据system_module_info.json生成target字典
41        """
42        with open(system_module_info_json, 'r', encoding='utf-8') as f:
43            product_list = json.loads(f.read())
44        project_path = BasicTool.get_abs_path(project_path)
45        product_info_dict: Dict[Text, Dict[Text, Text]] = dict()
46        for unit in product_list:
47            dest: List = unit.get("dest")
48            if dest is None:
49                print("warning: keyword 'dest' not found in {}".format(
50                    system_module_info_json))
51                continue
52            label: Text = unit.get("label")
53            gn_path = component_name = subsystem_name = None
54            if label:
55                gn_path = os.path.join(project_path, label.split(':')[
56                                       0].lstrip('/'), "BUILD.gn")
57                component_name = unit.get("part_name")
58                subsystem_name = unit.get("subsystem_name")
59                if (not component_name) or (not subsystem_name):
60                    cn, sn = GnCommonTool.find_part_subsystem(
61                        gn_path, project_path)
62                    component_name = cn if not component_name else component_name
63                    subsystem_name = sn if not subsystem_name else subsystem_name
64            else:
65                print("warning: keyword 'label' not found in {}".format(unit))
66            for target in dest:
67                product_info_dict[target] = {
68                    "component_name": component_name,
69                    "subsystem_name": subsystem_name,
70                    "gn_path": gn_path,
71                }
72        return product_info_dict
73
74    @classmethod
75    def __save_result_as_excel(cls, result_dict: dict, output_name: str):
76        header = ["subsystem_name", "component_name",
77                  "output_file", "size(Byte)"]
78        tmp_dict = deepcopy(result_dict)
79        excel_writer = SimpleExcelWriter("rom")
80        excel_writer.set_sheet_header(headers=header)
81        subsystem_start_row = 1
82        subsystem_end_row = 0
83        subsystem_col = 0
84        component_start_row = 1
85        component_end_row = 0
86        component_col = 1
87
88        for subsystem_name in tmp_dict.keys():
89            subsystem_dict = tmp_dict.get(subsystem_name)
90            subsystem_size = subsystem_dict.get("size")
91            subsystem_file_count = subsystem_dict.get("file_count")
92            del subsystem_dict["file_count"]
93            del subsystem_dict["size"]
94            subsystem_end_row += subsystem_file_count
95
96            for component_name in subsystem_dict.keys():
97                component_dict: Dict[str, int] = subsystem_dict.get(
98                    component_name)
99                component_size = component_dict.get("size")
100                component_file_count = component_dict.get("file_count")
101                del component_dict["file_count"]
102                del component_dict["size"]
103                component_end_row += component_file_count
104
105                for file_name, size in component_dict.items():
106                    excel_writer.append_line(
107                        [subsystem_name, component_name, file_name, size])
108                excel_writer.write_merge(component_start_row, component_col, component_end_row, component_col,
109                                         component_name)
110                component_start_row = component_end_row + 1
111            excel_writer.write_merge(subsystem_start_row, subsystem_col, subsystem_end_row, subsystem_col,
112                                     subsystem_name)
113            subsystem_start_row = subsystem_end_row + 1
114        excel_writer.save(output_name + ".xls")
115
116    @classmethod
117    def __put(cls, unit: typing.Dict[Text, Any], result_dict: typing.Dict[Text, Dict]):
118        """
119        subsystem_name:{
120                component_name: {
121                    file_name: file_size
122                }
123            }
124        """
125        component_name = NOTFOUND if unit.get(
126            "component_name") is None else unit.get("component_name")
127        subsystem_name = NOTFOUND if unit.get(
128            "subsystem_name") is None else unit.get("subsystem_name")
129        size = unit.get("size")
130        relative_filepath = unit.get("relative_filepath")
131        if result_dict.get(subsystem_name) is None:  # 子系统
132            result_dict[subsystem_name] = dict()
133            result_dict[subsystem_name]["size"] = 0
134            result_dict[subsystem_name]["file_count"] = 0
135
136        if result_dict.get(subsystem_name).get(component_name) is None:  # 部件
137            result_dict[subsystem_name][component_name] = dict()
138            result_dict[subsystem_name][component_name]["size"] = 0
139            result_dict[subsystem_name][component_name]["file_count"] = 0
140        result_dict[subsystem_name]["size"] += size
141        result_dict[subsystem_name]["file_count"] += 1
142        result_dict[subsystem_name][component_name]["size"] += size
143        result_dict[subsystem_name][component_name]["file_count"] += 1
144        result_dict[subsystem_name][component_name][relative_filepath] = size
145
146    @classmethod
147    def analysis(cls, system_module_info_json: Text, product_dirs: List[str],
148                 project_path: Text, product_name: Text, output_file: Text, output_execel: bool):
149        """
150        system_module_info_json: json文件
151        product_dirs:要处理的产物的路径列表如["vendor", "system/"]
152        project_path: 项目根路径
153        product_name: eg,rk3568
154        output_file: basename of output file
155        """
156        project_path = BasicTool.get_abs_path(project_path)
157        phone_dir = os.path.join(
158            project_path, "out", product_name, "packages", "phone")
159        product_dirs = [os.path.join(phone_dir, d) for d in product_dirs]
160        product_info_dict = cls.__collect_product_info(
161            system_module_info_json, project_path)  # 所有产物信息
162        result_dict: Dict[Text:Dict] = dict()
163        for d in product_dirs:
164            file_list: List[Text] = BasicTool.find_all_files(d)
165            for f in file_list:
166                size = os.path.getsize(f)
167                relative_filepath = f.replace(phone_dir, "").lstrip(os.sep)
168                unit: Dict[Text, Any] = product_info_dict.get(
169                    relative_filepath)
170                if unit is None:
171                    unit = dict()
172                unit["size"] = size
173                unit["relative_filepath"] = relative_filepath
174                cls.__put(unit, result_dict)
175        output_dir, _ = os.path.split(output_file)
176        if len(output_dir) != 0:
177            os.makedirs(output_dir, exist_ok=True)
178        with open(output_file + ".json", 'w', encoding='utf-8') as f:
179            f.write(json.dumps(result_dict, indent=4))
180        if output_execel:
181            cls.__save_result_as_excel(result_dict, output_file)
182
183
184def get_args():
185    VERSION = 2.0
186    parser = argparse.ArgumentParser(
187        description=f"analyze rom size of component.\n")
188    parser.add_argument("-v", "-version", action="version",
189                        version=f"version {VERSION}")
190    parser.add_argument("-p", "--project_path", type=str, required=True,
191                        help="root path of openharmony. eg: -p ~/openharmony")
192    parser.add_argument("-j", "--module_info_json", required=True, type=str,
193                        help="path of out/{product_name}/packages/phone/system_module_info.json")
194    parser.add_argument("-n", "--product_name", required=True,
195                        type=str, help="product name. eg: -n rk3568")
196    parser.add_argument("-d", "--product_dir", required=True, action="append",
197                        help="subdirectories of out/{product_name}/packages/phone to be counted."
198                             "eg: -d system -d vendor")
199    parser.add_argument("-o", "--output_file", type=str, default="rom_analysis_result",
200                        help="basename of output file, default: rom_analysis_result. eg: demo/rom_analysis_result")
201    parser.add_argument("-e", "--excel", type=bool, default=False,
202                        help="if output result as excel, default: False. eg: -e True")
203    args = parser.parse_args()
204    return args
205
206
207if __name__ == '__main__':
208    args = get_args()
209    module_info_json = args.module_info_json
210    project_path = args.project_path
211    product_name = args.product_name
212    product_dirs = args.product_dir
213    output_file = args.output_file
214    output_excel = args.excel
215    RomAnalyzer.analysis(module_info_json, product_dirs,
216                         project_path, product_name, output_file, output_excel)
217