-
Notifications
You must be signed in to change notification settings - Fork 44
Add code size measurement scripts #246
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
davidhorstmann-arm
wants to merge
10
commits into
Mbed-TLS:main
Choose a base branch
from
davidhorstmann-arm:code-size-measurement-script
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
129e228
Add script to generate a code size report
davidhorstmann-arm 4592c84
Add a script to display the captured code sizes
davidhorstmann-arm f04f29f
Add CMake toolchain file for Cortex-M55
davidhorstmann-arm 7563bd4
Add code size getting script for M55
davidhorstmann-arm 69c08b2
Add script to diff two code size reports
davidhorstmann-arm 87c57e8
Parameterise size command
davidhorstmann-arm 0be81ad
Parameterise the toolchain file
davidhorstmann-arm 3710b38
Rename 'get code size' script
davidhorstmann-arm 87d9122
Allow setting a custom config file
davidhorstmann-arm 7d4ab50
Alllow build directories for diffing
davidhorstmann-arm File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| set(CMAKE_SYSTEM_NAME Generic) | ||
|
|
||
| set(CMAKE_C_COMPILER arm-none-eabi-gcc) | ||
| # CMAKE_SIZE_UTIL is not a 'real' CMake variable but is sometimes | ||
| # used by convention in embedded toolchain files. | ||
| set(CMAKE_SIZE_UTIL arm-none-eabi-size) | ||
|
|
||
| set(CMAKE_C_FLAGS "-mthumb -mcpu=cortex-m55 -Os") | ||
| set(CMAKE_EXE_LINKER_FLAGS "--specs=nosys.specs") |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,89 @@ | ||
| #!/usr/bin/env python3 | ||
| """Examine 2 code size reports and print the difference between them. | ||
| """ | ||
|
|
||
| # Copyright The Mbed TLS Contributors | ||
| # SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later | ||
|
|
||
| import json | ||
| import os | ||
| import sys | ||
|
|
||
| def load_sizes(json_file): | ||
| with open(json_file) as f: | ||
| json_sizes = f.read() | ||
|
|
||
| sizes = json.loads(json_sizes) | ||
| return sizes | ||
|
|
||
| def generate_diff_table(sizes_a, sizes_b): | ||
| table = [] | ||
| total_size_a = 0 | ||
| total_size_b = 0 | ||
|
|
||
| for file in sizes_a: | ||
| size_a = (sizes_a[file]['text'] | ||
| + sizes_a[file]['data'] | ||
| + sizes_a[file]['bss']) | ||
| total_size_a += size_a | ||
|
|
||
| if file in sizes_b: | ||
| size_b = (sizes_b[file]['text'] | ||
| + sizes_b[file]['data'] | ||
| + sizes_b[file]['bss']) | ||
| size_diff = size_b - size_a | ||
|
|
||
| if size_diff != 0: | ||
| table.append((file.split('.')[0], size_a, size_b, size_diff, | ||
| (size_diff * 100.0 / size_a))) | ||
| else: | ||
| # This file is only in A, so there's a code size decrease | ||
| table.append((file.split('.')[0], size_a, 0, -size_a, -100.0)) | ||
|
|
||
| for file in sizes_b: | ||
| size_b = (sizes_b[file]['text'] | ||
| + sizes_b[file]['data'] | ||
| + sizes_b[file]['bss']) | ||
| total_size_b += size_b | ||
|
|
||
| if file not in sizes_a: | ||
| # This file is only in B, so there's a code size increase | ||
| table.append((file.split('.')[0], 0, size_b, size_b, 100.0)) | ||
|
|
||
| total_size_diff = total_size_b - total_size_a | ||
| table.append(('TOTAL', total_size_a, total_size_b, total_size_diff, | ||
| (total_size_diff * 100.0 / total_size_a))) | ||
|
|
||
| return table | ||
|
|
||
| def display_diff_table(table): | ||
| table_line_format = '{:<40} {:>8} {:>8} {:>+8} {:>+8.2f}%' | ||
|
|
||
| print('{:<40} {:>8} {:>8} {:>8} {:>9}'.format( | ||
| 'Module', 'Old', 'New', 'Delta', '% Delta')) | ||
|
|
||
| for line in table: | ||
| print(table_line_format.format(*line)) | ||
|
|
||
| def main(): | ||
| if len(sys.argv) < 3: | ||
| print('Error: Less than 2 JSON files / build directories supplied.', file=sys.stderr) | ||
| sys.exit(1) | ||
|
|
||
| file_a = sys.argv[1] | ||
| file_b = sys.argv[2] | ||
|
|
||
| # If the arguments are build directories, find the JSON | ||
| # code-size report in core/code_size.json | ||
| if os.path.isdir(file_a): | ||
| file_a = file_a + '/core/code_size.json' | ||
| if os.path.isdir(file_b): | ||
| file_b = file_b + '/core/code_size.json' | ||
|
|
||
| sizes_a = load_sizes(file_a) | ||
| sizes_b = load_sizes(file_b) | ||
|
|
||
| display_diff_table(generate_diff_table(sizes_a, sizes_b)) | ||
|
|
||
| if __name__ == '__main__': | ||
| main() | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,67 @@ | ||
| #!/usr/bin/env python3 | ||
| """Generate a code size report for the supplied library file, using the given | ||
| size tool, and write it in JSON format to the given output file. | ||
| """ | ||
|
|
||
| # Copyright The Mbed TLS Contributors | ||
| # SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later | ||
|
|
||
| import argparse | ||
| import json | ||
| import subprocess | ||
| import sys | ||
|
|
||
| def get_size_output(size_cmd: str, library_file: str): | ||
| """Run the size command on the library and get its output""" | ||
| output = subprocess.check_output([size_cmd, library_file]) | ||
| return str(output, 'UTF-8') | ||
|
|
||
| def size_breakdown(size_output: str): | ||
| """Convert the output of the size command to a dictionary like the following: | ||
| {'filename.c.obj' : {'text': 123, 'data': 456, 'bss': 789}}""" | ||
|
|
||
| sizes = {} | ||
|
|
||
| for line in size_output.splitlines()[1:]: | ||
| row = line.split() | ||
| obj_file_name = row[5] | ||
| text_size = int(row[0]) | ||
| data_size = int(row[1]) | ||
| bss_size = int(row[2]) | ||
|
|
||
| sizes[obj_file_name] = {'text': text_size, 'data': data_size, 'bss': bss_size} | ||
|
|
||
| return sizes | ||
|
|
||
| def write_out_results(sizes: dict, output_file: str): | ||
| """Write out the sizes in JSON to the output file""" | ||
| sizes_json = json.dumps(sizes, indent=4) | ||
|
|
||
| with open(output_file, "w") as out: | ||
| out.write(sizes_json) | ||
|
|
||
| def main(): | ||
| parser = argparse.ArgumentParser( | ||
| description='Generate a code size report in JSON format') | ||
|
|
||
| parser.add_argument("-o", "--output-file", | ||
| help="Filename of the report to generate", | ||
| default='code_size.json') | ||
|
|
||
| parser.add_argument("-s", "--size-cmd", | ||
| help="Size command to use (e.g. arm-none-eabi-size)", | ||
| required=True) | ||
|
|
||
| parser.add_argument("-l", "--library-file", | ||
| help="Library file to generate report from", | ||
| required=True) | ||
|
|
||
| args = parser.parse_args() | ||
|
|
||
| sizes = size_breakdown(get_size_output(args.size_cmd, args.library_file)) | ||
|
|
||
| write_out_results(sizes, args.output_file) | ||
|
|
||
| if __name__ == "__main__": | ||
| main() | ||
|
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| #!/usr/bin/env python3 | ||
| """Build the library for Cortex-M55 using the toolchain file in | ||
| framework/platform and measure and print the code size using the | ||
| existing scripts. | ||
| """ | ||
|
|
||
| # Copyright The Mbed TLS Contributors | ||
| # SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later | ||
|
|
||
| import argparse | ||
| import json | ||
| import os | ||
| import subprocess | ||
|
|
||
| def build_library(build_dir, toolchain_file, named_config): | ||
| config_file_path = build_dir + '/code_size_crypto_config.h' | ||
|
|
||
| subprocess.check_call(['cp', 'include/psa/crypto_config.h', config_file_path]) | ||
| subprocess.check_call(['scripts/config.py', '-f', config_file_path, named_config]) | ||
| subprocess.check_call(['cmake', '.', '-B' + build_dir, | ||
| '-DCMAKE_TOOLCHAIN_FILE=' + toolchain_file, | ||
| '-DENABLE_PROGRAMS=NO', | ||
| '-DTF_PSA_CRYPTO_CONFIG_FILE=' + config_file_path]) | ||
| subprocess.check_call(['cmake', '--build', build_dir, '-j' + str(os.cpu_count())]) | ||
|
|
||
| def generate_sizes(build_dir, size_cmd): | ||
| subprocess.check_call(['framework/scripts/generate_code_size_report.py', | ||
| '--output-file', build_dir + '/code_size.json', | ||
| '--library-file', build_dir + '/core/libtfpsacrypto.a', | ||
| '--size-cmd', size_cmd]) | ||
|
|
||
| def display_sizes(build_dir): | ||
| subprocess.check_call(['framework/scripts/show_code_size.py', | ||
| build_dir + '/code_size.json']) | ||
|
|
||
| if __name__ == '__main__': | ||
| BUILD_DIR = 'build-code-size' | ||
|
|
||
| parser = argparse.ArgumentParser( | ||
| description='Generate a code size report in JSON format') | ||
|
|
||
| parser.add_argument('-s', '--size-cmd', | ||
| help='Size command to use (default arm-none-eabi-size)', | ||
| default='arm-none-eabi-size') | ||
| parser.add_argument('-t', '--toolchain-file', | ||
| help='CMake toolchain file to use for building', | ||
| default='framework/platform/arm-gcc-m55.cmake') | ||
| parser.add_argument('-c', '--config-name', | ||
| help='Named config to use for size measurement.', | ||
| default='baremetal_size') | ||
|
|
||
| args = parser.parse_args() | ||
|
|
||
| build_library(BUILD_DIR, args.toolchain_file, args.config_name) | ||
| generate_sizes(BUILD_DIR, args.size_cmd) | ||
| display_sizes(BUILD_DIR) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| #!/usr/bin/env python3 | ||
| """Parse a JSON code size report and output a pretty-printed table of sizes | ||
| for each module along with their totals. | ||
| """ | ||
|
|
||
| # Copyright The Mbed TLS Contributors | ||
| # SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later | ||
|
|
||
| import json | ||
| import sys | ||
|
|
||
| def display_sizes(json_file): | ||
| with open(json_file) as f: | ||
| json_sizes = f.read() | ||
|
|
||
| sizes = json.loads(json_sizes) | ||
|
|
||
| padded_line = '{:<40} {:>8} {:>8} {:>8} {:>8}' | ||
|
|
||
| print(padded_line.format('file', 'text', 'data', 'bss', 'total')) | ||
|
|
||
| text_total = 0 | ||
| data_total = 0 | ||
| bss_total = 0 | ||
| total_total = 0 | ||
|
|
||
| for file in sizes: | ||
| module = file.split('.')[0] # Remove .c.obj extension | ||
| text = sizes[file]['text'] | ||
| data = sizes[file]['data'] | ||
| bss = sizes[file]['bss'] | ||
| print(padded_line.format(module, text, data, bss, text + data + bss)) | ||
| text_total += text | ||
| data_total += data | ||
| bss_total += bss | ||
| total_total += text + data + bss | ||
|
|
||
| print(padded_line.format('TOTAL', text_total, data_total, bss_total, total_total)) | ||
|
|
||
| if __name__ == '__main__': | ||
| if len(sys.argv) < 2: | ||
| print('Error: No JSON file supplied.', file=sys.stderr) | ||
| sys.exit(1) | ||
|
|
||
| display_sizes(sys.argv[1]) |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's your typical workflow with this script?
I use
mbedtls-size-dwim, where my workflow is to set up one or more build directories and run e.g.mbedtls-size-dwim build-m0pluseach time I commit and at any point while I'm developing. It shows the code size differences with the last commit.With
diff_code_size.py, where would I typically find the files to compare?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If working in conjunction with Mbed-TLS/TF-PSA-Crypto#590 it would be something like:
It might be easier if it found the code size report itself, should I add that feature?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, ok, you're typically comparing different build options? I find that I mostly want to compare different versions of the same code. That's why mbedtls-size-dwim stores sizes in a file named after the git head sha.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Usually I need to compare different options but assessing the code size impact of a config option happens often enough that I value the flexibility.