Tool: Update some new features and refinements
- Support name the output database file.
- Support input specific name database file.
- Fix the defect that delete all database file in the path.
- UI option and terminal options are conflicting now.
- Terminal messages are reversed, summary info shows at last.
- Support sort messages in terminal mode.
- Update help message and document.
- Other code and structure refinements.
Signed-off-by: Jianliang Shen <jianliang.shen@arm.com>
Change-Id: I597f05bebc4f20d316f400ed3d099bd9dbbd972a
diff --git a/code-size-analyze-tool/README.rst b/code-size-analyze-tool/README.rst
index add23e2..e9abcf2 100644
--- a/code-size-analyze-tool/README.rst
+++ b/code-size-analyze-tool/README.rst
@@ -24,7 +24,7 @@
.. code-block:: bash
- sudo apt-get install python3-dev libmysqlclient-dev libncursesw6 libncurses6
+ sudo apt-get install python3-dev libmysqlclient-dev libncursesw6 libncurses6 libsqlite3-dev
pip install mysqlclient XlsxWriter
Windows
@@ -44,56 +44,72 @@
.. code-block:: bash
- python3 code_size_analyze.py [-h] [-i MAP_FILE_INPUT] [-u]
- <--gnuarm|--armcc>
- [-a] [-s] [-l] [-o] [-f] [-d]
- [--dump_section SECTION_NAME]
- [--dump_library LIBRARY_NAME]
- [--dump_obj OBJ_NAME]
- [--dump_function DUMP_FUNCTION_NAME]
- [--dump_data DUMP_DATA_NAME]
- [--search_func FUNCTION_NAME]
- [--search_data DATA_NAME]
+ usage: code_size_analyze.py [-h] [--gnuarm | --armcc] [--db-name <data.db>]
+ [-u | -S | -s | -l | -o | -f | -d |
+ --dump-sec <sec> | --dump-lib <lib> |
+ --dump-obj <obj> | --dump-func <func> |
+ --dump-data <data> | --search-func <func> |
+ --search-data <data>]
+ [--sort-by-size | --sort-by-name |
+ --sort-by-obj | --sort-by-lib |
+ --sort-by-sec] [--desc | --asc]
+ file_input
- options:
- -h, --help show this help message and exit
- -i MAP_FILE_INPUT map file path <path>/tfm_s.map
- -u, --ui show UI
- --gnuarm gnuarm map file input
- --armcc armclang map file input
- -a, --all show total
- -s, --list_section list section
- -l, --list_library list library
- -o, --list_obj list object file
- -f, --list_function list function
- -d, --list_data list data
- --dump_section SECTION_NAME dump section
- --dump_library LIBRARY_NAME dump library
- --dump_obj OBJ_NAME dump object file
- --dump_function DUMP_FUNCTION_NAME dump function
- --dump_data DUMP_DATA_NAME dump data
- --search_func FUNCTION_NAME search function
- --search_data DATA_NAME search data
+ positional arguments:
+ file_input map or database file
+
+ optional arguments:
+ -h, --help show this help message and exit
+ --gnuarm GNUARM model
+ --armcc ARMCLANG model
+ --db-name <data.db> database name to save
+ -u, --ui start UI to analyze
+ -S, --Summary show summary message
+ -s, --list-section list section
+ -l, --list-library list library
+ -o, --list-obj list object file
+ -f, --list-function list function
+ -d, --list-data list data
+ --dump-sec <sec> dump section
+ --dump-lib <lib> dump library
+ --dump-obj <obj> dump object file
+ --dump-func <func> dump function
+ --dump-data <data> dump data
+ --search-func <func> search function
+ --search-data <data> search data
+ --sort-by-size list by size order
+ --sort-by-name list by name order
+ --sort-by-obj list by object file name order
+ --sort-by-lib list by library file name order
+ --sort-by-sec list by section name order
+ --desc sort with desc order
+ --asc sort with asc order
Create database
===============
It is required to input map file path for the script before show the UI. One of
-the options like ``--gnuarm`` or ``--armcc`` is required. Keep the compiler
-option same from the beginning to the end.
+the options like ``--gnuarm`` or ``--armcc`` is required.
+
+The default database name created is ``data.db``. Use ``--db-name`` to name the
+output file if necessary. For example, saving two different databases to compare
+later.
.. code-block:: bash
- python3 code_size_analyze.py -i MAP_FILE_INPUT <--gnuarm|--armcc>
+ $: python code_size_analyze.py tfm_s.map <--gnuarm|--armcc> --db-name tfm_s.db
-Show the UI
-===========
+UI mode
+=======
The script ui.py supplies a menu to choose what developers may be interested.
+You can enter UI mode by analyzing map file directly or by importing database
+file path. The latter way is suggested as it runs more quickly.
.. code-block:: bash
- python3 code_size_analyze.py -u <--gnuarm|--armcc>
+ $: python code_size_analyze.py tfm_s.map <--gnuarm|--armcc> -u
+ $: python code_size_analyze.py tfm_s.db -u
There are several keys to use UI.
@@ -106,56 +122,111 @@
* ``s`` or ``S``: Enter output file name to save the content of current page.
* ``:`` : Start search and enter the function or data name.
+Terminal mode
+=============
+
+In terminal mode, it is better to analyze database file rather than map file.
+
Dump detail information
-=======================
+-----------------------
You can get the list of all sections, libraries, object files, functions or
data. You can also dump the specific symbol with the name.
.. code-block:: bash
- python3 code_size_analyze.py <--gnuarm|--armcc> -s
- python3 code_size_analyze.py <--gnuarm|--armcc> --dump_section SECTION_NAME
+ $: python code_size_analyze.py tfm_s.map --armcc --db-name test.db -S
+ ───────────────────────────────────────────────
+ Code size : 56676 55.35 KB
+ -----------------------------------------------
+ RO data : 3732 3.64 KB
+ RW data : 204 0.20 KB
+ ZI data : 24588 24.01 KB
+ Flash size : 60612 59.19 KB = Code + RO + RW
+ RAM size : 24792 24.21 KB = RW + ZI
+ ───────────────────────────────────────────────
+ $: python code_size_analyze.py tfm_s.db -s
+ $: python code_size_analyze.py tfm_s.db --dump-sec <sec>
Search specific function or data
-================================
+--------------------------------
You can search the target with keyword in command line. For example:
.. code-block:: bash
- python3 code_size_analyze.py <--gnuarm|--armcc> --search_func FUNCTION_NAME
- python3 code_size_analyze.py <--gnuarm|--armcc> --search_data DATA_NAME
+ $: python code_size_analyze.py tfm_s.db --search-func <func>
+ $: python code_size_analyze.py tfm_s.db --search-data <data>
+
+Sort Table
+----------
+
+You can sort the messages in terminal mode. The script supplies five options and
+two orders. For example:
+
+.. code-block:: bash
+
+ $: python code_size_analyze.py tfm_s.db -l --sort-by-size --asc
+ ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
+ Name Flash size RAM size Code RO data RW data ZI data Inc. data Debug
+ --------------------------------------------------------------------------------------------------------------------------------------------------
+ libtfm_qcbor_s.a 758 0 758 0 0 0 4 17046
+ libtfm_sprt.a 1016 0 1016 0 0 0 0 41004
+ c_w.l 1248 96 1248 0 0 96 86 1892
+ libtfm_psa_rot_partition_attestation.a 2497 557 2492 5 0 557 68 51865
+ libtfm_spm.a 4112 657 3932 136 44 613 168 52958
+ libtfm_psa_rot_partition_its.a 5090 116 5030 32 28 88 28 49804
+ libtfm_psa_rot_partition_crypto.a 6062 3232 6062 0 0 3232 36 92472
+ libplatform_s.a 6486 316 5582 780 124 192 404 94887
+ libmbedcrypto.a 28408 2292 26138 2262 8 2284 1066 226489
+ ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
+
+Not all symbols support to be sorted by the whole five options, refer to the
+table to get more information.
+
++----------------+---------+---------+--------------+----------+------+
+| Options | Section | Library | Object files | Function | Data |
++================+=========+=========+==============+==========+======+
+| --sort-by-size | √ | √ | √ | √ | √ |
++----------------+---------+---------+--------------+----------+------+
+| --sort-by-name | √ | √ | √ | √ | √ |
++----------------+---------+---------+--------------+----------+------+
+| --sort-by-sec | √ | | | √ | √ |
++----------------+---------+---------+--------------+----------+------+
+| --sort-by-lib | | √ | √ | √ | √ |
++----------------+---------+---------+--------------+----------+------+
+| --sort-by-obj | | | √ | √ | √ |
++----------------+---------+---------+--------------+----------+------+
*******************
Code size diff tool
*******************
Use ``code_size_diff.py`` to diff two diffrent build results with same compiler.
-Firstly, use ``code_size_analyze.py`` to prepare two different databases. For
-example:
.. code-block:: bash
- usage: code_size_diff.py [-h] -i [input_dbs [input_dbs ...]]
- [-a] [-f] [-d] [-o] [-l]
+ usage: code_size_diff.py [-h] (-S | -f | -d | -o | -l) based_db compared_db
+
+ positional arguments:
+ based_db based databse
+ compared_db compared databse
optional arguments:
- -h, --help show this help message and exit
- -i [input_dbs [input_dbs ...]], --input [input_dbs [input_dbs ...]]
- Input two different data base files
- -a, --diff_all diff summary
- -f, --diff_function diff function
- -d, --diff_data diff data
- -o, --diff_obj diff object file
- -l, --diff_lib diff library
+ -h, --help show this help message and exit
+ -S, --diff-Summary diff summary
+ -f, --diff-function diff function
+ -d, --diff-data diff data
+ -o, --diff-obj diff object file
+ -l, --diff-lib diff library
-Then compare two database with the diff tool, the branch1 is base.
+Firstly, use ``code_size_analyze.py`` to prepare two different databases. Then
+compare two database with the diff tool, the branch1 is base.
.. code-block:: bash
- python3 code_size_diff.py -i output/branch1.db output/branch2.db -a
+ $: python code_size_diff.py output/branch1.db output/branch2.db -S
Code size: +++ 48928 B 47.78 KB
RO data: +++ 29440 B 28.75 KB
RW data: --- 64 B 0.06 KB
@@ -163,9 +234,6 @@
Flash size: +++ 78304 B 76.47 KB
RAM size: --- 564 B 0.55 KB
-The summary information change will be printed. Enter ``-h`` to get more usages
-of diff tool.
-
--------------
*Copyright (c) 2021-2022, Arm Limited. All rights reserved.*
diff --git a/code-size-analyze-tool/code_size_analyze.py b/code-size-analyze-tool/code_size_analyze.py
index 4aa6763..ef914f2 100644
--- a/code-size-analyze-tool/code_size_analyze.py
+++ b/code-size-analyze-tool/code_size_analyze.py
@@ -8,94 +8,168 @@
import argparse
import os
import sys
+import glob
sys.path.append("src")
from ui import UI
from sq import SQ
-none_databse = "Cannot find database file! Please use this command to create \
-databse:\n\n\tpython3 code_size_analyze.py -i <map file path> --gnuarm/--armcc\n"
+none_databse = "Cannot find database {}! Please use this command to create \
+databse:\n\n\tpython3 code_size_analyze.py --map <map file path> \
+--gnuarm/--armcc --db {}\n"
+
+def reverse_terminal_text(items):
+ line1 = "─" * 128
+ tmp, ret = [], []
+ for x in items:
+ if x == line1:
+ ret.append(tmp)
+ tmp = []
+ tmp.append(x)
+ items = []
+ for i in range(len(ret) - 1, -1, -1):
+ items.extend(ret[i])
+ items.append(line1)
+ return items
def main(args):
- """
- It is required to input only one of '--gnuarm' and '--armcc'.
- """
- if (args.gnuarm_compiler and args.armclang_compiler) or \
- (not args.gnuarm_compiler and not args.armclang_compiler):
- print("Error: Need \'--gnuarm\' or \'--armcc\'")
- exit(0)
-
+ map_file, db_file = "", ""
+ if args.file_input.find(".map") >= 0:
+ map_file = args.file_input
+ else:
+ db_file = args.file_input
"""
Class 'sq' is to create a sqlite3 database from map file of compiler.
"""
- if args.map_file_input:
+ if map_file:
+ if not args.gnuarm_compiler and not args.armclang_compiler:
+ print("Error: Need --gnuarm or --armcc to create database")
+ exit(0)
+ if os.path.exists(args.db_name):
+ for infile in glob.glob(os.path.join(os.getcwd(), args.db_name)):
+ os.remove(infile)
sq = SQ()
sq.gnuarm = True if args.gnuarm_compiler else False
sq.armcc = True if args.armclang_compiler else False
- sq.file_path = args.map_file_input
+ sq.map_file = map_file
+ sq.db_name = args.db_name
sq.update()
- if os.path.exists('data.db'):
+ if (db_file and os.path.exists(db_file)) or (map_file and os.path.exists(args.db_name)):
"""
Class 'ui' is to show the ui in terminal or export plaintext.
"""
ui = UI()
ui.gnuarm = True if args.gnuarm_compiler else False
ui.armcc = True if args.armclang_compiler else False
- output = ""
+ if db_file:
+ ui.db_file = db_file
+ if map_file:
+ ui.db_file = args.db_name
+ ui.open_db()
+ if args.sort_by_size:
+ ui.sort = "size"
+ if args.sort_by_name:
+ ui.sort = "name"
+ if args.sort_by_obj:
+ ui.sort = "obj_file"
+ if args.sort_by_lib:
+ ui.sort = "lib_file"
+ if args.sort_by_sec:
+ ui.sort = "section"
+
+ if args.desc:
+ ui.order = "DESC"
+ if args.asc:
+ ui.order = "ASC"
+
if args.ui_show:
+ if args.sort_by_name or args.sort_by_obj or args.sort_by_lib or args.sort_by_sec:
+ print("UI mode cannot support sort. Use it in terminal mode.")
+ exit(0)
ui.run()
- else:
- if args.all:
- ui.draw_summary_page()
- if args.list_function:
- ui.draw_function_page("")
+ if args.all:
+ ui.draw_summary_page()
- if args.function_name:
- ui.draw_function_page(args.function_name)
+ if args.list_function:
+ ui.draw_function_page("")
- if args.dump_function_name:
- ui.function_name = args.dump_function_name
- ui.draw_function_detail_page()
+ if args.function_name:
+ ui.draw_function_page(args.function_name)
- if args.list_data:
- ui.draw_data_page("")
+ if args.dump_function_name:
+ ui.function_name = args.dump_function_name
+ ui.draw_function_detail_page()
- if args.data_name:
- ui.draw_data_page(args.data_name)
+ if args.list_data:
+ ui.draw_data_page("")
- if args.dump_data_name:
- ui.data_name = args.dump_data_name
- ui.draw_data_detail_page()
+ if args.data_name:
+ ui.draw_data_page(args.data_name)
- if args.list_obj:
- ui.draw_obj_page()
+ if args.dump_data_name:
+ ui.data_name = args.dump_data_name
+ ui.draw_data_detail_page()
- if args.obj_name:
- ui.obj_file = args.obj_name
- ui.draw_obj_detail_page()
+ if args.list_obj:
+ if args.sort_by_obj:
+ ui.sort = "name"
+ if args.sort_by_sec:
+ print("Object files cannot sort by this option")
+ exit(0)
+ ui.draw_obj_page()
- if args.list_library:
- ui.draw_library_page()
+ if args.obj_name:
+ ui.obj_file = args.obj_name
+ ui.draw_obj_detail_page()
+ ui.items = reverse_terminal_text(ui.items)
- if args.library_name:
- ui.library_name = args.library_name
- ui.draw_library_detail_page()
+ if args.list_library:
+ if args.sort_by_lib:
+ ui.sort = "name"
+ if args.sort_by_obj or args.sort_by_sec:
+ print("Libraries cannot sort by this option")
+ exit(0)
+ ui.draw_library_page()
- if args.list_section:
- ui.draw_section_page()
+ if args.library_name:
+ if args.sort_by_sec or args.sort_by_obj:
+ print("Library dump cannot sort by this option")
+ exit(0)
+ ui.library_name = args.library_name
+ ui.draw_library_detail_page()
+ ui.items = reverse_terminal_text(ui.items)
- if args.section_name:
- ui.section_name = args.section_name
- ui.draw_section_lib()
+ if args.list_section:
+ if args.sort_by_sec:
+ ui.sort = "name"
+ if args.sort_by_lib or args.sort_by_obj:
+ print("Sections cannot sort by this option")
+ exit(0)
+ ui.draw_section_page()
- output = ui.items
- if output:
- for s in output:
- print(s)
- ui.con.close()
+ if args.section_name:
+ if args.sort_by_name or args.sort_by_obj or args.sort_by_lib or args.sort_by_sec:
+ print("Section dump cannot support sort.")
+ exit(0)
+ ui.section_name = args.section_name
+ ui.draw_section_lib()
+ ui.items = reverse_terminal_text(ui.items)
+
+ if "─" * 128 not in ui.items and "-" * 128 not in ui.items and ui.items:
+ max_len = 0
+ for x in ui.items:
+ max_len = max(max_len, len(x))
+ ui.items.insert(1, "-" * max_len)
+ ui.items.insert(0, "─" * max_len)
+ ui.items.append("─" * max_len)
+
+ if ui.items and not args.ui_show:
+ for s in ui.items:
+ print(s)
+
else:
- print(none_databse)
+ print(none_databse.format(db_file, db_file))
def parse_args():
"""
@@ -103,66 +177,120 @@
"""
parser = argparse.ArgumentParser()
- parser.add_argument('-i', '--input',
- dest='map_file_input',
- help='map file path <path>/tfm_s.map')
- parser.add_argument('-u', '--ui',
- dest='ui_show',
- action='store_true',
- help='show UI')
- parser.add_argument('--gnuarm',
- dest='gnuarm_compiler',
- action='store_true',
- help='gnuarm map file input')
- parser.add_argument('--armcc',
- dest='armclang_compiler',
- action='store_true',
- help='armclang map file input')
- parser.add_argument('-a', '--all',
- dest='all',
- action='store_true',
- help='show total')
- parser.add_argument('-s', '--list_section',
- dest='list_section',
- action='store_true',
- help='list section')
- parser.add_argument('-l', '--list_library',
- dest='list_library',
- action='store_true',
- help='list library')
- parser.add_argument('-o', '--list_obj',
- dest='list_obj',
- action='store_true',
- help='list object file')
- parser.add_argument('-f', '--list_function',
- dest='list_function',
- action='store_true',
- help='list function')
- parser.add_argument('-d', '--list_data',
- dest='list_data',
- action='store_true',
- help='list data')
- parser.add_argument('--dump_section',
- dest='section_name',
- help='dump section')
- parser.add_argument('--dump_library',
- dest='library_name',
- help='dump library')
- parser.add_argument('--dump_obj',
- dest='obj_name',
- help='dump object file')
- parser.add_argument('--dump_function',
- dest='dump_function_name',
- help='dump function')
- parser.add_argument('--dump_data',
- dest='dump_data_name',
- help='dump data')
- parser.add_argument('--search_func',
- dest='function_name',
- help='search function')
- parser.add_argument('--search_data',
- dest='data_name',
- help='search data')
+ compiler_group = parser.add_mutually_exclusive_group()
+ compiler_group.add_argument('--gnuarm',
+ dest='gnuarm_compiler',
+ action='store_true',
+ help='GNUARM model')
+ compiler_group.add_argument('--armcc',
+ dest='armclang_compiler',
+ action='store_true',
+ help='ARMCLANG model')
+
+ parser.add_argument('file_input', help='map or database file')
+ parser.add_argument('--db-name',
+ dest='db_name',
+ metavar='<data.db>',
+ default='data.db',
+ help='database name to save')
+
+ terminal_opt = parser.add_mutually_exclusive_group()
+ terminal_opt.add_argument('-u', '--ui',
+ dest='ui_show',
+ action='store_true',
+ help='start UI to analyze')
+ terminal_opt.add_argument('-S', '--Summary',
+ dest='all',
+ action='store_true',
+ help='show summary message')
+ terminal_opt.add_argument('-s', '--list-section',
+ dest='list_section',
+ action='store_true',
+ help='list section')
+ terminal_opt.add_argument('-l', '--list-library',
+ dest='list_library',
+ action='store_true',
+ help='list library')
+ terminal_opt.add_argument('-o', '--list-obj',
+ dest='list_obj',
+ action='store_true',
+ help='list object file')
+ terminal_opt.add_argument('-f', '--list-function',
+ dest='list_function',
+ action='store_true',
+ help='list function')
+ terminal_opt.add_argument('-d', '--list-data',
+ dest='list_data',
+ action='store_true',
+ help='list data')
+ terminal_opt.add_argument('--dump-sec',
+ dest='section_name',
+ metavar='<sec>',
+ help='dump section')
+ terminal_opt.add_argument('--dump-lib',
+ dest='library_name',
+ metavar='<lib>',
+ help='dump library')
+ terminal_opt.add_argument('--dump-obj',
+ dest='obj_name',
+ metavar='<obj>',
+ help='dump object file')
+ terminal_opt.add_argument('--dump-func',
+ dest='dump_function_name',
+ metavar='<func>',
+ help='dump function')
+ terminal_opt.add_argument('--dump-data',
+ dest='dump_data_name',
+ metavar='<data>',
+ help='dump data')
+ terminal_opt.add_argument('--search-func',
+ dest='function_name',
+ metavar='<func>',
+ help='search function')
+ terminal_opt.add_argument('--search-data',
+ dest='data_name',
+ metavar='<data>',
+ help='search data')
+
+ sort_opt = parser.add_mutually_exclusive_group()
+ sort_opt.add_argument('--sort-by-size',
+ dest='sort_by_size',
+ action='store_true',
+ default=True,
+ help='list by size order')
+ sort_opt.add_argument('--sort-by-name',
+ dest='sort_by_name',
+ action='store_true',
+ default=False,
+ help='list by name order')
+ sort_opt.add_argument('--sort-by-obj',
+ dest='sort_by_obj',
+ action='store_true',
+ default=False,
+ help='list by object file name order')
+ sort_opt.add_argument('--sort-by-lib',
+ dest='sort_by_lib',
+ action='store_true',
+ default=False,
+ help='list by library file name order')
+ sort_opt.add_argument('--sort-by-sec',
+ dest='sort_by_sec',
+ action='store_true',
+ default=False,
+ help='list by section name order')
+
+ sort_ord = parser.add_mutually_exclusive_group()
+ sort_ord.add_argument('--desc',
+ dest='desc',
+ action='store_true',
+ default=True,
+ help='sort with desc order')
+ sort_ord.add_argument('--asc',
+ dest='asc',
+ action='store_true',
+ default=False,
+ help='sort with asc order')
+
args = parser.parse_args()
return args
diff --git a/code-size-analyze-tool/code_size_diff.py b/code-size-analyze-tool/code_size_diff.py
index ffd4d84..9459ba0 100644
--- a/code-size-analyze-tool/code_size_diff.py
+++ b/code-size-analyze-tool/code_size_diff.py
@@ -83,7 +83,7 @@
print("{:<50}{:<10}{:<10}{:<50}".format(
s['name'], s['sign'], s['delta'], s['obj']))
print("─" * 120)
- print("Total Function Size cahnge = {:<6} B\t= {:<8.2f} KB".format(
+ print("Total Function Size change = {:<6} B\t= {:<8.2f} KB".format(
total_code_change, total_code_change/1024))
print("─" * 120)
@@ -314,14 +314,14 @@
def main(args):
global con1, cur1, con2, cur2
- if args.input_dbs:
- if len(args.input_dbs) == 2:
- con1 = sqlite3.connect(args.input_dbs[0])
- cur1 = con1.cursor()
- con2 = sqlite3.connect(args.input_dbs[1])
- cur2 = con2.cursor()
- else:
- print("Error! Two database files shall be input.")
+
+ if args.based_db and args.compared_db:
+ con1 = sqlite3.connect(args.based_db)
+ cur1 = con1.cursor()
+ con2 = sqlite3.connect(args.compared_db)
+ cur2 = con2.cursor()
+ else:
+ print("Error! Two database files shall be input.")
if args.diff_function:
diff_function()
if args.diff_data:
@@ -342,32 +342,29 @@
def parse_args():
parser = argparse.ArgumentParser()
- parser.add_argument('-i', '--input',
- dest='input_dbs',
- nargs='*',
- required=True,
- metavar='input_dbs',
- help='Input two different data base files')
- parser.add_argument('-a', '--diff_all',
- dest='diff_all',
- action='store_true',
- help='diff summary')
- parser.add_argument('-f', '--diff_function',
- dest='diff_function',
- action='store_true',
- help='diff function')
- parser.add_argument('-d', '--diff_data',
- dest='diff_data',
- action='store_true',
- help='diff data')
- parser.add_argument('-o', '--diff_obj',
- dest='diff_obj',
- action='store_true',
- help='diff object file')
- parser.add_argument('-l', '--diff_lib',
- dest='diff_lib',
- action='store_true',
- help='diff library')
+ parser.add_argument('based_db', help='based databse')
+ parser.add_argument('compared_db', help='compared databse')
+ opt = parser.add_mutually_exclusive_group(required=True)
+ opt.add_argument('-S', '--diff-Summary',
+ dest='diff_all',
+ action='store_true',
+ help='diff summary')
+ opt.add_argument('-f', '--diff-function',
+ dest='diff_function',
+ action='store_true',
+ help='diff function')
+ opt.add_argument('-d', '--diff-data',
+ dest='diff_data',
+ action='store_true',
+ help='diff data')
+ opt.add_argument('-o', '--diff-obj',
+ dest='diff_obj',
+ action='store_true',
+ help='diff object file')
+ opt.add_argument('-l', '--diff-lib',
+ dest='diff_lib',
+ action='store_true',
+ help='diff library')
args = parser.parse_args()
return args
diff --git a/code-size-analyze-tool/src/sq.py b/code-size-analyze-tool/src/sq.py
index 11f620a..039563a 100644
--- a/code-size-analyze-tool/src/sq.py
+++ b/code-size-analyze-tool/src/sq.py
@@ -6,8 +6,6 @@
# ------------------------------------------------------------------------------
import sqlite3
-import os
-import glob
from xlsxwriter.workbook import Workbook
class SQ(object):
@@ -22,7 +20,8 @@
- Variables:
- SQ().armcc - ARMCLANG option.
- SQ().gnuarm - GNUARM option.
- - SQ().file_path - The map file path which detail information comes from.
+ - SQ().map_file - The map file path which detail information comes from.
+ - SQ().db_name - The database file name to be saved.
"""
def __init__(self):
"""
@@ -30,27 +29,20 @@
"""
self.gnuarm = False
self.armcc = False
- self.file_path = ""
+ self.map_file = ""
+ self.db_name = ""
self.__gnuarm_info = []
self.__sec_dict = {}
- self.__delete()
- self.__con = sqlite3.connect("data.db")
- self.__cur = self.__con.cursor()
-
- def __delete(self):
- """
- Search and delete the previous database file and excel file.
- """
- for infile in glob.glob(os.path.join(os.getcwd(), '*.db')):
- os.remove(infile)
- for infile in glob.glob(os.path.join(os.getcwd(), '*.xlsx')):
- os.remove(infile)
+ self.__excel_name = ""
def __new(self):
"""
Create tables in a new empty database.
"""
+ self.__con = sqlite3.connect(self.db_name)
+ self.__cur = self.__con.cursor()
+ self.__excel_name = self.db_name +'.xlsx'
self.__cur.execute('''create table Summary
(Code INT NOT NULL,
RO_data INT NOT NULL,
@@ -82,7 +74,7 @@
lib_file TEXT NOT_NULL);''')
self.__cur.execute('''create table Library
(name TEXT NOT NULL,
- flashsize INT NOT NULL,
+ size INT NOT NULL,
ramsize INT NOT NULL,
code INT NOT NULL,
rodata INT NOT NULL,
@@ -92,8 +84,8 @@
Debug INT NOT NULL);''')
self.__cur.execute('''create table Object
(name TEXT NOT NULL,
- library TEXT NOT NULL,
- flashsize INT NOT NULL,
+ lib_file TEXT NOT NULL,
+ size INT NOT NULL,
ramsize INT NOT NULL,
code INT NOT NULL,
rodata INT NOT NULL,
@@ -101,6 +93,9 @@
zidata INT NOT NULL,
incdata INT NOT_NULL,
Debug INT NOT NULL);''')
+ self.__cur.execute('''create table Compiler
+ (Compiler TEXT NOT NULL,
+ flag INT NOT NULL);''')
if self.gnuarm:
self.__cur.execute('''create table Unknown
(name TEXT NOT NULL,
@@ -111,6 +106,12 @@
obj_file TEXT NOT_NULL,
lib_file TEXT NOT_NULL);''')
+ def __collect_compiler(self):
+ if self.gnuarm:
+ self.__cur.execute("insert into Compiler values (?, ?)", ("gnuarm", 1))
+ if self.armcc:
+ self.__cur.execute("insert into Compiler values (?, ?)", ("armcc", 0))
+
def __collect_summary(self):
code_size = ro_data = rw_data = zi_data = flash_size = ram_size = extra_ram = extra_flash = 0
if self.gnuarm:
@@ -150,7 +151,7 @@
"""
For Secure image, the TFM_DATA part is loaded from Flash.
"""
- for line in open(self.file_path, "r"):
+ for line in open(self.map_file, "r"):
if line.find("load address") >= 0:
extra_flash_addr = int(line.split()[-1] ,16)
extra_flash_data = int(line.split()[-4], 16)
@@ -158,7 +159,7 @@
flash_size += extra_flash_data
elif self.armcc:
- for line in open(self.file_path, "r"):
+ for line in open(self.map_file, "r"):
if line.find("gram Size: Code=") > 0:
content = line.split()
code_size = int(content[2].split('=')[1])
@@ -208,7 +209,7 @@
section_addr = ""
section_size = 0
section_pad_size = 0
- for line in open(self.file_path, "r"):
+ for line in open(self.map_file, "r"):
line_idx += 1
if line.find("Execution Region") > 0:
@@ -284,7 +285,7 @@
elif self.armcc:
line_idx, line_start = 0, 0
- for line in open(self.file_path, "r"):
+ for line in open(self.map_file, "r"):
line_idx += 1
if line.find("Code (inc. data) RO Data RW Data ZI Data Debug Library Name") > 0:
line_start = line_idx + 1
@@ -325,7 +326,7 @@
0, 0))
elif self.armcc:
line_idx, line_start = 0, 0
- for line in open(self.file_path, "r"):
+ for line in open(self.map_file, "r"):
line_idx += 1
if line.find("Code (inc. data) RO Data RW Data ZI Data Debug Object Name") > 0:
line_start = line_idx + 1
@@ -346,7 +347,7 @@
else:
break
line_idx, line_start = 0, 0
- for line in open(self.file_path, "r"):
+ for line in open(self.map_file, "r"):
line_idx += 1
if line.find("Code (inc. data) RO Data RW Data ZI Data Debug Library Member Name") > 0:
line_start = line_idx + 1
@@ -355,7 +356,7 @@
if len(content) == 7:
obj_name = content[6]
library_file = ""
- for line in open(self.file_path, "r"):
+ for line in open(self.map_file, "r"):
if line.find(obj_name) > 0:
ch_r = line[line.find(obj_name) + len(obj_name)]
ch_l = line[line.find(obj_name) - 1]
@@ -379,7 +380,7 @@
def __get_ram_and_flash_start_addr(self):
start = False
- for line in open(self.file_path, "r"):
+ for line in open(self.map_file, "r"):
if line.find('Memory Configuration') >= 0:
start = True
if line.find('Linker script and memory map') == 0:
@@ -397,7 +398,7 @@
def get_key_content():
start, end, real_start = False, False, False
content = ""
- for line in open(self.file_path, "r"):
+ for line in open(self.map_file, "r"):
if line.find('Linker script and memory map') >= 0:
start = True
if line.find('OUTPUT(') == 0:
@@ -558,7 +559,7 @@
table_list = ["Summary", "Section", "Library", "Object", "Function", "Data"]
if self.gnuarm:
table_list.append("Unknown")
- workbook = Workbook('data.xlsx')
+ workbook = Workbook(self.__excel_name)
title_m = workbook.add_format({'bold': True,
'align': 'left',
'font_size': 12})
@@ -603,6 +604,7 @@
self.__new()
if self.gnuarm:
self.__get_info_from_gnuarm_map()
+ self.__collect_compiler()
self.__collect_summary()
self.__collect_section()
self.__collect_library()
diff --git a/code-size-analyze-tool/src/ui.py b/code-size-analyze-tool/src/ui.py
index e555e59..6b5a704 100644
--- a/code-size-analyze-tool/src/ui.py
+++ b/code-size-analyze-tool/src/ui.py
@@ -20,6 +20,7 @@
- Methods:
- UI().run() - Run the UI in terminal.
- UI.draw_<symbol>_page() - Get the information of specific symbol
+ - UI.open_db() - Open database.
- Variables:
- UI().items - The result searched from database.
@@ -31,6 +32,9 @@
- UI().section_name - Specific section name.
- UI().library_name - Specific library name.
- UI().obj_file - Specific object file name.
+ - UI().db_file - Database file.
+ - UI().sort - Database list order: size, name and so on.
+ - UI().order - Database sort order: DESC and ASC.
"""
def __init__(self):
@@ -45,9 +49,10 @@
self.gnuarm = False
self.armcc = False
self.items = []
- self.con = sqlite3.connect("data.db")
+ self.db_file = ""
+ self.sort = "size"
+ self.order = "DESC"
- self.__cur = self.con.cursor()
self.__window = None
self.__width = 0
self.__height = 0
@@ -62,6 +67,17 @@
self.__cmd_func="Enter the function name:"
self.__cmd_data="Enter the data name:"
+ def open_db(self):
+ self.con = sqlite3.connect(self.db_file)
+ self.__cur = self.con.cursor()
+ cursor = self.__cur.execute("select * from Compiler")
+ for row in cursor:
+ compiler = row[1]
+ if compiler == 1:
+ self.gnuarm = True
+ elif compiler == 0:
+ self.armcc = True
+
def __init_curses(self):
"""
Setup the curses
@@ -413,7 +429,7 @@
self.items = ["{:<50}{:<16}{:<16}{:<16}".
format("Name", "Size", "Address", "PAD size")]
- cursor = self.__cur.execute("select * from Section ORDER BY size DESC")
+ cursor = self.__cur.execute("select * from Section ORDER BY {} {}".format(self.sort, self.order))
for row in cursor:
self.items.append("{:<50}{:<16}{:<16}{:<16}".
format(row[0], row[1], row[2], row[3]))
@@ -559,7 +575,7 @@
Dump library information.
"""
self.items = [self.__line1]
- insert_column_line("\t\t\t\t\t\t\tSection libraries")
+ insert_column_line(" " * ((128 - len("Section libraries"))//2) + "Section libraries")
for s in lib_list:
if s['Name'].find(".o") > 0:
exsit_no_lib_obj = True
@@ -571,7 +587,7 @@
"""
Dump object file information.
"""
- insert_column_line("\t\t\t\t\t\t\tSection object files")
+ insert_column_line(" " * ((128 - len("Section object files"))//2) + "Section object files")
for s in obj_list:
quick_insert_data_line(s)
ret = sum_data(obj_list)
@@ -581,8 +597,8 @@
Dump NOT-IN-LIBRARY object file information.
"""
if exsit_no_lib_obj:
- insert_column_line(
- "\t\t\t\t\t\t\tSection NOT-IN-LIBRARY object files")
+ insert_column_line(" " * ((128 - len("Section NOT-IN-LIBRARY object files"))//2) +
+ "Section NOT-IN-LIBRARY object files")
tmp_list = []
for s in lib_list:
if s['Name'].find(".o") > 0:
@@ -600,14 +616,14 @@
format(self.section_name, row[1], total_flash_size, total_ram_size, row[3]))
break
self.items.insert(0, self.__line2)
- self.items.insert(0, "\t\t\t\t\t\t\tSection information")
+ self.items.insert(0, " " * ((128 - len("Section information"))//2) + "Section information")
self.items.insert(0, self.__line1)
"""
Dump detail information of the section.
"""
index = 4 * ' '
- self.items.append("\t\t\t\t\t\t\tDetail information")
+ self.items.append(" " * ((128 - len("Detail information"))//2) + "Detail information")
self.items.append(self.__line2)
for s in lib_list:
self.items.append("{} Code Size = {} RO Data = {} RW Data = {} ZI Data = {}".
@@ -617,10 +633,12 @@
self.items.append(index + "{} Code Size = {} RO Data = {} RW Data = {} ZI Data = {}".format(
t['Name'], t['Code'], t['RO'], t['RW'], t['ZI']))
count = 0
- cursor = self.__cur.execute("select * from Function WHERE section = '{}' and lib_file = '{}' and obj_file = '{}' ORDER BY size DESC".
+ cursor = self.__cur.execute("select * from Function WHERE section = '{}' and lib_file = '{}' and obj_file = '{}' ORDER BY {} {}".
format(self.section_name,
s['Name'],
- t['Name']))
+ t['Name'],
+ self.sort,
+ self.order))
for row in cursor:
if row and count == 0:
self.items.append(index * 2 + "Code size = {}".
@@ -631,11 +649,13 @@
def get_certain_data(type_name, s, t):
count = 0
- cursor = self.__cur.execute("select * from Data WHERE section = '{}' and lib_file = '{}' and obj_file = '{}' and type = '{}' ORDER BY size DESC".
+ cursor = self.__cur.execute("select * from Data WHERE section = '{}' and lib_file = '{}' and obj_file = '{}' and type = '{}' ORDER BY {} {}".
format(self.section_name,
s['Name'],
t['Name'],
- type_name))
+ type_name,
+ self.sort,
+ self.order))
for row in cursor:
if row and count == 0:
self.items.append(index * 2 + "{} Data = {}".
@@ -648,6 +668,7 @@
get_certain_data('RW', s, t)
get_certain_data('ZI', s, t)
self.items.append(self.__line2)
+ self.items[-1] = self.__line1
def draw_section_func(self):
self.items = ["{:<50}{:<32}{:<10}{:<16}{:<40}{:<40}".
@@ -657,8 +678,8 @@
"Address",
"Object File",
"Library")]
- cursor = self.__cur.execute("select * from Function WHERE section = '{}' ORDER BY size DESC".
- format(self.section_name))
+ cursor = self.__cur.execute("select * from Function WHERE section = '{}' ORDER BY {} {}".
+ format(self.section_name, self.sort, self.order))
for row in cursor:
self.items.append("{:<50}{:<32}{:<10}{:<16}{:<40}{:<40}".
format(row[0], row[1], row[2], row[3], row[4], row[5]))
@@ -673,8 +694,8 @@
"Object File",
"Library")]
- cursor = self.__cur.execute("select * from Data WHERE section = '{}' ORDER BY size DESC".
- format(self.section_name))
+ cursor = self.__cur.execute("select * from Data WHERE section = '{}' ORDER BY {} {}".
+ format(self.section_name, self.sort, self.order))
for row in cursor:
data_name = row[0]
if len(data_name) >= 50:
@@ -718,7 +739,7 @@
"Debug")]
cursor = self.__cur.execute(
- "select * from Library ORDER BY flashsize DESC")
+ "select * from Library ORDER BY {} {}".format(self.sort, self.order))
for row in cursor:
self.items.append("{:<50}{:<12}{:<12}{:<12}{:<12}{:<12}{:<12}{:<12}{:<12}".
format(row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8]))
@@ -761,8 +782,8 @@
"Inc. data"))
self.items.append(self.__line2)
- cursor = self.__cur.execute("select * from Object WHERE library = '{}' ORDER BY flashsize DESC".
- format(self.library_name))
+ cursor = self.__cur.execute("select * from Object WHERE lib_file = '{}' ORDER BY {} {}".
+ format(self.library_name, self.sort, self.order))
for row in cursor:
self.items.append("{:<50}{:<12}{:<12}{:<12}{:<12}{:<12}{:<12}{:<12}".
format(row[0], row[2], row[3], row[4], row[5], row[6], row[7], row[8]))
@@ -770,8 +791,8 @@
"""
Draw functions.
"""
- cursor = self.__cur.execute("select * from Function WHERE lib_file = '{}' ORDER BY size DESC".
- format(self.library_name))
+ cursor = self.__cur.execute("select * from Function WHERE lib_file = '{}' ORDER BY {} {}".
+ format(self.library_name, self.sort, self.order))
for row in cursor:
if not flag:
self.__quick_append()
@@ -782,22 +803,22 @@
"""
Draw RO data.
"""
- cursor = self.__cur.execute("select * from Data WHERE type = 'RO' and lib_file = '{}' ORDER BY size DESC".
- format(self.library_name))
+ cursor = self.__cur.execute("select * from Data WHERE type = 'RO' and lib_file = '{}' ORDER BY {} {}".
+ format(self.library_name, self.sort, self.order))
self.__quick_append_data(cursor)
"""
Draw RW data.
"""
- cursor = self.__cur.execute("select * from Data WHERE type = 'RW' and lib_file = '{}' ORDER BY size DESC".
- format(self.library_name))
+ cursor = self.__cur.execute("select * from Data WHERE type = 'RW' and lib_file = '{}' ORDER BY {} {}".
+ format(self.library_name, self.sort, self.order))
self.__quick_append_data(cursor)
"""
Draw ZI data.
"""
- cursor = self.__cur.execute("select * from Data WHERE type = 'ZI' and lib_file = '{}' ORDER BY size DESC".
- format(self.library_name))
+ cursor = self.__cur.execute("select * from Data WHERE type = 'ZI' and lib_file = '{}' ORDER BY {} {}".
+ format(self.library_name, self.sort, self.order))
self.__quick_append_data(cursor)
self.items.append(self.__line1)
@@ -813,13 +834,12 @@
"ZI data",
"Inc. data",
"Debug")]
- cursor = self.__cur.execute(
- "select * from Object WHERE library = 'no library' ORDER BY flashsize DESC")
+ cursor = self.__cur.execute("select * from Object WHERE lib_file = 'no library' ORDER BY {} {}".format(self.sort, self.order))
for row in cursor:
self.items.append("{:<50}{:<50}{:<12}{:<12}{:<12}{:<12}{:<12}{:<12}{:<12}{:<12}".
format(row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8], row[9]))
cursor = self.__cur.execute(
- "select * from Object WHERE library != 'no library' ORDER BY flashsize DESC")
+ "select * from Object WHERE lib_file != 'no library' ORDER BY {} {}".format(self.sort, self.order))
for row in cursor:
self.items.append("{:<50}{:<50}{:<12}{:<12}{:<12}{:<12}{:<12}{:<12}{:<12}{:<12}".
format(row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8], row[9]))
@@ -845,8 +865,8 @@
format(row[0], row[2], row[3], row[4], row[5], row[6], row[7], row[8]))
break
- cursor = self.__cur.execute("select * from Function WHERE obj_file = '{}' ORDER BY size DESC".
- format(self.obj_file))
+ cursor = self.__cur.execute("select * from Function WHERE obj_file = '{}' ORDER BY {} {}".
+ format(self.obj_file, self.sort, self.order))
for row in cursor:
if not flag:
self.__quick_append()
@@ -854,16 +874,16 @@
format(row[0], row[1], row[2], "Code", row[4]))
flag = True
- cursor = self.__cur.execute("select * from Data WHERE type = 'RO' and obj_file = '{}' ORDER BY size DESC".
- format(self.obj_file))
+ cursor = self.__cur.execute("select * from Data WHERE type = 'RO' and obj_file = '{}' ORDER BY {} {}".
+ format(self.obj_file, self.sort, self.order))
self.__quick_append_data(cursor)
- cursor = self.__cur.execute("select * from Data WHERE type = 'RW' and obj_file = '{}' ORDER BY size DESC".
- format(self.obj_file))
+ cursor = self.__cur.execute("select * from Data WHERE type = 'RW' and obj_file = '{}' ORDER BY {} {}".
+ format(self.obj_file, self.sort, self.order))
self.__quick_append_data(cursor)
- cursor = self.__cur.execute("select * from Data WHERE type = 'ZI' and obj_file = '{}' ORDER BY size DESC".
- format(self.obj_file))
+ cursor = self.__cur.execute("select * from Data WHERE type = 'ZI' and obj_file = '{}' ORDER BY {} {}".
+ format(self.obj_file, self.sort, self.order))
self.__quick_append_data(cursor)
self.items.append(self.__line1)
@@ -880,8 +900,7 @@
cursor = self.__cur.execute("select * from Function WHERE name LIKE '%{}%'".
format(search_func))
else:
- cursor = self.__cur.execute(
- "select * from Function ORDER BY size DESC")
+ cursor = self.__cur.execute("select * from Function ORDER BY {} {}".format(self.sort, self.order))
for row in cursor:
self.items.append("{:<50}{:<50}{:<10}{:<16}{:<40}{:<40}".
format(row[0], row[1], row[2], row[3], row[4], row[5]))
@@ -917,7 +936,7 @@
cursor = self.__cur.execute("select * from Data WHERE name LIKE '%{}%'".
format(search_data))
else:
- cursor = self.__cur.execute("select * from Data ORDER BY size DESC")
+ cursor = self.__cur.execute("select * from Data ORDER BY {} {}".format(self.sort, self.order))
for row in cursor:
data_name = row[0]
if len(data_name) >= 50:
@@ -948,6 +967,7 @@
"""
Continue running the TUI until get interrupted
"""
+ self.open_db()
self.__init_curses()
try:
self.__draw_page()
@@ -955,4 +975,5 @@
except KeyboardInterrupt:
pass
finally:
+ self.con.close()
curses.endwin()