blob: 8cd1b27751e07cc67005bb8ab209e6d7da986902 [file] [log] [blame]
Xiaofei Baibca03e52021-09-09 09:42:37 +00001#!/usr/bin/env python3
2
3"""
Xiaofei Baibca03e52021-09-09 09:42:37 +00004This script is for comparing the size of the library files from two
5different Git revisions within an Mbed TLS repository.
6The results of the comparison is formatted as csv and stored at a
7configurable location.
8Note: must be run from Mbed TLS root.
9"""
10
11# Copyright The Mbed TLS Contributors
12# SPDX-License-Identifier: Apache-2.0
13#
14# Licensed under the Apache License, Version 2.0 (the "License"); you may
15# not use this file except in compliance with the License.
16# You may obtain a copy of the License at
17#
18# http://www.apache.org/licenses/LICENSE-2.0
19#
20# Unless required by applicable law or agreed to in writing, software
21# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
22# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
23# See the License for the specific language governing permissions and
24# limitations under the License.
25
26import argparse
27import os
Yanray Wang16ebc572023-05-30 18:10:20 +080028import re
Xiaofei Baibca03e52021-09-09 09:42:37 +000029import subprocess
30import sys
Yanray Wang16ebc572023-05-30 18:10:20 +080031import typing
Yanray Wang23bd5322023-05-24 11:03:59 +080032from enum import Enum
Xiaofei Baibca03e52021-09-09 09:42:37 +000033
Yanray Wang16ebc572023-05-30 18:10:20 +080034from mbedtls_dev import typing_util
Gilles Peskined9071e72022-09-18 21:17:09 +020035from mbedtls_dev import build_tree
36
Yanray Wang23bd5322023-05-24 11:03:59 +080037class SupportedArch(Enum):
38 """Supported architecture for code size measurement."""
39 AARCH64 = 'aarch64'
40 AARCH32 = 'aarch32'
Yanray Wangaba71582023-05-29 16:45:56 +080041 ARMV8_M = 'armv8-m'
Yanray Wang23bd5322023-05-24 11:03:59 +080042 X86_64 = 'x86_64'
43 X86 = 'x86'
44
Yanray Wang6a862582023-05-24 12:24:38 +080045CONFIG_TFM_MEDIUM_MBEDCRYPTO_H = "../configs/tfm_mbedcrypto_config_profile_medium.h"
46CONFIG_TFM_MEDIUM_PSA_CRYPTO_H = "../configs/crypto_config_profile_medium.h"
47class SupportedConfig(Enum):
48 """Supported configuration for code size measurement."""
49 DEFAULT = 'default'
50 TFM_MEDIUM = 'tfm-medium'
51
Yanray Wang16ebc572023-05-30 18:10:20 +080052# Static library
53MBEDTLS_STATIC_LIB = {
54 'CRYPTO': 'library/libmbedcrypto.a',
55 'X509': 'library/libmbedx509.a',
56 'TLS': 'library/libmbedtls.a',
57}
58
Yanray Wang23bd5322023-05-24 11:03:59 +080059DETECT_ARCH_CMD = "cc -dM -E - < /dev/null"
60def detect_arch() -> str:
61 """Auto-detect host architecture."""
62 cc_output = subprocess.check_output(DETECT_ARCH_CMD, shell=True).decode()
63 if "__aarch64__" in cc_output:
64 return SupportedArch.AARCH64.value
65 if "__arm__" in cc_output:
66 return SupportedArch.AARCH32.value
67 if "__x86_64__" in cc_output:
68 return SupportedArch.X86_64.value
69 if "__x86__" in cc_output:
70 return SupportedArch.X86.value
71 else:
72 print("Unknown host architecture, cannot auto-detect arch.")
73 sys.exit(1)
Gilles Peskined9071e72022-09-18 21:17:09 +020074
Yanray Wang6a862582023-05-24 12:24:38 +080075class CodeSizeInfo: # pylint: disable=too-few-public-methods
76 """Gather information used to measure code size.
77
78 It collects information about architecture, configuration in order to
79 infer build command for code size measurement.
80 """
81
Yanray Wangc18cd892023-05-31 11:08:04 +080082 SupportedArchConfig = [
83 "-a " + SupportedArch.AARCH64.value + " -c " + SupportedConfig.DEFAULT.value,
84 "-a " + SupportedArch.AARCH32.value + " -c " + SupportedConfig.DEFAULT.value,
85 "-a " + SupportedArch.X86_64.value + " -c " + SupportedConfig.DEFAULT.value,
86 "-a " + SupportedArch.X86.value + " -c " + SupportedConfig.DEFAULT.value,
87 "-a " + SupportedArch.ARMV8_M.value + " -c " + SupportedConfig.TFM_MEDIUM.value,
88 ]
89
Yanray Wang21f17442023-06-01 11:29:06 +080090 def __init__(self, arch: str, config: str, sys_arch: str) -> None:
Yanray Wang6a862582023-05-24 12:24:38 +080091 """
92 arch: architecture to measure code size on.
93 config: configuration type to measure code size with.
Yanray Wang699a6c82023-07-04 17:21:28 +080094 sys_arch: host architecture.
Yanray Wang6a862582023-05-24 12:24:38 +080095 """
96 self.arch = arch
97 self.config = config
Yanray Wang21f17442023-06-01 11:29:06 +080098 self.sys_arch = sys_arch
Yanray Wang5e9130a2023-07-17 11:55:54 +080099 self.make_cmd = self.set_make_command()
Yanray Wang6a862582023-05-24 12:24:38 +0800100
101 def set_make_command(self) -> str:
102 """Infer build command based on architecture and configuration."""
103
Yanray Wang21f17442023-06-01 11:29:06 +0800104 if self.config == SupportedConfig.DEFAULT.value and \
105 self.arch == self.sys_arch:
Yanray Wang6a862582023-05-24 12:24:38 +0800106 return 'make -j lib CFLAGS=\'-Os \' '
Yanray Wangaba71582023-05-29 16:45:56 +0800107 elif self.arch == SupportedArch.ARMV8_M.value and \
Yanray Wang6a862582023-05-24 12:24:38 +0800108 self.config == SupportedConfig.TFM_MEDIUM.value:
109 return \
Yanray Wang60430bd2023-05-29 14:48:18 +0800110 'make -j lib CC=armclang \
Yanray Wang6a862582023-05-24 12:24:38 +0800111 CFLAGS=\'--target=arm-arm-none-eabi -mcpu=cortex-m33 -Os \
112 -DMBEDTLS_CONFIG_FILE=\\\"' + CONFIG_TFM_MEDIUM_MBEDCRYPTO_H + '\\\" \
113 -DMBEDTLS_PSA_CRYPTO_CONFIG_FILE=\\\"' + CONFIG_TFM_MEDIUM_PSA_CRYPTO_H + '\\\" \''
114 else:
Yanray Wang21f17442023-06-01 11:29:06 +0800115 print("Unsupported combination of architecture: {} and configuration: {}"
Yanray Wang6a862582023-05-24 12:24:38 +0800116 .format(self.arch, self.config))
Yanray Wangc18cd892023-05-31 11:08:04 +0800117 print("\nPlease use supported combination of architecture and configuration:")
118 for comb in CodeSizeInfo.SupportedArchConfig:
119 print(comb)
Yanray Wang21f17442023-06-01 11:29:06 +0800120 print("\nFor your system, please use:")
121 for comb in CodeSizeInfo.SupportedArchConfig:
122 if "default" in comb and self.sys_arch not in comb:
123 continue
124 print(comb)
Yanray Wang6a862582023-05-24 12:24:38 +0800125 sys.exit(1)
126
127
Yanray Wange0e27602023-07-14 17:37:45 +0800128class CodeSizeCalculator:
129 """ A calculator to calculate code size of library objects based on
130 Git revision and code size measurement tool.
131 """
132
133 def __init__(
134 self,
135 revision: str,
136 make_cmd: str,
137 ) -> None:
138 """
139 revision: Git revision.(E.g: commit)
140 make_cmd: command to build library objects.
141 """
142 self.repo_path = "."
143 self.git_command = "git"
144 self.make_clean = 'make clean'
145
146 self.revision = revision
147 self.make_cmd = make_cmd
148
149 @staticmethod
150 def validate_revision(revision: str) -> bytes:
151 result = subprocess.check_output(["git", "rev-parse", "--verify",
152 revision + "^{commit}"], shell=False)
153 return result
154
155 def _create_git_worktree(self, revision: str) -> str:
156 """Make a separate worktree for revision.
157 Do not modify the current worktree."""
158
159 if revision == "current":
160 print("Using current work directory")
161 git_worktree_path = self.repo_path
162 else:
163 print("Creating git worktree for", revision)
164 git_worktree_path = os.path.join(self.repo_path, "temp-" + revision)
165 subprocess.check_output(
166 [self.git_command, "worktree", "add", "--detach",
167 git_worktree_path, revision], cwd=self.repo_path,
168 stderr=subprocess.STDOUT
169 )
170
171 return git_worktree_path
172
173 def _build_libraries(self, git_worktree_path: str) -> None:
174 """Build libraries in the specified worktree."""
175
176 my_environment = os.environ.copy()
177 try:
178 subprocess.check_output(
179 self.make_clean, env=my_environment, shell=True,
180 cwd=git_worktree_path, stderr=subprocess.STDOUT,
181 )
182 subprocess.check_output(
183 self.make_cmd, env=my_environment, shell=True,
184 cwd=git_worktree_path, stderr=subprocess.STDOUT,
185 )
186 except subprocess.CalledProcessError as e:
187 self._handle_called_process_error(e, git_worktree_path)
188
189 def _gen_raw_code_size(self, revision, git_worktree_path):
190 """Calculate code size with measurement tool in UTF-8 encoding."""
191 if revision == "current":
192 print("Measuring code size in current work directory")
193 else:
194 print("Measuring code size for", revision)
195
196 res = {}
197 for mod, st_lib in MBEDTLS_STATIC_LIB.items():
198 try:
199 result = subprocess.check_output(
200 ["size", st_lib, "-t"], cwd=git_worktree_path,
201 universal_newlines=True
202 )
203 res[mod] = result
204 except subprocess.CalledProcessError as e:
205 self._handle_called_process_error(e, git_worktree_path)
206
207 return res
208
209 def _remove_worktree(self, git_worktree_path: str) -> None:
210 """Remove temporary worktree."""
211 if git_worktree_path != self.repo_path:
212 print("Removing temporary worktree", git_worktree_path)
213 subprocess.check_output(
214 [self.git_command, "worktree", "remove", "--force",
215 git_worktree_path], cwd=self.repo_path,
216 stderr=subprocess.STDOUT
217 )
218
219 def _handle_called_process_error(self, e: subprocess.CalledProcessError,
220 git_worktree_path: str) -> None:
221 """Handle a CalledProcessError and quit the program gracefully.
222 Remove any extra worktrees so that the script may be called again."""
223
224 # Tell the user what went wrong
225 print("The following command: {} failed and exited with code {}"
226 .format(e.cmd, e.returncode))
227 print("Process output:\n {}".format(str(e.output, "utf-8")))
228
229 # Quit gracefully by removing the existing worktree
230 self._remove_worktree(git_worktree_path)
231 sys.exit(-1)
232
233 def cal_libraries_code_size(self) -> typing.Dict:
234 """Calculate code size of libraries by measurement tool."""
235
236 revision = self.revision
237 git_worktree_path = self._create_git_worktree(revision)
238 self._build_libraries(git_worktree_path)
239 res = self._gen_raw_code_size(revision, git_worktree_path)
240 self._remove_worktree(git_worktree_path)
241
242 return res
243
244
Yanray Wang15c43f32023-07-17 11:17:12 +0800245class CodeSizeGenerator:
246 """ A generator based on size measurement tool for library objects.
247
248 This is an abstract class. To use it, derive a class that implements
249 size_generator_write_record and size_generator_write_comparison methods,
250 then call both of them with proper arguments.
251 """
252 def size_generator_write_record(
253 self,
254 revision: str,
255 code_size_text: typing.Dict,
256 output_file: str
257 ) -> None:
258 """Write size record into a file.
259
260 revision: Git revision.(E.g: commit)
261 code_size_text: text output (utf-8) from code size measurement tool.
262 output_file: file which the code size record is written to.
263 """
264 raise NotImplementedError
265
266 def size_generator_write_comparison(
267 self,
268 old_rev: str,
269 new_rev: str,
270 output_stream
271 ) -> None:
272 """Write a comparision result into a stream between two revisions.
273
274 old_rev: old git revision to compared with.
275 new_rev: new git revision to compared with.
276 output_stream: stream which the code size record is written to.
277 (E.g: file / sys.stdout)
278 """
279 raise NotImplementedError
280
281
282class CodeSizeGeneratorWithSize(CodeSizeGenerator):
Yanray Wang16ebc572023-05-30 18:10:20 +0800283 """Code Size Base Class for size record saving and writing."""
284
Yanray Wangfc6ed4d2023-07-14 17:33:09 +0800285 class SizeEntry: # pylint: disable=too-few-public-methods
286 """Data Structure to only store information of code size."""
287 def __init__(self, text, data, bss, dec):
288 self.text = text
289 self.data = data
290 self.bss = bss
291 self.total = dec # total <=> dec
292
Yanray Wang16ebc572023-05-30 18:10:20 +0800293 def __init__(self) -> None:
294 """ Variable code_size is used to store size info for any revisions.
295 code_size: (data format)
296 {revision: {module: {file_name: SizeEntry,
297 etc ...
298 },
299 etc ...
300 },
301 etc ...
302 }
303 """
304 self.code_size = {} #type: typing.Dict[str, typing.Dict]
305
306 def set_size_record(self, revision: str, mod: str, size_text: str) -> None:
307 """Store size information for target revision and high-level module.
308
309 size_text Format: text data bss dec hex filename
310 """
311 size_record = {}
312 for line in size_text.splitlines()[1:]:
313 data = line.split()
Yanray Wangfc6ed4d2023-07-14 17:33:09 +0800314 size_record[data[5]] = CodeSizeGeneratorWithSize.SizeEntry(\
315 data[0], data[1], data[2], data[3])
Yanray Wang16ebc572023-05-30 18:10:20 +0800316 if revision in self.code_size:
317 self.code_size[revision].update({mod: size_record})
318 else:
319 self.code_size[revision] = {mod: size_record}
320
321 def read_size_record(self, revision: str, fname: str) -> None:
322 """Read size information from csv file and write it into code_size.
323
324 fname Format: filename text data bss dec
325 """
326 mod = ""
327 size_record = {}
328 with open(fname, 'r') as csv_file:
329 for line in csv_file:
330 data = line.strip().split()
331 # check if we find the beginning of a module
332 if data and data[0] in MBEDTLS_STATIC_LIB:
333 mod = data[0]
334 continue
335
336 if mod:
337 size_record[data[0]] = \
Yanray Wangfc6ed4d2023-07-14 17:33:09 +0800338 CodeSizeGeneratorWithSize.SizeEntry(\
339 data[1], data[2], data[3], data[4])
Yanray Wang16ebc572023-05-30 18:10:20 +0800340
341 # check if we hit record for the end of a module
342 m = re.match(r'.?TOTALS', line)
343 if m:
344 if revision in self.code_size:
345 self.code_size[revision].update({mod: size_record})
346 else:
347 self.code_size[revision] = {mod: size_record}
348 mod = ""
349 size_record = {}
350
351 def _size_reader_helper(
352 self,
353 revision: str,
354 output: typing_util.Writable
355 ) -> typing.Iterator[tuple]:
356 """A helper function to peel code_size based on revision."""
357 for mod, file_size in self.code_size[revision].items():
358 output.write("\n" + mod + "\n")
359 for fname, size_entry in file_size.items():
360 yield mod, fname, size_entry
361
362 def write_size_record(
363 self,
364 revision: str,
365 output: typing_util.Writable
366 ) -> None:
367 """Write size information to a file.
368
369 Writing Format: file_name text data bss total(dec)
370 """
371 output.write("{:<30} {:>7} {:>7} {:>7} {:>7}\n"
372 .format("filename", "text", "data", "bss", "total"))
373 for _, fname, size_entry in self._size_reader_helper(revision, output):
374 output.write("{:<30} {:>7} {:>7} {:>7} {:>7}\n"
375 .format(fname, size_entry.text, size_entry.data,\
376 size_entry.bss, size_entry.total))
377
378 def write_comparison(
379 self,
380 old_rev: str,
381 new_rev: str,
382 output: typing_util.Writable
383 ) -> None:
384 """Write comparison result into a file.
385
386 Writing Format: file_name current(total) old(total) change(Byte) change_pct(%)
387 """
388 output.write("{:<30} {:>7} {:>7} {:>7} {:>7}\n"
389 .format("filename", "current", "old", "change", "change%"))
390 for mod, fname, size_entry in self._size_reader_helper(new_rev, output):
391 new_size = int(size_entry.total)
392 # check if we have the file in old revision
393 if fname in self.code_size[old_rev][mod]:
394 old_size = int(self.code_size[old_rev][mod][fname].total)
395 change = new_size - old_size
396 if old_size != 0:
397 change_pct = change / old_size
398 else:
399 change_pct = 0
400 output.write("{:<30} {:>7} {:>7} {:>7} {:>7.2%}\n"
401 .format(fname, new_size, old_size, change, change_pct))
402 else:
403 output.write("{} {}\n".format(fname, new_size))
404
Yanray Wang15c43f32023-07-17 11:17:12 +0800405 def size_generator_write_record(
406 self,
407 revision: str,
408 code_size_text: typing.Dict,
409 output_file: str
410 ) -> None:
411 """Write size record into a specified file based on Git revision and
412 output from `size` tool."""
413 for mod, size_text in code_size_text.items():
414 self.set_size_record(revision, mod, size_text)
415
416 print("Generating code size csv for", revision)
417 output = open(output_file, "w")
418 self.write_size_record(revision, output)
419
420 def size_generator_write_comparison(
421 self,
422 old_rev: str,
423 new_rev: str,
424 output_stream
425 ) -> None:
426 """Write a comparision result into a stream between two revisions."""
427 output = open(output_stream, "w")
428 self.write_comparison(old_rev, new_rev, output)
429
Yanray Wang16ebc572023-05-30 18:10:20 +0800430
Yanray Wangfc6ed4d2023-07-14 17:33:09 +0800431class CodeSizeComparison:
Xiaofei Bai2400b502021-10-21 12:22:58 +0000432 """Compare code size between two Git revisions."""
Xiaofei Baibca03e52021-09-09 09:42:37 +0000433
Yanray Wang72b105f2023-05-31 15:20:39 +0800434 def __init__(
435 self,
436 old_revision: str,
437 new_revision: str,
438 result_dir: str,
439 code_size_info: CodeSizeInfo
440 ) -> None:
Xiaofei Baibca03e52021-09-09 09:42:37 +0000441 """
Yanray Wang6a862582023-05-24 12:24:38 +0800442 old_revision: revision to compare against.
Xiaofei Baibca03e52021-09-09 09:42:37 +0000443 new_revision:
Yanray Wang6a862582023-05-24 12:24:38 +0800444 result_dir: directory for comparison result.
445 code_size_info: an object containing information to build library.
Xiaofei Baibca03e52021-09-09 09:42:37 +0000446 """
447 self.repo_path = "."
448 self.result_dir = os.path.abspath(result_dir)
Xiaofei Bai184e8b62021-10-26 09:23:42 +0000449 os.makedirs(self.result_dir, exist_ok=True)
Xiaofei Baibca03e52021-09-09 09:42:37 +0000450
451 self.csv_dir = os.path.abspath("code_size_records/")
Xiaofei Bai184e8b62021-10-26 09:23:42 +0000452 os.makedirs(self.csv_dir, exist_ok=True)
Xiaofei Baibca03e52021-09-09 09:42:37 +0000453
454 self.old_rev = old_revision
455 self.new_rev = new_revision
456 self.git_command = "git"
Yanray Wang4c26db02023-07-04 16:49:04 +0800457 self.make_clean = 'make clean'
Yanray Wang5e9130a2023-07-17 11:55:54 +0800458 self.make_cmd = code_size_info.make_cmd
Yanray Wang369cd962023-05-24 17:13:29 +0800459 self.fname_suffix = "-" + code_size_info.arch + "-" +\
460 code_size_info.config
Yanray Wangfc6ed4d2023-07-14 17:33:09 +0800461 self.code_size_generator = CodeSizeGeneratorWithSize()
Xiaofei Baibca03e52021-09-09 09:42:37 +0000462
Yanray Wang5e9130a2023-07-17 11:55:54 +0800463 def cal_code_size(self, revision: str):
464 """Calculate code size of library objects in a UTF-8 encoding"""
Xiaofei Baibca03e52021-09-09 09:42:37 +0000465
Yanray Wang5e9130a2023-07-17 11:55:54 +0800466 return CodeSizeCalculator(revision, self.make_cmd).\
Yanray Wange0e27602023-07-14 17:37:45 +0800467 cal_libraries_code_size()
Yanray Wang8804db92023-05-30 18:18:18 +0800468
Yanray Wang5e9130a2023-07-17 11:55:54 +0800469 def gen_code_size_report(self, revision):
470 """Generate code size record and write it into a file."""
Xiaofei Baibca03e52021-09-09 09:42:37 +0000471
Yanray Wang5e9130a2023-07-17 11:55:54 +0800472 output_file = os.path.join(self.csv_dir,\
473 revision + self.fname_suffix + ".csv")
Xiaofei Baibca03e52021-09-09 09:42:37 +0000474 # Check if the corresponding record exists
Yanray Wang5e9130a2023-07-17 11:55:54 +0800475 if (revision != "current") and os.path.exists(output_file):
Xiaofei Baibca03e52021-09-09 09:42:37 +0000476 print("Code size csv file for", revision, "already exists.")
Yanray Wang5e9130a2023-07-17 11:55:54 +0800477 self.code_size_generator.read_size_record(revision, output_file)
Xiaofei Baibca03e52021-09-09 09:42:37 +0000478 else:
Yanray Wang5e9130a2023-07-17 11:55:54 +0800479 self.code_size_generator.size_generator_write_record(revision,\
480 self.cal_code_size(revision), output_file)
Xiaofei Baibca03e52021-09-09 09:42:37 +0000481
Yanray Wang5e9130a2023-07-17 11:55:54 +0800482 def gen_code_size_comparison(self) -> int:
483 """Generate results of code size changes between two revisions,
Xiaofei Baibca03e52021-09-09 09:42:37 +0000484 old and new. Measured code size results of these two revisions
Xiaofei Bai2400b502021-10-21 12:22:58 +0000485 must be available."""
Xiaofei Baibca03e52021-09-09 09:42:37 +0000486
Yanray Wang5e9130a2023-07-17 11:55:54 +0800487 output_file = os.path.join(self.result_dir, "compare-" +
488 self.old_rev + "-" + self.new_rev +
489 self.fname_suffix + ".csv")
Xiaofei Bai184e8b62021-10-26 09:23:42 +0000490
Yanray Wangc7a2a6d2023-05-31 15:47:25 +0800491 print("\nGenerating comparison results between",\
492 self.old_rev, "and", self.new_rev)
Yanray Wange0e27602023-07-14 17:37:45 +0800493 self.code_size_generator.size_generator_write_comparison(\
Yanray Wang5e9130a2023-07-17 11:55:54 +0800494 self.old_rev, self.new_rev, output_file)
Xiaofei Bai2400b502021-10-21 12:22:58 +0000495 return 0
Xiaofei Baibca03e52021-09-09 09:42:37 +0000496
Yanray Wang72b105f2023-05-31 15:20:39 +0800497 def get_comparision_results(self) -> int:
Xiaofei Baibca03e52021-09-09 09:42:37 +0000498 """Compare size of library/*.o between self.old_rev and self.new_rev,
499 and generate the result file."""
Gilles Peskined9071e72022-09-18 21:17:09 +0200500 build_tree.check_repo_path()
Yanray Wang5e9130a2023-07-17 11:55:54 +0800501 self.gen_code_size_report(self.old_rev)
502 self.gen_code_size_report(self.new_rev)
503 return self.gen_code_size_comparison()
Xiaofei Baibca03e52021-09-09 09:42:37 +0000504
Xiaofei Bai2400b502021-10-21 12:22:58 +0000505def main():
Yanray Wang502c54f2023-05-31 11:41:36 +0800506 parser = argparse.ArgumentParser(description=(__doc__))
507 group_required = parser.add_argument_group(
508 'required arguments',
509 'required arguments to parse for running ' + os.path.basename(__file__))
510 group_required.add_argument(
511 "-o", "--old-rev", type=str, required=True,
512 help="old revision for comparison.")
513
514 group_optional = parser.add_argument_group(
515 'optional arguments',
516 'optional arguments to parse for running ' + os.path.basename(__file__))
517 group_optional.add_argument(
Xiaofei Baibca03e52021-09-09 09:42:37 +0000518 "-r", "--result-dir", type=str, default="comparison",
519 help="directory where comparison result is stored, \
Yanray Wang502c54f2023-05-31 11:41:36 +0800520 default is comparison")
521 group_optional.add_argument(
Xiaofei Bai184e8b62021-10-26 09:23:42 +0000522 "-n", "--new-rev", type=str, default=None,
523 help="new revision for comparison, default is the current work \
Yanray Wang502c54f2023-05-31 11:41:36 +0800524 directory, including uncommitted changes.")
525 group_optional.add_argument(
Yanray Wang23bd5322023-05-24 11:03:59 +0800526 "-a", "--arch", type=str, default=detect_arch(),
527 choices=list(map(lambda s: s.value, SupportedArch)),
528 help="specify architecture for code size comparison, default is the\
Yanray Wang502c54f2023-05-31 11:41:36 +0800529 host architecture.")
530 group_optional.add_argument(
Yanray Wang6a862582023-05-24 12:24:38 +0800531 "-c", "--config", type=str, default=SupportedConfig.DEFAULT.value,
532 choices=list(map(lambda s: s.value, SupportedConfig)),
533 help="specify configuration type for code size comparison,\
Yanray Wang502c54f2023-05-31 11:41:36 +0800534 default is the current MbedTLS configuration.")
Xiaofei Baibca03e52021-09-09 09:42:37 +0000535 comp_args = parser.parse_args()
536
537 if os.path.isfile(comp_args.result_dir):
538 print("Error: {} is not a directory".format(comp_args.result_dir))
539 parser.exit()
540
Yanray Wange0e27602023-07-14 17:37:45 +0800541 validate_res = CodeSizeCalculator.validate_revision(comp_args.old_rev)
Xiaofei Baiccd738b2021-11-03 07:12:31 +0000542 old_revision = validate_res.decode().replace("\n", "")
Xiaofei Bai2400b502021-10-21 12:22:58 +0000543
Xiaofei Bai184e8b62021-10-26 09:23:42 +0000544 if comp_args.new_rev is not None:
Yanray Wange0e27602023-07-14 17:37:45 +0800545 validate_res = CodeSizeCalculator.validate_revision(comp_args.new_rev)
Xiaofei Baiccd738b2021-11-03 07:12:31 +0000546 new_revision = validate_res.decode().replace("\n", "")
Xiaofei Bai184e8b62021-10-26 09:23:42 +0000547 else:
548 new_revision = "current"
Xiaofei Bai2400b502021-10-21 12:22:58 +0000549
Yanray Wang21f17442023-06-01 11:29:06 +0800550 code_size_info = CodeSizeInfo(comp_args.arch, comp_args.config,
551 detect_arch())
Yanray Wangc7a2a6d2023-05-31 15:47:25 +0800552 print("Measure code size for architecture: {}, configuration: {}\n"
Yanray Wangaba71582023-05-29 16:45:56 +0800553 .format(code_size_info.arch, code_size_info.config))
Xiaofei Baibca03e52021-09-09 09:42:37 +0000554 result_dir = comp_args.result_dir
Yanray Wang6a862582023-05-24 12:24:38 +0800555 size_compare = CodeSizeComparison(old_revision, new_revision, result_dir,
556 code_size_info)
Xiaofei Baibca03e52021-09-09 09:42:37 +0000557 return_code = size_compare.get_comparision_results()
558 sys.exit(return_code)
559
560
561if __name__ == "__main__":
Xiaofei Bai2400b502021-10-21 12:22:58 +0000562 main()