code_size_compare: add logging module and tweak prompt message
Signed-off-by: Yanray Wang <yanray.wang@arm.com>
diff --git a/scripts/code_size_compare.py b/scripts/code_size_compare.py
index 0bd9143..dc41d26 100755
--- a/scripts/code_size_compare.py
+++ b/scripts/code_size_compare.py
@@ -24,6 +24,7 @@
# limitations under the License.
import argparse
+import logging
import os
import re
import subprocess
@@ -32,8 +33,9 @@
from enum import Enum
from types import SimpleNamespace
-from mbedtls_dev import typing_util
from mbedtls_dev import build_tree
+from mbedtls_dev import logging_util
+from mbedtls_dev import typing_util
class SupportedArch(Enum):
"""Supported architecture for code size measurement."""
@@ -91,7 +93,8 @@
def __init__(
self,
size_version: SimpleNamespace,
- host_arch: str
+ host_arch: str,
+ logger: logging.Logger,
) -> None:
"""
size_version: SimpleNamespace containing info for code size measurement.
@@ -101,6 +104,7 @@
"""
self.size_version = size_version
self.host_arch = host_arch
+ self.logger = logger
def infer_make_command(self) -> str:
"""Infer build command based on architecture and configuration."""
@@ -116,16 +120,20 @@
-DMBEDTLS_CONFIG_FILE=\\\"' + CONFIG_TFM_MEDIUM_MBEDCRYPTO_H + '\\\" \
-DMBEDTLS_PSA_CRYPTO_CONFIG_FILE=\\\"' + CONFIG_TFM_MEDIUM_PSA_CRYPTO_H + '\\\" \''
else:
- print("Unsupported combination of architecture: {} and configuration: {}"
- .format(self.size_version.arch, self.size_version.config))
- print("\nPlease use supported combination of architecture and configuration:")
+ self.logger.error("Unsupported combination of architecture: {} " \
+ "and configuration: {}.\n"
+ .format(self.size_version.arch,
+ self.size_version.config))
+ self.logger.info("Please use supported combination of " \
+ "architecture and configuration:")
for comb in CodeSizeBuildInfo.SupportedArchConfig:
- print(comb)
- print("\nFor your system, please use:")
+ self.logger.info(comb)
+ self.logger.info("")
+ self.logger.info("For your system, please use:")
for comb in CodeSizeBuildInfo.SupportedArchConfig:
if "default" in comb and self.host_arch not in comb:
continue
- print(comb)
+ self.logger.info(comb)
sys.exit(1)
@@ -138,7 +146,8 @@
self,
revision: str,
make_cmd: str,
- measure_cmd: str
+ measure_cmd: str,
+ logger: logging.Logger,
) -> None:
"""
revision: Git revision.(E.g: commit)
@@ -152,6 +161,7 @@
self.revision = revision
self.make_cmd = make_cmd
self.measure_cmd = measure_cmd
+ self.logger = logger
@staticmethod
def validate_revision(revision: str) -> bytes:
@@ -159,19 +169,21 @@
revision + "^{commit}"], shell=False)
return result
- def _create_git_worktree(self, revision: str) -> str:
+ def _create_git_worktree(self) -> str:
"""Make a separate worktree for revision.
Do not modify the current worktree."""
- if revision == "current":
- print("Using current work directory")
+ if self.revision == "current":
+ self.logger.debug("Using current work directory.")
git_worktree_path = self.repo_path
else:
- print("Creating git worktree for", revision)
- git_worktree_path = os.path.join(self.repo_path, "temp-" + revision)
+ self.logger.debug("Creating git worktree for {}."
+ .format(self.revision))
+ git_worktree_path = os.path.join(self.repo_path,
+ "temp-" + self.revision)
subprocess.check_output(
[self.git_command, "worktree", "add", "--detach",
- git_worktree_path, revision], cwd=self.repo_path,
+ git_worktree_path, self.revision], cwd=self.repo_path,
stderr=subprocess.STDOUT
)
@@ -180,6 +192,8 @@
def _build_libraries(self, git_worktree_path: str) -> None:
"""Build libraries in the specified worktree."""
+ self.logger.debug("Building objects of library for {}."
+ .format(self.revision))
my_environment = os.environ.copy()
try:
subprocess.check_output(
@@ -193,12 +207,12 @@
except subprocess.CalledProcessError as e:
self._handle_called_process_error(e, git_worktree_path)
- def _gen_raw_code_size(self, revision, git_worktree_path):
+ def _gen_raw_code_size(self, git_worktree_path: str) -> typing.Dict:
"""Calculate code size with measurement tool in UTF-8 encoding."""
- if revision == "current":
- print("Measuring code size in current work directory")
- else:
- print("Measuring code size for", revision)
+
+ self.logger.debug("Measuring code size for {} by `{}`."
+ .format(self.revision,
+ self.measure_cmd.strip().split(' ')[0]))
res = {}
for mod, st_lib in MBEDTLS_STATIC_LIB.items():
@@ -216,7 +230,8 @@
def _remove_worktree(self, git_worktree_path: str) -> None:
"""Remove temporary worktree."""
if git_worktree_path != self.repo_path:
- print("Removing temporary worktree", git_worktree_path)
+ self.logger.debug("Removing temporary worktree {}."
+ .format(git_worktree_path))
subprocess.check_output(
[self.git_command, "worktree", "remove", "--force",
git_worktree_path], cwd=self.repo_path,
@@ -229,9 +244,8 @@
Remove any extra worktrees so that the script may be called again."""
# Tell the user what went wrong
- print("The following command: {} failed and exited with code {}"
- .format(e.cmd, e.returncode))
- print("Process output:\n {}".format(str(e.output, "utf-8")))
+ self.logger.error(e, exc_info=True)
+ self.logger.error("Process output:\n {}".format(str(e.output, "utf-8")))
# Quit gracefully by removing the existing worktree
self._remove_worktree(git_worktree_path)
@@ -240,10 +254,9 @@
def cal_libraries_code_size(self) -> typing.Dict:
"""Calculate code size of libraries by measurement tool."""
- revision = self.revision
- git_worktree_path = self._create_git_worktree(revision)
+ git_worktree_path = self._create_git_worktree()
self._build_libraries(git_worktree_path)
- res = self._gen_raw_code_size(revision, git_worktree_path)
+ res = self._gen_raw_code_size(git_worktree_path)
self._remove_worktree(git_worktree_path)
return res
@@ -256,6 +269,9 @@
size_generator_write_record and size_generator_write_comparison methods,
then call both of them with proper arguments.
"""
+ def __init__(self, logger: logging.Logger) -> None:
+ self.logger = logger
+
def size_generator_write_record(
self,
revision: str,
@@ -301,7 +317,7 @@
self.bss = bss
self.total = dec # total <=> dec
- def __init__(self) -> None:
+ def __init__(self, logger: logging.Logger) -> None:
""" Variable code_size is used to store size info for any revisions.
code_size: (data format)
{revision: {module: {file_name: [text, data, bss, dec],
@@ -312,6 +328,7 @@
etc ...
}
"""
+ super().__init__(logger)
self.code_size = {} #type: typing.Dict[str, typing.Dict]
def set_size_record(self, revision: str, mod: str, size_text: str) -> None:
@@ -458,10 +475,11 @@
) -> None:
"""Write size record into a specified file based on Git revision and
output from `size` tool."""
+ self.logger.debug("Generating code size csv for {}.".format(revision))
+
for mod, size_text in code_size_text.items():
self.set_size_record(revision, mod, size_text)
- print("Generating code size csv for", revision)
output = open(output_file, "w")
self.write_size_record(revision, output)
@@ -473,6 +491,9 @@
result_options: SimpleNamespace
) -> None:
"""Write a comparision result into a stream between two revisions."""
+ self.logger.debug("Generating comparison results between {} and {}."
+ .format(old_rev, new_rev))
+
if result_options.stdout:
output = sys.stdout
else:
@@ -488,6 +509,7 @@
old_size_version: SimpleNamespace,
new_size_version: SimpleNamespace,
code_size_common: SimpleNamespace,
+ logger: logging.Logger,
) -> None:
"""
old_revision: revision to compare against.
@@ -501,36 +523,40 @@
self.csv_dir = os.path.abspath("code_size_records/")
os.makedirs(self.csv_dir, exist_ok=True)
+ self.logger = logger
+
self.old_size_version = old_size_version
self.new_size_version = new_size_version
self.code_size_common = code_size_common
- self.old_size_version.make_cmd = \
- CodeSizeBuildInfo(self.old_size_version,\
- self.code_size_common.host_arch).infer_make_command()
- self.new_size_version.make_cmd = \
- CodeSizeBuildInfo(self.new_size_version,\
- self.code_size_common.host_arch).infer_make_command()
+ self.old_size_version.make_cmd = CodeSizeBuildInfo(
+ self.old_size_version, self.code_size_common.host_arch,
+ self.logger).infer_make_command()
+ self.new_size_version.make_cmd = CodeSizeBuildInfo(
+ self.new_size_version, self.code_size_common.host_arch,
+ self.logger).infer_make_command()
self.git_command = "git"
self.make_clean = 'make clean'
- self.code_size_generator = self.__init_code_size_generator__(\
- self.code_size_common.measure_cmd)
+ self.code_size_generator = self.__generate_size_parser()
- @staticmethod
- def __init_code_size_generator__(measure_cmd):
- if re.match(r'size', measure_cmd.strip()):
- return CodeSizeGeneratorWithSize()
+ def __generate_size_parser(self):
+ if re.match(r'size', self.code_size_common.measure_cmd.strip()):
+ return CodeSizeGeneratorWithSize(self.logger)
else:
- print("Error: unsupported tool:", measure_cmd.strip().split(' ')[0])
+ self.logger.error("Unsupported measurement tool: `{}`."
+ .format(self.code_size_common.measure_cmd
+ .strip().split(' ')[0]))
sys.exit(1)
def cal_code_size(self, size_version: SimpleNamespace):
"""Calculate code size of library objects in a UTF-8 encoding"""
- return CodeSizeCalculator(size_version.revision, size_version.make_cmd,\
- self.code_size_common.measure_cmd).cal_libraries_code_size()
+ return CodeSizeCalculator(size_version.revision, size_version.make_cmd,
+ self.code_size_common.measure_cmd,
+ self.logger).cal_libraries_code_size()
def gen_file_name(self, old_size_version, new_size_version=None):
+ """Generate a literal string as csv file name."""
if new_size_version:
return '{}-{}-{}-{}-{}-{}-{}.csv'\
.format(old_size_version.revision[:7],
@@ -547,11 +573,17 @@
def gen_code_size_report(self, size_version: SimpleNamespace):
"""Generate code size record and write it into a file."""
- output_file = os.path.join(self.csv_dir, self.gen_file_name(size_version))
+ self.logger.info("Start to generate code size record for {}."
+ .format(size_version.revision))
+ output_file = os.path.join(self.csv_dir,
+ self.gen_file_name(size_version))
# Check if the corresponding record exists
- if (size_version.revision != "current") and os.path.exists(output_file):
- print("Code size csv file for", size_version.revision, "already exists.")
- self.code_size_generator.read_size_record(size_version.revision, output_file)
+ if size_version.revision != "current" and \
+ os.path.exists(output_file):
+ self.logger.debug("Code size csv file for {} already exists."
+ .format(size_version.revision))
+ self.code_size_generator.read_size_record(
+ size_version.revision, output_file)
else:
self.code_size_generator.size_generator_write_record(\
size_version.revision, self.cal_code_size(size_version),
@@ -562,14 +594,18 @@
old and new. Measured code size results of these two revisions
must be available."""
- output_file = os.path.join(self.result_dir,\
- self.gen_file_name(self.old_size_version, self.new_size_version))
+ self.logger.info("Start to generate comparision result between "\
+ "{} and {}."
+ .format(self.old_size_version.revision,
+ self.new_size_version.revision))
+ output_file = os.path.join(
+ self.result_dir,
+ self.gen_file_name(self.old_size_version, self.new_size_version))
- print("\nGenerating comparison results between",\
- self.old_size_version.revision, "and", self.new_size_version.revision)
- self.code_size_generator.size_generator_write_comparison(\
- self.old_size_version.revision, self.new_size_version.revision,\
- output_file, self.code_size_common.result_options)
+ self.code_size_generator.size_generator_write_comparison(
+ self.old_size_version.revision, self.new_size_version.revision,
+ output_file, self.code_size_common.result_options)
+
return 0
def get_comparision_results(self) -> int:
@@ -619,10 +655,17 @@
'--stdout', action='store_true', dest='stdout',
help="Set this option to direct comparison result into sys.stdout.\
(Default: file)")
+ group_optional.add_argument(
+ '--verbose', action='store_true', dest='verbose',
+ help="Show logs in detail for code size measurement. (Default: False)")
comp_args = parser.parse_args()
+ logger = logging.getLogger()
+ logging_util.configure_logger(logger)
+ logger.setLevel(logging.DEBUG if comp_args.verbose else logging.INFO)
+
if os.path.isfile(comp_args.result_dir):
- print("Error: {} is not a directory".format(comp_args.result_dir))
+ logger.error("{} is not a directory".format(comp_args.result_dir))
parser.exit()
validate_res = CodeSizeCalculator.validate_revision(comp_args.old_rev)
@@ -658,11 +701,16 @@
measure_cmd='size -t',
)
+ logger.info("Measure code size between {}:{}-{} and {}:{}-{} by `{}`."
+ .format(old_size_version.revision, old_size_version.config,
+ old_size_version.arch,
+ new_size_version.revision, old_size_version.config,
+ new_size_version.arch,
+ code_size_common.measure_cmd.strip().split(' ')[0]))
size_compare = CodeSizeComparison(old_size_version, new_size_version,\
- code_size_common)
+ code_size_common, logger)
return_code = size_compare.get_comparision_results()
sys.exit(return_code)
-
if __name__ == "__main__":
main()