code_size_compare: make CodeSizeBuildInfo more flexible
This commit changes how to infer make command. Although we haven't supported to pass more options in command line, this is the preparation work to support those features. Signed-off-by: Yanray Wang <yanray.wang@arm.com>
This commit is contained in:
parent
955671b0ef
commit
5605c6f58f
1 changed files with 119 additions and 30 deletions
|
@ -27,6 +27,7 @@ import argparse
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
import typing
|
import typing
|
||||||
|
@ -45,8 +46,6 @@ class SupportedArch(Enum):
|
||||||
X86 = 'x86'
|
X86 = 'x86'
|
||||||
|
|
||||||
|
|
||||||
CONFIG_TFM_MEDIUM_MBEDCRYPTO_H = '../configs/tfm_mbedcrypto_config_profile_medium.h'
|
|
||||||
CONFIG_TFM_MEDIUM_PSA_CRYPTO_H = '../configs/crypto_config_profile_medium.h'
|
|
||||||
class SupportedConfig(Enum):
|
class SupportedConfig(Enum):
|
||||||
"""Supported configuration for code size measurement."""
|
"""Supported configuration for code size measurement."""
|
||||||
DEFAULT = 'default'
|
DEFAULT = 'default'
|
||||||
|
@ -69,7 +68,8 @@ class CodeSizeDistinctInfo: # pylint: disable=too-few-public-methods
|
||||||
git_rev: str,
|
git_rev: str,
|
||||||
arch: str,
|
arch: str,
|
||||||
config: str,
|
config: str,
|
||||||
make_cmd: str,
|
compiler: str,
|
||||||
|
opt_level: str,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""
|
"""
|
||||||
:param: version: which version to compare with for code size.
|
:param: version: which version to compare with for code size.
|
||||||
|
@ -77,13 +77,18 @@ class CodeSizeDistinctInfo: # pylint: disable=too-few-public-methods
|
||||||
:param: arch: architecture to measure code size on.
|
:param: arch: architecture to measure code size on.
|
||||||
:param: config: Configuration type to calculate code size.
|
:param: config: Configuration type to calculate code size.
|
||||||
(See SupportedConfig)
|
(See SupportedConfig)
|
||||||
:param: make_cmd: make command to build library/*.o.
|
:param: compiler: compiler used to build library/*.o.
|
||||||
|
:param: opt_level: Options that control optimization. (E.g. -Os)
|
||||||
"""
|
"""
|
||||||
self.version = version
|
self.version = version
|
||||||
self.git_rev = git_rev
|
self.git_rev = git_rev
|
||||||
self.arch = arch
|
self.arch = arch
|
||||||
self.config = config
|
self.config = config
|
||||||
self.make_cmd = make_cmd
|
self.compiler = compiler
|
||||||
|
self.opt_level = opt_level
|
||||||
|
# Note: Variables below are not initialized by class instantiation.
|
||||||
|
self.pre_make_cmd = [] #type: typing.List[str]
|
||||||
|
self.make_cmd = ''
|
||||||
|
|
||||||
|
|
||||||
class CodeSizeCommonInfo: # pylint: disable=too-few-public-methods
|
class CodeSizeCommonInfo: # pylint: disable=too-few-public-methods
|
||||||
|
@ -140,6 +145,13 @@ def detect_arch() -> str:
|
||||||
print("Unknown host architecture, cannot auto-detect arch.")
|
print("Unknown host architecture, cannot auto-detect arch.")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
TFM_MEDIUM_CONFIG_H = 'configs/tfm_mbedcrypto_config_profile_medium.h'
|
||||||
|
TFM_MEDIUM_CRYPTO_CONFIG_H = 'configs/crypto_config_profile_medium.h'
|
||||||
|
|
||||||
|
CONFIG_H = 'include/mbedtls/mbedtls_config.h'
|
||||||
|
CRYPTO_CONFIG_H = 'include/psa/crypto_config.h'
|
||||||
|
BACKUP_SUFFIX = '.code_size.bak'
|
||||||
|
|
||||||
class CodeSizeBuildInfo: # pylint: disable=too-few-public-methods
|
class CodeSizeBuildInfo: # pylint: disable=too-few-public-methods
|
||||||
"""Gather information used to measure code size.
|
"""Gather information used to measure code size.
|
||||||
|
|
||||||
|
@ -167,34 +179,79 @@ class CodeSizeBuildInfo: # pylint: disable=too-few-public-methods
|
||||||
- size_dist_info.arch: architecture to measure code size on.
|
- size_dist_info.arch: architecture to measure code size on.
|
||||||
- size_dist_info.config: configuration type to measure
|
- size_dist_info.config: configuration type to measure
|
||||||
code size with.
|
code size with.
|
||||||
|
- size_dist_info.compiler: compiler used to build library/*.o.
|
||||||
|
- size_dist_info.opt_level: Options that control optimization.
|
||||||
|
(E.g. -Os)
|
||||||
:param host_arch: host architecture.
|
:param host_arch: host architecture.
|
||||||
:param logger: logging module
|
:param logger: logging module
|
||||||
"""
|
"""
|
||||||
self.size_dist_info = size_dist_info
|
self.arch = size_dist_info.arch
|
||||||
|
self.config = size_dist_info.config
|
||||||
|
self.compiler = size_dist_info.compiler
|
||||||
|
self.opt_level = size_dist_info.opt_level
|
||||||
|
|
||||||
|
self.make_cmd = ['make', '-j', 'lib']
|
||||||
|
|
||||||
self.host_arch = host_arch
|
self.host_arch = host_arch
|
||||||
self.logger = logger
|
self.logger = logger
|
||||||
|
|
||||||
def infer_make_command(self) -> str:
|
def check_correctness(self) -> bool:
|
||||||
"""Infer make command based on architecture and configuration."""
|
"""Check whether we are using proper / supported combination
|
||||||
|
of information to build library/*.o."""
|
||||||
|
|
||||||
# make command by default
|
# default config
|
||||||
if self.size_dist_info.config == SupportedConfig.DEFAULT.value and \
|
if self.config == SupportedConfig.DEFAULT.value and \
|
||||||
self.size_dist_info.arch == self.host_arch:
|
self.arch == self.host_arch:
|
||||||
return 'make -j lib CFLAGS=\'-Os \' '
|
return True
|
||||||
# make command for TF-M
|
# TF-M
|
||||||
elif self.size_dist_info.arch == SupportedArch.ARMV8_M.value and \
|
elif self.arch == SupportedArch.ARMV8_M.value and \
|
||||||
self.size_dist_info.config == SupportedConfig.TFM_MEDIUM.value:
|
self.config == SupportedConfig.TFM_MEDIUM.value:
|
||||||
return \
|
return True
|
||||||
'make -j lib CC=armclang \
|
|
||||||
CFLAGS=\'--target=arm-arm-none-eabi -mcpu=cortex-m33 -Os \
|
return False
|
||||||
-DMBEDTLS_CONFIG_FILE=\\\"' + CONFIG_TFM_MEDIUM_MBEDCRYPTO_H + '\\\" \
|
|
||||||
-DMBEDTLS_PSA_CRYPTO_CONFIG_FILE=\\\"' + CONFIG_TFM_MEDIUM_PSA_CRYPTO_H + '\\\" \''
|
def infer_pre_make_command(self) -> typing.List[str]:
|
||||||
# unsupported combinations
|
"""Infer command to set up proper configuration before running make."""
|
||||||
|
pre_make_cmd = [] #type: typing.List[str]
|
||||||
|
if self.config == SupportedConfig.TFM_MEDIUM.value:
|
||||||
|
pre_make_cmd.append('cp -r {} {}'
|
||||||
|
.format(TFM_MEDIUM_CONFIG_H, CONFIG_H))
|
||||||
|
pre_make_cmd.append('cp -r {} {}'
|
||||||
|
.format(TFM_MEDIUM_CRYPTO_CONFIG_H,
|
||||||
|
CRYPTO_CONFIG_H))
|
||||||
|
|
||||||
|
return pre_make_cmd
|
||||||
|
|
||||||
|
def infer_make_cflags(self) -> str:
|
||||||
|
"""Infer CFLAGS by instance attributes in CodeSizeDistinctInfo."""
|
||||||
|
cflags = [] #type: typing.List[str]
|
||||||
|
|
||||||
|
# set optimization level
|
||||||
|
cflags.append(self.opt_level)
|
||||||
|
# set compiler by config
|
||||||
|
if self.config == SupportedConfig.TFM_MEDIUM.value:
|
||||||
|
self.compiler = 'armclang'
|
||||||
|
cflags.append('-mcpu=cortex-m33')
|
||||||
|
# set target
|
||||||
|
if self.compiler == 'armclang':
|
||||||
|
cflags.append('--target=arm-arm-none-eabi')
|
||||||
|
|
||||||
|
return ' '.join(cflags)
|
||||||
|
|
||||||
|
def infer_make_command(self) -> str:
|
||||||
|
"""Infer make command by CFLAGS and CC."""
|
||||||
|
|
||||||
|
if self.check_correctness():
|
||||||
|
# set CFLAGS=
|
||||||
|
self.make_cmd.append('CFLAGS=\'{}\''.format(self.infer_make_cflags()))
|
||||||
|
# set CC=
|
||||||
|
self.make_cmd.append('CC={}'.format(self.compiler))
|
||||||
|
return ' '.join(self.make_cmd)
|
||||||
else:
|
else:
|
||||||
self.logger.error("Unsupported combination of architecture: {} " \
|
self.logger.error("Unsupported combination of architecture: {} " \
|
||||||
"and configuration: {}.\n"
|
"and configuration: {}.\n"
|
||||||
.format(self.size_dist_info.arch,
|
.format(self.arch,
|
||||||
self.size_dist_info.config))
|
self.config))
|
||||||
self.logger.info("Please use supported combination of " \
|
self.logger.info("Please use supported combination of " \
|
||||||
"architecture and configuration:")
|
"architecture and configuration:")
|
||||||
for comb in CodeSizeBuildInfo.SupportedArchConfig:
|
for comb in CodeSizeBuildInfo.SupportedArchConfig:
|
||||||
|
@ -213,15 +270,17 @@ class CodeSizeCalculator:
|
||||||
Git revision and code size measurement tool.
|
Git revision and code size measurement tool.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(
|
def __init__( #pylint: disable=too-many-arguments
|
||||||
self,
|
self,
|
||||||
git_rev: str,
|
git_rev: str,
|
||||||
|
pre_make_cmd: typing.List[str],
|
||||||
make_cmd: str,
|
make_cmd: str,
|
||||||
measure_cmd: str,
|
measure_cmd: str,
|
||||||
logger: logging.Logger,
|
logger: logging.Logger,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""
|
"""
|
||||||
:param git_rev: Git revision. (E.g: commit)
|
:param git_rev: Git revision. (E.g: commit)
|
||||||
|
:param pre_make_cmd: command to set up proper config before running make.
|
||||||
:param make_cmd: command to build library/*.o.
|
:param make_cmd: command to build library/*.o.
|
||||||
:param measure_cmd: command to measure code size for library/*.o.
|
:param measure_cmd: command to measure code size for library/*.o.
|
||||||
:param logger: logging module
|
:param logger: logging module
|
||||||
|
@ -231,6 +290,7 @@ class CodeSizeCalculator:
|
||||||
self.make_clean = 'make clean'
|
self.make_clean = 'make clean'
|
||||||
|
|
||||||
self.git_rev = git_rev
|
self.git_rev = git_rev
|
||||||
|
self.pre_make_cmd = pre_make_cmd
|
||||||
self.make_cmd = make_cmd
|
self.make_cmd = make_cmd
|
||||||
self.measure_cmd = measure_cmd
|
self.measure_cmd = measure_cmd
|
||||||
self.logger = logger
|
self.logger = logger
|
||||||
|
@ -246,7 +306,7 @@ class CodeSizeCalculator:
|
||||||
"""Create a separate worktree for Git revision.
|
"""Create a separate worktree for Git revision.
|
||||||
If Git revision is current, use current worktree instead."""
|
If Git revision is current, use current worktree instead."""
|
||||||
|
|
||||||
if self.git_rev == "current":
|
if self.git_rev == 'current':
|
||||||
self.logger.debug("Using current work directory.")
|
self.logger.debug("Using current work directory.")
|
||||||
git_worktree_path = self.repo_path
|
git_worktree_path = self.repo_path
|
||||||
else:
|
else:
|
||||||
|
@ -262,6 +322,16 @@ class CodeSizeCalculator:
|
||||||
|
|
||||||
return git_worktree_path
|
return git_worktree_path
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def backup_config_files(restore: bool) -> None:
|
||||||
|
"""Backup / Restore config files."""
|
||||||
|
if restore:
|
||||||
|
shutil.move(CONFIG_H + BACKUP_SUFFIX, CONFIG_H)
|
||||||
|
shutil.move(CRYPTO_CONFIG_H + BACKUP_SUFFIX, CRYPTO_CONFIG_H)
|
||||||
|
else:
|
||||||
|
shutil.copy(CONFIG_H, CONFIG_H + BACKUP_SUFFIX)
|
||||||
|
shutil.copy(CRYPTO_CONFIG_H, CRYPTO_CONFIG_H + BACKUP_SUFFIX)
|
||||||
|
|
||||||
def _build_libraries(self, git_worktree_path: str) -> None:
|
def _build_libraries(self, git_worktree_path: str) -> None:
|
||||||
"""Build library/*.o in the specified worktree."""
|
"""Build library/*.o in the specified worktree."""
|
||||||
|
|
||||||
|
@ -269,6 +339,14 @@ class CodeSizeCalculator:
|
||||||
.format(self.git_rev))
|
.format(self.git_rev))
|
||||||
my_environment = os.environ.copy()
|
my_environment = os.environ.copy()
|
||||||
try:
|
try:
|
||||||
|
if self.git_rev == 'current':
|
||||||
|
self.backup_config_files(restore=False)
|
||||||
|
for pre_cmd in self.pre_make_cmd:
|
||||||
|
subprocess.check_output(
|
||||||
|
pre_cmd, env=my_environment, shell=True,
|
||||||
|
cwd=git_worktree_path, stderr=subprocess.STDOUT,
|
||||||
|
universal_newlines=True
|
||||||
|
)
|
||||||
subprocess.check_output(
|
subprocess.check_output(
|
||||||
self.make_clean, env=my_environment, shell=True,
|
self.make_clean, env=my_environment, shell=True,
|
||||||
cwd=git_worktree_path, stderr=subprocess.STDOUT,
|
cwd=git_worktree_path, stderr=subprocess.STDOUT,
|
||||||
|
@ -279,6 +357,8 @@ class CodeSizeCalculator:
|
||||||
cwd=git_worktree_path, stderr=subprocess.STDOUT,
|
cwd=git_worktree_path, stderr=subprocess.STDOUT,
|
||||||
universal_newlines=True
|
universal_newlines=True
|
||||||
)
|
)
|
||||||
|
if self.git_rev == 'current':
|
||||||
|
self.backup_config_files(restore=True)
|
||||||
except subprocess.CalledProcessError as e:
|
except subprocess.CalledProcessError as e:
|
||||||
self._handle_called_process_error(e, git_worktree_path)
|
self._handle_called_process_error(e, git_worktree_path)
|
||||||
|
|
||||||
|
@ -628,6 +708,13 @@ class CodeSizeComparison:
|
||||||
self.old_size_dist_info = old_size_dist_info
|
self.old_size_dist_info = old_size_dist_info
|
||||||
self.new_size_dist_info = new_size_dist_info
|
self.new_size_dist_info = new_size_dist_info
|
||||||
self.size_common_info = size_common_info
|
self.size_common_info = size_common_info
|
||||||
|
# infer pre make command
|
||||||
|
self.old_size_dist_info.pre_make_cmd = CodeSizeBuildInfo(
|
||||||
|
self.old_size_dist_info, self.size_common_info.host_arch,
|
||||||
|
self.logger).infer_pre_make_command()
|
||||||
|
self.new_size_dist_info.pre_make_cmd = CodeSizeBuildInfo(
|
||||||
|
self.new_size_dist_info, self.size_common_info.host_arch,
|
||||||
|
self.logger).infer_pre_make_command()
|
||||||
# infer make command
|
# infer make command
|
||||||
self.old_size_dist_info.make_cmd = CodeSizeBuildInfo(
|
self.old_size_dist_info.make_cmd = CodeSizeBuildInfo(
|
||||||
self.old_size_dist_info, self.size_common_info.host_arch,
|
self.old_size_dist_info, self.size_common_info.host_arch,
|
||||||
|
@ -654,7 +741,6 @@ class CodeSizeComparison:
|
||||||
.strip().split(' ')[0]))
|
.strip().split(' ')[0]))
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
def cal_code_size(
|
def cal_code_size(
|
||||||
self,
|
self,
|
||||||
size_dist_info: CodeSizeDistinctInfo
|
size_dist_info: CodeSizeDistinctInfo
|
||||||
|
@ -662,6 +748,7 @@ class CodeSizeComparison:
|
||||||
"""Calculate code size of library/*.o in a UTF-8 encoding"""
|
"""Calculate code size of library/*.o in a UTF-8 encoding"""
|
||||||
|
|
||||||
return CodeSizeCalculator(size_dist_info.git_rev,
|
return CodeSizeCalculator(size_dist_info.git_rev,
|
||||||
|
size_dist_info.pre_make_cmd,
|
||||||
size_dist_info.make_cmd,
|
size_dist_info.make_cmd,
|
||||||
self.size_common_info.measure_cmd,
|
self.size_common_info.measure_cmd,
|
||||||
self.logger).cal_libraries_code_size()
|
self.logger).cal_libraries_code_size()
|
||||||
|
@ -737,7 +824,6 @@ class CodeSizeComparison:
|
||||||
self.gen_code_size_report(self.new_size_dist_info)
|
self.gen_code_size_report(self.new_size_dist_info)
|
||||||
self.gen_code_size_comparison()
|
self.gen_code_size_comparison()
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = argparse.ArgumentParser(description=(__doc__))
|
parser = argparse.ArgumentParser(description=(__doc__))
|
||||||
group_required = parser.add_argument_group(
|
group_required = parser.add_argument_group(
|
||||||
|
@ -800,14 +886,17 @@ def main():
|
||||||
new_revision = CodeSizeCalculator.validate_git_revision(
|
new_revision = CodeSizeCalculator.validate_git_revision(
|
||||||
comp_args.new_rev)
|
comp_args.new_rev)
|
||||||
else:
|
else:
|
||||||
new_revision = "current"
|
new_revision = 'current'
|
||||||
|
|
||||||
|
# version, git_rev, arch, config, compiler, opt_level
|
||||||
old_size_dist_info = CodeSizeDistinctInfo(
|
old_size_dist_info = CodeSizeDistinctInfo(
|
||||||
'old', old_revision, comp_args.arch, comp_args.config, '')
|
'old', old_revision, comp_args.arch, comp_args.config, 'cc', '-Os')
|
||||||
new_size_dist_info = CodeSizeDistinctInfo(
|
new_size_dist_info = CodeSizeDistinctInfo(
|
||||||
'new', new_revision, comp_args.arch, comp_args.config, '')
|
'new', new_revision, comp_args.arch, comp_args.config, 'cc', '-Os')
|
||||||
|
# host_arch, measure_cmd
|
||||||
size_common_info = CodeSizeCommonInfo(
|
size_common_info = CodeSizeCommonInfo(
|
||||||
detect_arch(), 'size -t')
|
detect_arch(), 'size -t')
|
||||||
|
# record_dir, comp_dir, with_markdown, stdout
|
||||||
result_options = CodeSizeResultInfo(
|
result_options = CodeSizeResultInfo(
|
||||||
comp_args.record_dir, comp_args.comp_dir,
|
comp_args.record_dir, comp_args.comp_dir,
|
||||||
comp_args.markdown, comp_args.stdout)
|
comp_args.markdown, comp_args.stdout)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue