2017-10-09 19:26:19 +00:00
|
|
|
# Copyright 2017 The Chromium Authors. All rights reserved.
|
|
|
|
# Use of this source code is governed by a BSD-style license that can be
|
|
|
|
# found in the LICENSE file.
|
|
|
|
|
|
|
|
|
|
|
|
# Recipe for uploading Coverage results.
|
|
|
|
|
|
|
|
|
|
|
|
import calendar
|
|
|
|
|
|
|
|
|
|
|
|
DEPS = [
|
2017-10-17 17:40:52 +00:00
|
|
|
'gsutil',
|
|
|
|
'recipe_engine/file',
|
2017-10-09 19:26:19 +00:00
|
|
|
'recipe_engine/json',
|
|
|
|
'recipe_engine/path',
|
|
|
|
'recipe_engine/properties',
|
2017-10-17 17:40:52 +00:00
|
|
|
'recipe_engine/python',
|
|
|
|
'recipe_engine/raw_io',
|
2017-10-09 19:26:19 +00:00
|
|
|
'recipe_engine/step',
|
|
|
|
'recipe_engine/time',
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
TRY_JOB_FOLDER = 'trybot/%s/%s/' # % (issue_number, patchset_number)
|
|
|
|
COMMIT_FOLDER = 'commit/%s/' # % (git_revision)
|
|
|
|
|
2017-10-17 17:40:52 +00:00
|
|
|
RAW_FILE = '*.profraw'
|
2017-10-09 19:26:19 +00:00
|
|
|
PARSED_FILE = '%s.profdata'
|
|
|
|
SUMMARY_FILE = '%s.summary'
|
2017-10-17 17:40:52 +00:00
|
|
|
|
|
|
|
COVERAGE_RAW_ARCHIVE = '%s.profraw.tar.gz'
|
2017-10-09 19:26:19 +00:00
|
|
|
# Text is an easier format to read with machines (e.g. for Gerrit).
|
|
|
|
COVERAGE_TEXT_FILE = '%s.text.tar'
|
|
|
|
# HTML is a quick and dirty browsable format. (e.g. for coverage.skia.org)
|
|
|
|
COVERAGE_HTML_FILE = '%s.html.tar'
|
|
|
|
|
|
|
|
def RunSteps(api):
|
|
|
|
# See https://clang.llvm.org/docs/SourceBasedCodeCoverage.html for a
|
|
|
|
# detailed explanation of getting code coverage from LLVM.
|
|
|
|
# Since we have already compiled the binary with the special flags
|
|
|
|
# and run the executable to generate an output.profraw, we
|
|
|
|
# need to merge and index the data, create the coverage output,
|
|
|
|
# and then upload the results to GCS. We also upload the intermediate
|
|
|
|
# results to GCS so we can regenerate reports if needed.
|
|
|
|
builder_name = api.properties['buildername']
|
|
|
|
bucket = api.properties['gs_bucket']
|
|
|
|
|
2017-10-17 17:40:52 +00:00
|
|
|
# The raw data files are brought in as isolated inputs. It is possible
|
|
|
|
# for there to be 1 if the coverage task wasn't broken up.
|
2018-04-17 19:55:57 +00:00
|
|
|
raw_inputs = api.file.glob_paths(
|
|
|
|
'find raw inputs', api.path['start_dir'].join('coverage'),
|
|
|
|
RAW_FILE, test_data=['a.raw', 'b.raw', 'c.raw'])
|
2017-10-17 17:40:52 +00:00
|
|
|
|
|
|
|
|
2017-10-09 19:26:19 +00:00
|
|
|
# The instrumented executable is brought in as an isolated input.
|
2018-06-01 14:08:53 +00:00
|
|
|
executable = api.path['start_dir'].join('build', 'dm')
|
2017-10-09 19:26:19 +00:00
|
|
|
# clang_dir is brought in via CIPD.
|
|
|
|
clang_dir = api.path['start_dir'].join('clang_linux', 'bin')
|
|
|
|
|
|
|
|
revision = api.properties['revision']
|
|
|
|
path = COMMIT_FOLDER % revision
|
|
|
|
|
|
|
|
issue = api.properties.get('patch_issue')
|
|
|
|
patchset = api.properties.get('patch_set')
|
|
|
|
if issue and patchset:
|
|
|
|
path = TRY_JOB_FOLDER % (issue, patchset)
|
|
|
|
|
2017-10-17 17:40:52 +00:00
|
|
|
# Upload the raw files, tarred together to decrease upload time and
|
|
|
|
# improve compression.
|
|
|
|
tar_file = api.path['start_dir'].join('raw_data.profraw.tar.gz')
|
|
|
|
cmd = ['tar', '-zcvf', tar_file]
|
|
|
|
cmd.extend(raw_inputs)
|
|
|
|
api.step('create raw data archive', cmd=cmd)
|
|
|
|
|
|
|
|
gcs_file = COVERAGE_RAW_ARCHIVE % builder_name
|
|
|
|
api.gsutil.cp('raw data archive', tar_file,
|
|
|
|
'gs://%s/%s%s' % (bucket, path, gcs_file))
|
2017-10-09 19:26:19 +00:00
|
|
|
|
2017-10-17 17:40:52 +00:00
|
|
|
# Merge all the raw data files together, then index the data.
|
|
|
|
# This creates one cohesive
|
2017-10-09 19:26:19 +00:00
|
|
|
indexed_data = api.path['start_dir'].join('output.profdata')
|
2017-10-17 17:40:52 +00:00
|
|
|
cmd = [clang_dir.join('llvm-profdata'),
|
|
|
|
'merge',
|
|
|
|
'-sparse',
|
|
|
|
'-o',
|
|
|
|
indexed_data]
|
|
|
|
cmd.extend(raw_inputs)
|
2017-10-09 19:26:19 +00:00
|
|
|
api.step('merge and index',
|
2017-10-17 17:40:52 +00:00
|
|
|
cmd=cmd)
|
2017-10-09 19:26:19 +00:00
|
|
|
|
|
|
|
gcs_file = PARSED_FILE % builder_name
|
|
|
|
api.gsutil.cp('parsed data', indexed_data,
|
2018-01-16 21:06:09 +00:00
|
|
|
'gs://%s/%s%s' % (bucket, path, gcs_file), extra_args=['-Z'])
|
2017-10-09 19:26:19 +00:00
|
|
|
|
|
|
|
# Create text coverage output
|
|
|
|
output_data = api.path['start_dir'].join('coverage_text')
|
|
|
|
api.step('create text summary',
|
|
|
|
cmd=[clang_dir.join('llvm-cov'),
|
|
|
|
'show',
|
|
|
|
executable,
|
|
|
|
'-instr-profile=' + str(indexed_data),
|
|
|
|
'-use-color=0',
|
|
|
|
'-format=text',
|
|
|
|
'-output-dir=' + str(output_data)])
|
|
|
|
|
|
|
|
# Upload the summary by itself so we can get easier access to it (instead of
|
|
|
|
# downloading and untarring all the coverage data.
|
|
|
|
gcs_file = SUMMARY_FILE % builder_name
|
|
|
|
api.gsutil.cp('coverage summary', output_data.join('index.txt'),
|
2018-01-16 21:06:09 +00:00
|
|
|
'gs://%s/%s%s' % (bucket, path, gcs_file), extra_args=['-Z'])
|
2017-10-09 19:26:19 +00:00
|
|
|
|
|
|
|
tar_file = api.path['start_dir'].join('coverage.text.tar')
|
|
|
|
|
|
|
|
# Tar and upload the coverage data. We tar it to ease downloading/ingestion,
|
|
|
|
# otherwise, there is a 1:1 mapping of source code files -> coverage files.
|
|
|
|
api.step('create text coverage archive', cmd=['tar', '-cvf',
|
|
|
|
tar_file, output_data])
|
|
|
|
|
|
|
|
gcs_file = COVERAGE_TEXT_FILE % builder_name
|
|
|
|
api.gsutil.cp('text coverage data', tar_file,
|
2018-01-16 21:06:09 +00:00
|
|
|
'gs://%s/%s%s' % (bucket, path, gcs_file), extra_args=['-Z'])
|
2017-10-09 19:26:19 +00:00
|
|
|
|
|
|
|
# Create html coverage output
|
|
|
|
output_data = api.path['start_dir'].join('coverage_html')
|
|
|
|
api.step('create html summary',
|
|
|
|
cmd=[clang_dir.join('llvm-cov'),
|
|
|
|
'show',
|
|
|
|
executable,
|
|
|
|
'-instr-profile=' + str(indexed_data),
|
|
|
|
'-use-color=1',
|
|
|
|
'-format=html',
|
|
|
|
'-output-dir=' + str(output_data)])
|
|
|
|
|
|
|
|
tar_file = api.path['start_dir'].join('coverage.html.tar')
|
|
|
|
|
|
|
|
# Tar and upload the coverage data. We tar it to ease downloading/ingestion,
|
|
|
|
# otherwise, there is a 1:1 mapping of source code files -> coverage files.
|
|
|
|
api.step('create html coverage archive',
|
|
|
|
cmd=['tar', '-cvf', tar_file, output_data])
|
|
|
|
|
|
|
|
gcs_file = COVERAGE_HTML_FILE % builder_name
|
|
|
|
api.gsutil.cp('html coverage data', tar_file,
|
2018-01-16 21:06:09 +00:00
|
|
|
'gs://%s/%s%s' % (bucket, path, gcs_file), extra_args=['-Z'])
|
2017-10-09 19:26:19 +00:00
|
|
|
|
|
|
|
|
|
|
|
def GenTests(api):
|
2017-10-16 01:05:58 +00:00
|
|
|
builder = 'Test-Debian9-GCC-GCE-CPU-AVX2-x86_64-Debug-All'
|
2017-10-09 19:26:19 +00:00
|
|
|
yield (
|
|
|
|
api.test('normal_bot') +
|
|
|
|
api.properties(buildername=builder,
|
|
|
|
gs_bucket='skia-coverage',
|
|
|
|
revision='abc123',
|
|
|
|
path_config='kitchen')
|
|
|
|
)
|
|
|
|
|
|
|
|
yield (
|
|
|
|
api.test('alternate_bucket') +
|
|
|
|
api.properties(buildername=builder,
|
|
|
|
gs_bucket='skia-coverage-alt',
|
|
|
|
revision='abc123',
|
|
|
|
path_config='kitchen')
|
|
|
|
)
|
|
|
|
|
|
|
|
yield (
|
|
|
|
api.test('failed_once') +
|
|
|
|
api.properties(buildername=builder,
|
|
|
|
gs_bucket='skia-coverage',
|
|
|
|
revision='abc123',
|
|
|
|
path_config='kitchen') +
|
2017-10-17 17:40:52 +00:00
|
|
|
api.step_data('upload parsed data', retcode=1)
|
2017-10-09 19:26:19 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
yield (
|
|
|
|
api.test('failed_all') +
|
|
|
|
api.properties(buildername=builder,
|
|
|
|
gs_bucket='skia-coverage',
|
|
|
|
revision='abc123',
|
|
|
|
path_config='kitchen') +
|
2017-10-17 17:40:52 +00:00
|
|
|
api.step_data('upload parsed data', retcode=1) +
|
|
|
|
api.step_data('upload parsed data (attempt 2)', retcode=1) +
|
|
|
|
api.step_data('upload parsed data (attempt 3)', retcode=1) +
|
|
|
|
api.step_data('upload parsed data (attempt 4)', retcode=1) +
|
|
|
|
api.step_data('upload parsed data (attempt 5)', retcode=1)
|
2017-10-09 19:26:19 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
yield (
|
|
|
|
api.test('trybot') +
|
|
|
|
api.properties(
|
|
|
|
buildername=builder,
|
|
|
|
gs_bucket='skia-coverage',
|
|
|
|
revision='abc123',
|
|
|
|
path_config='kitchen',
|
|
|
|
patch_storage='gerrit') +
|
|
|
|
api.properties.tryserver(
|
|
|
|
buildername=builder,
|
|
|
|
gerrit_project='skia',
|
|
|
|
gerrit_url='https://skia-review.googlesource.com/',
|
|
|
|
)
|
|
|
|
)
|