Add argument to take profdata as input for code coverage script.
[email protected]
Bug: 836663
Change-Id: I55c7a7b6d5df87bec04b32b369969787321941e4
Reviewed-on: https://chromium-review.googlesource.com/1044308
Commit-Queue: Abhishek Arya <[email protected]>
Reviewed-by: Max Moroz <[email protected]>
Cr-Commit-Position: refs/heads/master@{#556049}
diff --git a/tools/code_coverage/coverage.py b/tools/code_coverage/coverage.py
index f0f99d44..843bacbc 100755
--- a/tools/code_coverage/coverage.py
+++ b/tools/code_coverage/coverage.py
@@ -314,6 +314,14 @@
html_file.write(html_header + html_table + html_footer)
+def _ConfigureLogging(args):
+ """Configures logging settings for later use."""
+ log_level = logging.DEBUG if args.verbose else logging.INFO
+ log_format = '[%(asctime)s %(levelname)s] %(message)s'
+ log_file = args.log_file if args.log_file else None
+ logging.basicConfig(filename=log_file, level=log_level, format=log_format)
+
+
def _GetSharedLibraries(binary_paths):
"""Returns set of shared libraries used by specified binaries."""
libraries = set()
@@ -322,8 +330,8 @@
if sys.platform.startswith('linux'):
cmd.extend(['ldd'])
- shared_library_re = re.compile(
- r'.*\.so\s=>\s(.*' + BUILD_DIR + '.*\.so)\s.*')
+ shared_library_re = re.compile(r'.*\.so\s=>\s(.*' + BUILD_DIR +
+ r'.*\.so)\s.*')
elif sys.platform.startswith('darwin'):
cmd.extend(['otool', '-L'])
shared_library_re = re.compile(r'\s+(@rpath/.*\.dylib)\s.*')
@@ -1202,6 +1210,26 @@
return os.path.relpath(target_path, base_dir)
+def _GetBinaryPathsFromTargets(targets, build_dir):
+ """Return binary paths from target names."""
+ # FIXME: Derive output binary from target build definitions rather than
+ # assuming that it is always the same name.
+ binary_paths = []
+ for target in targets:
+ binary_path = os.path.join(build_dir, target)
+ if _GetHostPlatform() == 'win':
+ binary_path += '.exe'
+
+ if os.path.exists(binary_path):
+ binary_paths.append(binary_path)
+ else:
+ logging.warning(
+ 'Target binary %s not found in build directory, skipping.',
+ os.path.basename(binary_path))
+
+ return binary_paths
+
+
def _ParseCommandArguments():
"""Adds and parses relevant arguments for tool comands.
@@ -1230,10 +1258,21 @@
'-c',
'--command',
action='append',
- required=True,
+ required=False,
help='Commands used to run test targets, one test target needs one and '
'only one command, when specifying commands, one should assume the '
- 'current working directory is the root of the checkout.')
+ 'current working directory is the root of the checkout. This option is '
+ 'incompatible with -p/--profdata-file option.')
+
+ arg_parser.add_argument(
+ '-p',
+ '--profdata-file',
+ type=str,
+ required=False,
+ help='Path to profdata file to use for generating code coverage reports. '
+ 'This can be useful if you generated the profdata file seperately in '
+ 'your own test harness. This option is ignored if run command(s) are '
+ 'already provided above using -c/--command option.')
arg_parser.add_argument(
'-f',
@@ -1278,36 +1317,34 @@
def Main():
"""Execute tool commands."""
- assert os.path.abspath(os.getcwd()) == SRC_ROOT_PATH, ('This script must be '
- 'called from the root '
- 'of checkout.')
+ # Change directory to source root to aid in relative paths calculations.
+ os.chdir(SRC_ROOT_PATH)
- # This helps to setup coverage binaries even when script is called with
- # empty params. This is used by coverage bot for initial setup.
+ # Setup coverage binaries even when script is called with empty params. This
+ # is used by coverage bot for initial setup.
DownloadCoverageToolsIfNeeded()
args = _ParseCommandArguments()
+ _ConfigureLogging(args)
+
global BUILD_DIR
BUILD_DIR = args.build_dir
global OUTPUT_DIR
OUTPUT_DIR = args.output_dir
- assert len(args.targets) == len(args.command), ('Number of targets must be '
- 'equal to the number of test '
- 'commands.')
+ assert args.command or args.profdata_file, (
+ 'Need to either provide commands to run using -c/--command option OR '
+ 'provide prof-data file as input using -p/--profdata-file option.')
- # logging should be configured before it is used.
- log_level = logging.DEBUG if args.verbose else logging.INFO
- log_format = '[%(asctime)s %(levelname)s] %(message)s'
- log_file = args.log_file if args.log_file else None
- logging.basicConfig(filename=log_file, level=log_level, format=log_format)
+ assert not args.command or (len(args.targets) == len(args.command)), (
+ 'Number of targets must be equal to the number of test commands.')
assert os.path.exists(BUILD_DIR), (
'Build directory: {} doesn\'t exist. '
'Please run "gn gen" to generate.').format(BUILD_DIR)
+
_ValidateCurrentPlatformIsSupported()
_ValidateBuildingWithClangCoverage()
- _VerifyTargetExecutablesAreInBuildDirectory(args.command)
absolute_filter_paths = []
if args.filters:
@@ -1316,9 +1353,18 @@
if not os.path.exists(OUTPUT_DIR):
os.makedirs(OUTPUT_DIR)
- profdata_file_path = _CreateCoverageProfileDataForTargets(
- args.targets, args.command, args.jobs)
- binary_paths = [_GetBinaryPath(command) for command in args.command]
+ # Get profdate file and list of binary paths.
+ if args.command:
+ # A list of commands are provided. Run them to generate profdata file, and
+ # create a list of binary paths from parsing commands.
+ _VerifyTargetExecutablesAreInBuildDirectory(args.command)
+ profdata_file_path = _CreateCoverageProfileDataForTargets(
+ args.targets, args.command, args.jobs)
+ binary_paths = [_GetBinaryPath(command) for command in args.command]
+ else:
+ # An input prof-data file is already provided. Just calculate binary paths.
+ profdata_file_path = args.profdata_file
+ binary_paths = _GetBinaryPathsFromTargets(args.targets, args.build_dir)
logging.info('Generating code coverage report in html (this can take a while '
'depending on size of target!)')