Commit 481d3480 authored by Yuke Liao's avatar Yuke Liao Committed by Commit Bot

[Coverage] Add debug info for diagnostics.

This CL adds an argument option to print out debug info for diagnostics.

Bug: 801231
Change-Id: I53b23c6569c9938ef4c5b5a786ceaeee751ffc5d
Reviewed-on: https://chromium-review.googlesource.com/871506Reviewed-by: default avatarAbhishek Arya <inferno@chromium.org>
Commit-Queue: Yuke Liao <liaoyuke@chromium.org>
Cr-Commit-Position: refs/heads/master@{#532530}
parent 43346bef
...@@ -54,6 +54,7 @@ import sys ...@@ -54,6 +54,7 @@ import sys
import argparse import argparse
import json import json
import logging
import os import os
import subprocess import subprocess
import urllib2 import urllib2
...@@ -331,7 +332,7 @@ def DownloadCoverageToolsIfNeeded(): ...@@ -331,7 +332,7 @@ def DownloadCoverageToolsIfNeeded():
try: try:
clang_update.DownloadAndUnpack(coverage_tools_url, clang_update.DownloadAndUnpack(coverage_tools_url,
clang_update.LLVM_BUILD_DIR) clang_update.LLVM_BUILD_DIR)
print('Coverage tools %s unpacked' % package_version) logging.info('Coverage tools %s unpacked', package_version)
with open(coverage_revision_stamp_file, 'w') as file_handle: with open(coverage_revision_stamp_file, 'w') as file_handle:
file_handle.write('%s,%s' % (package_version, platform)) file_handle.write('%s,%s' % (package_version, platform))
file_handle.write('\n') file_handle.write('\n')
...@@ -357,6 +358,8 @@ def _GenerateLineByLineFileCoverageInHtml(binary_paths, profdata_file_path, ...@@ -357,6 +358,8 @@ def _GenerateLineByLineFileCoverageInHtml(binary_paths, profdata_file_path,
# [[-object BIN]] [SOURCES] # [[-object BIN]] [SOURCES]
# NOTE: For object files, the first one is specified as a positional argument, # NOTE: For object files, the first one is specified as a positional argument,
# and the rest are specified as keyword argument. # and the rest are specified as keyword argument.
logging.debug('Generating per file line by line coverage reports using '
'"llvm-cov show" command')
subprocess_cmd = [ subprocess_cmd = [
LLVM_COV_PATH, 'show', '-format=html', LLVM_COV_PATH, 'show', '-format=html',
'-output-dir={}'.format(OUTPUT_DIR), '-output-dir={}'.format(OUTPUT_DIR),
...@@ -365,16 +368,16 @@ def _GenerateLineByLineFileCoverageInHtml(binary_paths, profdata_file_path, ...@@ -365,16 +368,16 @@ def _GenerateLineByLineFileCoverageInHtml(binary_paths, profdata_file_path,
subprocess_cmd.extend( subprocess_cmd.extend(
['-object=' + binary_path for binary_path in binary_paths[1:]]) ['-object=' + binary_path for binary_path in binary_paths[1:]])
subprocess_cmd.extend(filters) subprocess_cmd.extend(filters)
subprocess.check_call(subprocess_cmd) subprocess.check_call(subprocess_cmd)
logging.debug('Finished running "llvm-cov show" command')
def _GeneratePerDirectoryCoverageInHtml(binary_paths, profdata_file_path, def _GeneratePerDirectoryCoverageInHtml(binary_paths, profdata_file_path,
filters): filters):
"""Generates coverage breakdown per directory.""" """Generates coverage breakdown per directory."""
logging.debug('Calculating and writing per-directory coverage reports')
per_file_coverage_summary = _GeneratePerFileCoverageSummary( per_file_coverage_summary = _GeneratePerFileCoverageSummary(
binary_paths, profdata_file_path, filters) binary_paths, profdata_file_path, filters)
per_directory_coverage_summary = defaultdict( per_directory_coverage_summary = defaultdict(
lambda: _CoverageSummary(0, 0, 0, 0, 0, 0)) lambda: _CoverageSummary(0, 0, 0, 0, 0, 0))
...@@ -393,6 +396,9 @@ def _GeneratePerDirectoryCoverageInHtml(binary_paths, profdata_file_path, ...@@ -393,6 +396,9 @@ def _GeneratePerDirectoryCoverageInHtml(binary_paths, profdata_file_path,
_GenerateCoverageInHtmlForDirectory( _GenerateCoverageInHtmlForDirectory(
dir_path, per_directory_coverage_summary, per_file_coverage_summary) dir_path, per_directory_coverage_summary, per_file_coverage_summary)
logging.debug(
'Finished calculating and writing per-directory coverage reports')
def _GenerateCoverageInHtmlForDirectory( def _GenerateCoverageInHtmlForDirectory(
dir_path, per_directory_coverage_summary, per_file_coverage_summary): dir_path, per_directory_coverage_summary, per_file_coverage_summary):
...@@ -496,8 +502,7 @@ def _BuildTargets(targets, jobs_count): ...@@ -496,8 +502,7 @@ def _BuildTargets(targets, jobs_count):
build_args = _ParseArgsGnFile() build_args = _ParseArgsGnFile()
return 'use_goma' in build_args and build_args['use_goma'] == 'true' return 'use_goma' in build_args and build_args['use_goma'] == 'true'
print('Building %s' % str(targets)) logging.info('Building %s', str(targets))
if jobs_count is None and _IsGomaConfigured(): if jobs_count is None and _IsGomaConfigured():
jobs_count = DEFAULT_GOMA_JOBS jobs_count = DEFAULT_GOMA_JOBS
...@@ -507,6 +512,7 @@ def _BuildTargets(targets, jobs_count): ...@@ -507,6 +512,7 @@ def _BuildTargets(targets, jobs_count):
subprocess_cmd.extend(targets) subprocess_cmd.extend(targets)
subprocess.check_call(subprocess_cmd) subprocess.check_call(subprocess_cmd)
logging.debug('Finished building %s', str(targets))
def _GetProfileRawDataPathsByExecutingCommands(targets, commands): def _GetProfileRawDataPathsByExecutingCommands(targets, commands):
...@@ -519,6 +525,8 @@ def _GetProfileRawDataPathsByExecutingCommands(targets, commands): ...@@ -519,6 +525,8 @@ def _GetProfileRawDataPathsByExecutingCommands(targets, commands):
Returns: Returns:
A list of relative paths to the generated profraw data files. A list of relative paths to the generated profraw data files.
""" """
logging.debug('Executing the test commands')
# Remove existing profraw data files. # Remove existing profraw data files.
for file_or_dir in os.listdir(OUTPUT_DIR): for file_or_dir in os.listdir(OUTPUT_DIR):
if file_or_dir.endswith(PROFRAW_FILE_EXTENSION): if file_or_dir.endswith(PROFRAW_FILE_EXTENSION):
...@@ -528,6 +536,8 @@ def _GetProfileRawDataPathsByExecutingCommands(targets, commands): ...@@ -528,6 +536,8 @@ def _GetProfileRawDataPathsByExecutingCommands(targets, commands):
for target, command in zip(targets, commands): for target, command in zip(targets, commands):
_ExecuteCommand(target, command) _ExecuteCommand(target, command)
logging.debug('Finished executing the test commands')
profraw_file_paths = [] profraw_file_paths = []
for file_or_dir in os.listdir(OUTPUT_DIR): for file_or_dir in os.listdir(OUTPUT_DIR):
if file_or_dir.endswith(PROFRAW_FILE_EXTENSION): if file_or_dir.endswith(PROFRAW_FILE_EXTENSION):
...@@ -570,8 +580,8 @@ def _ExecuteCommand(target, command): ...@@ -570,8 +580,8 @@ def _ExecuteCommand(target, command):
output_file_name = os.extsep.join([target + '_output', 'txt']) output_file_name = os.extsep.join([target + '_output', 'txt'])
output_file_path = os.path.join(OUTPUT_DIR, output_file_name) output_file_path = os.path.join(OUTPUT_DIR, output_file_name)
print('Running command: "%s", the output is redirected to "%s"' % logging.info('Running command: "%s", the output is redirected to "%s"',
(command, output_file_path)) command, output_file_path)
output = subprocess.check_output( output = subprocess.check_output(
command.split(), env={ command.split(), env={
'LLVM_PROFILE_FILE': expected_profraw_file_path 'LLVM_PROFILE_FILE': expected_profraw_file_path
...@@ -593,10 +603,9 @@ def _CreateCoverageProfileDataFromProfRawData(profraw_file_paths): ...@@ -593,10 +603,9 @@ def _CreateCoverageProfileDataFromProfRawData(profraw_file_paths):
Raises: Raises:
CalledProcessError: An error occurred merging profraw data files. CalledProcessError: An error occurred merging profraw data files.
""" """
print('Creating the profile data file') logging.info('Creating the coverage profile data file')
logging.debug('Merging profraw files to create profdata file')
profdata_file_path = os.path.join(OUTPUT_DIR, PROFDATA_FILE_NAME) profdata_file_path = os.path.join(OUTPUT_DIR, PROFDATA_FILE_NAME)
try: try:
subprocess_cmd = [ subprocess_cmd = [
LLVM_PROFDATA_PATH, 'merge', '-o', profdata_file_path, '-sparse=true' LLVM_PROFDATA_PATH, 'merge', '-o', profdata_file_path, '-sparse=true'
...@@ -607,6 +616,9 @@ def _CreateCoverageProfileDataFromProfRawData(profraw_file_paths): ...@@ -607,6 +616,9 @@ def _CreateCoverageProfileDataFromProfRawData(profraw_file_paths):
print('Failed to merge profraw files to create profdata file') print('Failed to merge profraw files to create profdata file')
raise error raise error
logging.debug('Finished merging profraw files')
logging.info('Code coverage profile data is created as: %s',
profdata_file_path)
return profdata_file_path return profdata_file_path
...@@ -616,6 +628,8 @@ def _GeneratePerFileCoverageSummary(binary_paths, profdata_file_path, filters): ...@@ -616,6 +628,8 @@ def _GeneratePerFileCoverageSummary(binary_paths, profdata_file_path, filters):
# [[-object BIN]] [SOURCES]. # [[-object BIN]] [SOURCES].
# NOTE: For object files, the first one is specified as a positional argument, # NOTE: For object files, the first one is specified as a positional argument,
# and the rest are specified as keyword argument. # and the rest are specified as keyword argument.
logging.debug('Generating per-file code coverage summary using "llvm-cov '
'export -summary-only" command')
subprocess_cmd = [ subprocess_cmd = [
LLVM_COV_PATH, 'export', '-summary-only', LLVM_COV_PATH, 'export', '-summary-only',
'-instr-profile=' + profdata_file_path, binary_paths[0] '-instr-profile=' + profdata_file_path, binary_paths[0]
...@@ -652,6 +666,7 @@ def _GeneratePerFileCoverageSummary(binary_paths, profdata_file_path, filters): ...@@ -652,6 +666,7 @@ def _GeneratePerFileCoverageSummary(binary_paths, profdata_file_path, filters):
lines_total=summary['lines']['count'], lines_total=summary['lines']['count'],
lines_covered=summary['lines']['covered']) lines_covered=summary['lines']['covered'])
logging.debug('Finished generating per-file code coverage summary')
return per_file_coverage_summary return per_file_coverage_summary
...@@ -781,6 +796,15 @@ def _ParseCommandArguments(): ...@@ -781,6 +796,15 @@ def _ParseCommandArguments():
'will be derived based on CPUs availability. Please refer to ' 'will be derived based on CPUs availability. Please refer to '
'\'ninja -h\' for more details.') '\'ninja -h\' for more details.')
arg_parser.add_argument(
'-v',
'--verbose',
action='store_true',
help='Prints additional output for diagnostics.')
arg_parser.add_argument(
'-l', '--log_file', type=str, help='Redirects logs to a file.')
arg_parser.add_argument( arg_parser.add_argument(
'targets', nargs='+', help='The names of the test targets to run.') 'targets', nargs='+', help='The names of the test targets to run.')
...@@ -803,6 +827,11 @@ def Main(): ...@@ -803,6 +827,11 @@ def Main():
global OUTPUT_DIR global OUTPUT_DIR
OUTPUT_DIR = args.output_dir OUTPUT_DIR = args.output_dir
log_level = logging.DEBUG if args.verbose else logging.INFO
log_format = '[%(asctime)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 len(args.targets) == len(args.command), ('Number of targets must be ' assert len(args.targets) == len(args.command), ('Number of targets must be '
'equal to the number of test ' 'equal to the number of test '
'commands.') 'commands.')
...@@ -823,8 +852,8 @@ def Main(): ...@@ -823,8 +852,8 @@ def Main():
args.targets, args.command, args.jobs) args.targets, args.command, args.jobs)
binary_paths = [_GetBinaryPath(command) for command in args.command] binary_paths = [_GetBinaryPath(command) for command in args.command]
print('Generating code coverage report in html (this can take a while ' logging.info('Generating code coverage report in html (this can take a while '
'depending on size of target!)') 'depending on size of target!)')
_GenerateLineByLineFileCoverageInHtml(binary_paths, profdata_file_path, _GenerateLineByLineFileCoverageInHtml(binary_paths, profdata_file_path,
absolute_filter_paths) absolute_filter_paths)
_GeneratePerDirectoryCoverageInHtml(binary_paths, profdata_file_path, _GeneratePerDirectoryCoverageInHtml(binary_paths, profdata_file_path,
...@@ -836,8 +865,8 @@ def Main(): ...@@ -836,8 +865,8 @@ def Main():
html_index_file_path = 'file://' + os.path.abspath( html_index_file_path = 'file://' + os.path.abspath(
os.path.join(OUTPUT_DIR, 'index.html')) os.path.join(OUTPUT_DIR, 'index.html'))
print('\nCode coverage profile data is created as: %s' % profdata_file_path) logging.info('Index file for html report is generated as: %s',
print('Index file for html report is generated as: %s' % html_index_file_path) html_index_file_path)
if __name__ == '__main__': if __name__ == '__main__':
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment