diff --git a/platform/arm-gcc-m55.cmake b/platform/arm-gcc-m55.cmake new file mode 100644 index 000000000..018129995 --- /dev/null +++ b/platform/arm-gcc-m55.cmake @@ -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") diff --git a/scripts/diff_code_size.py b/scripts/diff_code_size.py new file mode 100755 index 000000000..fd37e7343 --- /dev/null +++ b/scripts/diff_code_size.py @@ -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() diff --git a/scripts/generate_code_size_report.py b/scripts/generate_code_size_report.py new file mode 100755 index 000000000..409130421 --- /dev/null +++ b/scripts/generate_code_size_report.py @@ -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() + diff --git a/scripts/get_code_size.py b/scripts/get_code_size.py new file mode 100755 index 000000000..65c9a71c4 --- /dev/null +++ b/scripts/get_code_size.py @@ -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) diff --git a/scripts/show_code_size.py b/scripts/show_code_size.py new file mode 100755 index 000000000..83cdc1a39 --- /dev/null +++ b/scripts/show_code_size.py @@ -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])