blob: 01d93cad0fc8f0d335dcc7c847a0e6f7725bb8ce [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 make_command: command to build library (Inferred from arch and config).
96 """
97 self.arch = arch
98 self.config = config
Yanray Wang21f17442023-06-01 11:29:06 +080099 self.sys_arch = sys_arch
Yanray Wang6a862582023-05-24 12:24:38 +0800100 self.make_command = self.set_make_command()
101
102 def set_make_command(self) -> str:
103 """Infer build command based on architecture and configuration."""
104
Yanray Wang21f17442023-06-01 11:29:06 +0800105 if self.config == SupportedConfig.DEFAULT.value and \
106 self.arch == self.sys_arch:
Yanray Wang6a862582023-05-24 12:24:38 +0800107 return 'make -j lib CFLAGS=\'-Os \' '
Yanray Wangaba71582023-05-29 16:45:56 +0800108 elif self.arch == SupportedArch.ARMV8_M.value and \
Yanray Wang6a862582023-05-24 12:24:38 +0800109 self.config == SupportedConfig.TFM_MEDIUM.value:
110 return \
Yanray Wang60430bd2023-05-29 14:48:18 +0800111 'make -j lib CC=armclang \
Yanray Wang6a862582023-05-24 12:24:38 +0800112 CFLAGS=\'--target=arm-arm-none-eabi -mcpu=cortex-m33 -Os \
113 -DMBEDTLS_CONFIG_FILE=\\\"' + CONFIG_TFM_MEDIUM_MBEDCRYPTO_H + '\\\" \
114 -DMBEDTLS_PSA_CRYPTO_CONFIG_FILE=\\\"' + CONFIG_TFM_MEDIUM_PSA_CRYPTO_H + '\\\" \''
115 else:
Yanray Wang21f17442023-06-01 11:29:06 +0800116 print("Unsupported combination of architecture: {} and configuration: {}"
Yanray Wang6a862582023-05-24 12:24:38 +0800117 .format(self.arch, self.config))
Yanray Wangc18cd892023-05-31 11:08:04 +0800118 print("\nPlease use supported combination of architecture and configuration:")
119 for comb in CodeSizeInfo.SupportedArchConfig:
120 print(comb)
Yanray Wang21f17442023-06-01 11:29:06 +0800121 print("\nFor your system, please use:")
122 for comb in CodeSizeInfo.SupportedArchConfig:
123 if "default" in comb and self.sys_arch not in comb:
124 continue
125 print(comb)
Yanray Wang6a862582023-05-24 12:24:38 +0800126 sys.exit(1)
127
128
Yanray Wange0e27602023-07-14 17:37:45 +0800129class CodeSizeCalculator:
130 """ A calculator to calculate code size of library objects based on
131 Git revision and code size measurement tool.
132 """
133
134 def __init__(
135 self,
136 revision: str,
137 make_cmd: str,
138 ) -> None:
139 """
140 revision: Git revision.(E.g: commit)
141 make_cmd: command to build library objects.
142 """
143 self.repo_path = "."
144 self.git_command = "git"
145 self.make_clean = 'make clean'
146
147 self.revision = revision
148 self.make_cmd = make_cmd
149
150 @staticmethod
151 def validate_revision(revision: str) -> bytes:
152 result = subprocess.check_output(["git", "rev-parse", "--verify",
153 revision + "^{commit}"], shell=False)
154 return result
155
156 def _create_git_worktree(self, revision: str) -> str:
157 """Make a separate worktree for revision.
158 Do not modify the current worktree."""
159
160 if revision == "current":
161 print("Using current work directory")
162 git_worktree_path = self.repo_path
163 else:
164 print("Creating git worktree for", revision)
165 git_worktree_path = os.path.join(self.repo_path, "temp-" + revision)
166 subprocess.check_output(
167 [self.git_command, "worktree", "add", "--detach",
168 git_worktree_path, revision], cwd=self.repo_path,
169 stderr=subprocess.STDOUT
170 )
171
172 return git_worktree_path
173
174 def _build_libraries(self, git_worktree_path: str) -> None:
175 """Build libraries in the specified worktree."""
176
177 my_environment = os.environ.copy()
178 try:
179 subprocess.check_output(
180 self.make_clean, env=my_environment, shell=True,
181 cwd=git_worktree_path, stderr=subprocess.STDOUT,
182 )
183 subprocess.check_output(
184 self.make_cmd, env=my_environment, shell=True,
185 cwd=git_worktree_path, stderr=subprocess.STDOUT,
186 )
187 except subprocess.CalledProcessError as e:
188 self._handle_called_process_error(e, git_worktree_path)
189
190 def _gen_raw_code_size(self, revision, git_worktree_path):
191 """Calculate code size with measurement tool in UTF-8 encoding."""
192 if revision == "current":
193 print("Measuring code size in current work directory")
194 else:
195 print("Measuring code size for", revision)
196
197 res = {}
198 for mod, st_lib in MBEDTLS_STATIC_LIB.items():
199 try:
200 result = subprocess.check_output(
201 ["size", st_lib, "-t"], cwd=git_worktree_path,
202 universal_newlines=True
203 )
204 res[mod] = result
205 except subprocess.CalledProcessError as e:
206 self._handle_called_process_error(e, git_worktree_path)
207
208 return res
209
210 def _remove_worktree(self, git_worktree_path: str) -> None:
211 """Remove temporary worktree."""
212 if git_worktree_path != self.repo_path:
213 print("Removing temporary worktree", git_worktree_path)
214 subprocess.check_output(
215 [self.git_command, "worktree", "remove", "--force",
216 git_worktree_path], cwd=self.repo_path,
217 stderr=subprocess.STDOUT
218 )
219
220 def _handle_called_process_error(self, e: subprocess.CalledProcessError,
221 git_worktree_path: str) -> None:
222 """Handle a CalledProcessError and quit the program gracefully.
223 Remove any extra worktrees so that the script may be called again."""
224
225 # Tell the user what went wrong
226 print("The following command: {} failed and exited with code {}"
227 .format(e.cmd, e.returncode))
228 print("Process output:\n {}".format(str(e.output, "utf-8")))
229
230 # Quit gracefully by removing the existing worktree
231 self._remove_worktree(git_worktree_path)
232 sys.exit(-1)
233
234 def cal_libraries_code_size(self) -> typing.Dict:
235 """Calculate code size of libraries by measurement tool."""
236
237 revision = self.revision
238 git_worktree_path = self._create_git_worktree(revision)
239 self._build_libraries(git_worktree_path)
240 res = self._gen_raw_code_size(revision, git_worktree_path)
241 self._remove_worktree(git_worktree_path)
242
243 return res
244
245
Yanray Wang15c43f32023-07-17 11:17:12 +0800246class CodeSizeGenerator:
247 """ A generator based on size measurement tool for library objects.
248
249 This is an abstract class. To use it, derive a class that implements
250 size_generator_write_record and size_generator_write_comparison methods,
251 then call both of them with proper arguments.
252 """
253 def size_generator_write_record(
254 self,
255 revision: str,
256 code_size_text: typing.Dict,
257 output_file: str
258 ) -> None:
259 """Write size record into a file.
260
261 revision: Git revision.(E.g: commit)
262 code_size_text: text output (utf-8) from code size measurement tool.
263 output_file: file which the code size record is written to.
264 """
265 raise NotImplementedError
266
267 def size_generator_write_comparison(
268 self,
269 old_rev: str,
270 new_rev: str,
271 output_stream
272 ) -> None:
273 """Write a comparision result into a stream between two revisions.
274
275 old_rev: old git revision to compared with.
276 new_rev: new git revision to compared with.
277 output_stream: stream which the code size record is written to.
278 (E.g: file / sys.stdout)
279 """
280 raise NotImplementedError
281
282
283class CodeSizeGeneratorWithSize(CodeSizeGenerator):
Yanray Wang16ebc572023-05-30 18:10:20 +0800284 """Code Size Base Class for size record saving and writing."""
285
Yanray Wangfc6ed4d2023-07-14 17:33:09 +0800286 class SizeEntry: # pylint: disable=too-few-public-methods
287 """Data Structure to only store information of code size."""
288 def __init__(self, text, data, bss, dec):
289 self.text = text
290 self.data = data
291 self.bss = bss
292 self.total = dec # total <=> dec
293
Yanray Wang16ebc572023-05-30 18:10:20 +0800294 def __init__(self) -> None:
295 """ Variable code_size is used to store size info for any revisions.
296 code_size: (data format)
297 {revision: {module: {file_name: SizeEntry,
298 etc ...
299 },
300 etc ...
301 },
302 etc ...
303 }
304 """
305 self.code_size = {} #type: typing.Dict[str, typing.Dict]
306
307 def set_size_record(self, revision: str, mod: str, size_text: str) -> None:
308 """Store size information for target revision and high-level module.
309
310 size_text Format: text data bss dec hex filename
311 """
312 size_record = {}
313 for line in size_text.splitlines()[1:]:
314 data = line.split()
Yanray Wangfc6ed4d2023-07-14 17:33:09 +0800315 size_record[data[5]] = CodeSizeGeneratorWithSize.SizeEntry(\
316 data[0], data[1], data[2], data[3])
Yanray Wang16ebc572023-05-30 18:10:20 +0800317 if revision in self.code_size:
318 self.code_size[revision].update({mod: size_record})
319 else:
320 self.code_size[revision] = {mod: size_record}
321
322 def read_size_record(self, revision: str, fname: str) -> None:
323 """Read size information from csv file and write it into code_size.
324
325 fname Format: filename text data bss dec
326 """
327 mod = ""
328 size_record = {}
329 with open(fname, 'r') as csv_file:
330 for line in csv_file:
331 data = line.strip().split()
332 # check if we find the beginning of a module
333 if data and data[0] in MBEDTLS_STATIC_LIB:
334 mod = data[0]
335 continue
336
337 if mod:
338 size_record[data[0]] = \
Yanray Wangfc6ed4d2023-07-14 17:33:09 +0800339 CodeSizeGeneratorWithSize.SizeEntry(\
340 data[1], data[2], data[3], data[4])
Yanray Wang16ebc572023-05-30 18:10:20 +0800341
342 # check if we hit record for the end of a module
343 m = re.match(r'.?TOTALS', line)
344 if m:
345 if revision in self.code_size:
346 self.code_size[revision].update({mod: size_record})
347 else:
348 self.code_size[revision] = {mod: size_record}
349 mod = ""
350 size_record = {}
351
352 def _size_reader_helper(
353 self,
354 revision: str,
355 output: typing_util.Writable
356 ) -> typing.Iterator[tuple]:
357 """A helper function to peel code_size based on revision."""
358 for mod, file_size in self.code_size[revision].items():
359 output.write("\n" + mod + "\n")
360 for fname, size_entry in file_size.items():
361 yield mod, fname, size_entry
362
363 def write_size_record(
364 self,
365 revision: str,
366 output: typing_util.Writable
367 ) -> None:
368 """Write size information to a file.
369
370 Writing Format: file_name text data bss total(dec)
371 """
372 output.write("{:<30} {:>7} {:>7} {:>7} {:>7}\n"
373 .format("filename", "text", "data", "bss", "total"))
374 for _, fname, size_entry in self._size_reader_helper(revision, output):
375 output.write("{:<30} {:>7} {:>7} {:>7} {:>7}\n"
376 .format(fname, size_entry.text, size_entry.data,\
377 size_entry.bss, size_entry.total))
378
379 def write_comparison(
380 self,
381 old_rev: str,
382 new_rev: str,
383 output: typing_util.Writable
384 ) -> None:
385 """Write comparison result into a file.
386
387 Writing Format: file_name current(total) old(total) change(Byte) change_pct(%)
388 """
389 output.write("{:<30} {:>7} {:>7} {:>7} {:>7}\n"
390 .format("filename", "current", "old", "change", "change%"))
391 for mod, fname, size_entry in self._size_reader_helper(new_rev, output):
392 new_size = int(size_entry.total)
393 # check if we have the file in old revision
394 if fname in self.code_size[old_rev][mod]:
395 old_size = int(self.code_size[old_rev][mod][fname].total)
396 change = new_size - old_size
397 if old_size != 0:
398 change_pct = change / old_size
399 else:
400 change_pct = 0
401 output.write("{:<30} {:>7} {:>7} {:>7} {:>7.2%}\n"
402 .format(fname, new_size, old_size, change, change_pct))
403 else:
404 output.write("{} {}\n".format(fname, new_size))
405
Yanray Wang15c43f32023-07-17 11:17:12 +0800406 def size_generator_write_record(
407 self,
408 revision: str,
409 code_size_text: typing.Dict,
410 output_file: str
411 ) -> None:
412 """Write size record into a specified file based on Git revision and
413 output from `size` tool."""
414 for mod, size_text in code_size_text.items():
415 self.set_size_record(revision, mod, size_text)
416
417 print("Generating code size csv for", revision)
418 output = open(output_file, "w")
419 self.write_size_record(revision, output)
420
421 def size_generator_write_comparison(
422 self,
423 old_rev: str,
424 new_rev: str,
425 output_stream
426 ) -> None:
427 """Write a comparision result into a stream between two revisions."""
428 output = open(output_stream, "w")
429 self.write_comparison(old_rev, new_rev, output)
430
Yanray Wang16ebc572023-05-30 18:10:20 +0800431
Yanray Wangfc6ed4d2023-07-14 17:33:09 +0800432class CodeSizeComparison:
Xiaofei Bai2400b502021-10-21 12:22:58 +0000433 """Compare code size between two Git revisions."""
Xiaofei Baibca03e52021-09-09 09:42:37 +0000434
Yanray Wang72b105f2023-05-31 15:20:39 +0800435 def __init__(
436 self,
437 old_revision: str,
438 new_revision: str,
439 result_dir: str,
440 code_size_info: CodeSizeInfo
441 ) -> None:
Xiaofei Baibca03e52021-09-09 09:42:37 +0000442 """
Yanray Wang6a862582023-05-24 12:24:38 +0800443 old_revision: revision to compare against.
Xiaofei Baibca03e52021-09-09 09:42:37 +0000444 new_revision:
Yanray Wang6a862582023-05-24 12:24:38 +0800445 result_dir: directory for comparison result.
446 code_size_info: an object containing information to build library.
Xiaofei Baibca03e52021-09-09 09:42:37 +0000447 """
448 self.repo_path = "."
449 self.result_dir = os.path.abspath(result_dir)
Xiaofei Bai184e8b62021-10-26 09:23:42 +0000450 os.makedirs(self.result_dir, exist_ok=True)
Xiaofei Baibca03e52021-09-09 09:42:37 +0000451
452 self.csv_dir = os.path.abspath("code_size_records/")
Xiaofei Bai184e8b62021-10-26 09:23:42 +0000453 os.makedirs(self.csv_dir, exist_ok=True)
Xiaofei Baibca03e52021-09-09 09:42:37 +0000454
455 self.old_rev = old_revision
456 self.new_rev = new_revision
457 self.git_command = "git"
Yanray Wang4c26db02023-07-04 16:49:04 +0800458 self.make_clean = 'make clean'
Yanray Wang6a862582023-05-24 12:24:38 +0800459 self.make_command = code_size_info.make_command
Yanray Wang369cd962023-05-24 17:13:29 +0800460 self.fname_suffix = "-" + code_size_info.arch + "-" +\
461 code_size_info.config
Yanray Wangfc6ed4d2023-07-14 17:33:09 +0800462 self.code_size_generator = CodeSizeGeneratorWithSize()
Xiaofei Baibca03e52021-09-09 09:42:37 +0000463
Yanray Wange0e27602023-07-14 17:37:45 +0800464 def _gen_code_size_csv(self, revision: str) -> None:
Xiaofei Baibca03e52021-09-09 09:42:37 +0000465 """Generate code size csv file."""
466
Xiaofei Bai184e8b62021-10-26 09:23:42 +0000467 if revision == "current":
Yanray Wangc7a2a6d2023-05-31 15:47:25 +0800468 print("Measuring code size in current work directory")
Xiaofei Bai184e8b62021-10-26 09:23:42 +0000469 else:
470 print("Measuring code size for", revision)
Yanray Wang8804db92023-05-30 18:18:18 +0800471
Yanray Wange0e27602023-07-14 17:37:45 +0800472 code_size_text = CodeSizeCalculator(revision, self.make_command).\
473 cal_libraries_code_size()
Yanray Wang8804db92023-05-30 18:18:18 +0800474
Yanray Wange0e27602023-07-14 17:37:45 +0800475 csv_file = os.path.join(self.csv_dir, revision +
476 self.fname_suffix + ".csv")
477 self.code_size_generator.size_generator_write_record(revision,\
478 code_size_text, csv_file)
Xiaofei Baibca03e52021-09-09 09:42:37 +0000479
Yanray Wang72b105f2023-05-31 15:20:39 +0800480 def _get_code_size_for_rev(self, revision: str) -> None:
Xiaofei Baibca03e52021-09-09 09:42:37 +0000481 """Generate code size csv file for the specified git revision."""
482
483 # Check if the corresponding record exists
Yanray Wang369cd962023-05-24 17:13:29 +0800484 csv_fname = revision + self.fname_suffix + ".csv"
Xiaofei Bai184e8b62021-10-26 09:23:42 +0000485 if (revision != "current") and \
Xiaofei Baibca03e52021-09-09 09:42:37 +0000486 os.path.exists(os.path.join(self.csv_dir, csv_fname)):
487 print("Code size csv file for", revision, "already exists.")
Yanray Wangfc6ed4d2023-07-14 17:33:09 +0800488 self.code_size_generator.read_size_record(revision,\
489 os.path.join(self.csv_dir, csv_fname))
Xiaofei Baibca03e52021-09-09 09:42:37 +0000490 else:
Yanray Wange0e27602023-07-14 17:37:45 +0800491 self._gen_code_size_csv(revision)
Xiaofei Baibca03e52021-09-09 09:42:37 +0000492
Yanray Wang72b105f2023-05-31 15:20:39 +0800493 def _gen_code_size_comparison(self) -> int:
Xiaofei Baibca03e52021-09-09 09:42:37 +0000494 """Generate results of the size changes between two revisions,
495 old and new. Measured code size results of these two revisions
Xiaofei Bai2400b502021-10-21 12:22:58 +0000496 must be available."""
Xiaofei Baibca03e52021-09-09 09:42:37 +0000497
Yanray Wange0e27602023-07-14 17:37:45 +0800498 res_file = os.path.join(self.result_dir, "compare-" +
499 self.old_rev + "-" + self.new_rev +
500 self.fname_suffix + ".csv")
Xiaofei Bai184e8b62021-10-26 09:23:42 +0000501
Yanray Wangc7a2a6d2023-05-31 15:47:25 +0800502 print("\nGenerating comparison results between",\
503 self.old_rev, "and", self.new_rev)
Yanray Wange0e27602023-07-14 17:37:45 +0800504 self.code_size_generator.size_generator_write_comparison(\
505 self.old_rev, self.new_rev, res_file)
Xiaofei Baibca03e52021-09-09 09:42:37 +0000506
Xiaofei Bai2400b502021-10-21 12:22:58 +0000507 return 0
Xiaofei Baibca03e52021-09-09 09:42:37 +0000508
Yanray Wang72b105f2023-05-31 15:20:39 +0800509 def get_comparision_results(self) -> int:
Xiaofei Baibca03e52021-09-09 09:42:37 +0000510 """Compare size of library/*.o between self.old_rev and self.new_rev,
511 and generate the result file."""
Gilles Peskined9071e72022-09-18 21:17:09 +0200512 build_tree.check_repo_path()
Xiaofei Baibca03e52021-09-09 09:42:37 +0000513 self._get_code_size_for_rev(self.old_rev)
514 self._get_code_size_for_rev(self.new_rev)
Yanray Wang8804db92023-05-30 18:18:18 +0800515 return self._gen_code_size_comparison()
Xiaofei Baibca03e52021-09-09 09:42:37 +0000516
Xiaofei Bai2400b502021-10-21 12:22:58 +0000517def main():
Yanray Wang502c54f2023-05-31 11:41:36 +0800518 parser = argparse.ArgumentParser(description=(__doc__))
519 group_required = parser.add_argument_group(
520 'required arguments',
521 'required arguments to parse for running ' + os.path.basename(__file__))
522 group_required.add_argument(
523 "-o", "--old-rev", type=str, required=True,
524 help="old revision for comparison.")
525
526 group_optional = parser.add_argument_group(
527 'optional arguments',
528 'optional arguments to parse for running ' + os.path.basename(__file__))
529 group_optional.add_argument(
Xiaofei Baibca03e52021-09-09 09:42:37 +0000530 "-r", "--result-dir", type=str, default="comparison",
531 help="directory where comparison result is stored, \
Yanray Wang502c54f2023-05-31 11:41:36 +0800532 default is comparison")
533 group_optional.add_argument(
Xiaofei Bai184e8b62021-10-26 09:23:42 +0000534 "-n", "--new-rev", type=str, default=None,
535 help="new revision for comparison, default is the current work \
Yanray Wang502c54f2023-05-31 11:41:36 +0800536 directory, including uncommitted changes.")
537 group_optional.add_argument(
Yanray Wang23bd5322023-05-24 11:03:59 +0800538 "-a", "--arch", type=str, default=detect_arch(),
539 choices=list(map(lambda s: s.value, SupportedArch)),
540 help="specify architecture for code size comparison, default is the\
Yanray Wang502c54f2023-05-31 11:41:36 +0800541 host architecture.")
542 group_optional.add_argument(
Yanray Wang6a862582023-05-24 12:24:38 +0800543 "-c", "--config", type=str, default=SupportedConfig.DEFAULT.value,
544 choices=list(map(lambda s: s.value, SupportedConfig)),
545 help="specify configuration type for code size comparison,\
Yanray Wang502c54f2023-05-31 11:41:36 +0800546 default is the current MbedTLS configuration.")
Xiaofei Baibca03e52021-09-09 09:42:37 +0000547 comp_args = parser.parse_args()
548
549 if os.path.isfile(comp_args.result_dir):
550 print("Error: {} is not a directory".format(comp_args.result_dir))
551 parser.exit()
552
Yanray Wange0e27602023-07-14 17:37:45 +0800553 validate_res = CodeSizeCalculator.validate_revision(comp_args.old_rev)
Xiaofei Baiccd738b2021-11-03 07:12:31 +0000554 old_revision = validate_res.decode().replace("\n", "")
Xiaofei Bai2400b502021-10-21 12:22:58 +0000555
Xiaofei Bai184e8b62021-10-26 09:23:42 +0000556 if comp_args.new_rev is not None:
Yanray Wange0e27602023-07-14 17:37:45 +0800557 validate_res = CodeSizeCalculator.validate_revision(comp_args.new_rev)
Xiaofei Baiccd738b2021-11-03 07:12:31 +0000558 new_revision = validate_res.decode().replace("\n", "")
Xiaofei Bai184e8b62021-10-26 09:23:42 +0000559 else:
560 new_revision = "current"
Xiaofei Bai2400b502021-10-21 12:22:58 +0000561
Yanray Wang21f17442023-06-01 11:29:06 +0800562 code_size_info = CodeSizeInfo(comp_args.arch, comp_args.config,
563 detect_arch())
Yanray Wangc7a2a6d2023-05-31 15:47:25 +0800564 print("Measure code size for architecture: {}, configuration: {}\n"
Yanray Wangaba71582023-05-29 16:45:56 +0800565 .format(code_size_info.arch, code_size_info.config))
Xiaofei Baibca03e52021-09-09 09:42:37 +0000566 result_dir = comp_args.result_dir
Yanray Wang6a862582023-05-24 12:24:38 +0800567 size_compare = CodeSizeComparison(old_revision, new_revision, result_dir,
568 code_size_info)
Xiaofei Baibca03e52021-09-09 09:42:37 +0000569 return_code = size_compare.get_comparision_results()
570 sys.exit(return_code)
571
572
573if __name__ == "__main__":
Xiaofei Bai2400b502021-10-21 12:22:58 +0000574 main()