"""This script helps to generate source based code coverage report.
Usage:
python genReport.py --objects [OBJECTS] --format [FORMAT]
"""
# Copyright (C) 2023 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import argparse
import os
import subprocess
import sys
def genProfdata(files, llvmDir):
llvmProfdataBin = os.path.join(llvmDir,
'llvm-profdata')
# To prevent args characters from exceeding the limitation,
# we split the files into several batches and merge them one by one.
batch_size =
10
profraws_length = len(files)
profdata_list = []
for offset
in range(
0, profraws_length, batch_size):
profdata_filename = f
'{offset}.profdata'
profdata_list.append(profdata_filename)
subprocess_cmd = [llvmProfdataBin,
'merge']
subprocess_cmd.extend(files[offset:min(offset+batch_size, profraws_length)])
subprocess_cmd.extend([f
'-o={profdata_filename}'])
subprocess.call(subprocess_cmd)
subprocess_cmd = [llvmProfdataBin,
'merge']
subprocess_cmd.extend(profdata_list)
subprocess_cmd.extend([
'-o=out.profdata'])
subprocess.call(subprocess_cmd)
for profdata
in profdata_list:
os.remove(profdata)
def genHtml(llvmDir, objects, out):
llvmCovBin = os.path.join(llvmDir,
'llvm-cov')
subprocess_cmd = [
llvmCovBin,
'show',
'-instr-profile=out.profdata',
]
subprocess_cmd.extend(objects)
subprocess_cmd.extend([
'-use-color',
'--format=html'])
with(open(out+
'.html',
'w', encoding=
'utf-8'))
as f:
subprocess.call(subprocess_cmd, stdout=f)
def genJson(llvmDir, objects, out, summary_only=
True):
llvmCovBin = os.path.join(llvmDir,
'llvm-cov')
subprocess_cmd = [
llvmCovBin,
'export',
'-instr-profile=out.profdata',
]
subprocess_cmd.extend(objects)
if summary_only:
subprocess_cmd.extend([
'-summary-only'])
with(open(out+
'.json',
'w', encoding=
'utf-8'))
as f:
subprocess.call(subprocess_cmd, stdout=f)
def genLcov(llvmDir, objects, out, summary_only=
True):
llvmCovBin = os.path.join(llvmDir,
'llvm-cov')
subprocess_cmd = [
llvmCovBin,
'export',
'-format=lcov',
'-instr-profile=out.profdata',
]
subprocess_cmd.extend(objects)
if summary_only:
subprocess_cmd.extend([
'-summary-only'])
with(open(out+
'.lcov',
'w', encoding=
'utf-8'))
as f:
subprocess.call(subprocess_cmd, stdout=f)
def main():
arg_parser = argparse.ArgumentParser()
arg_parser.add_argument(
'--objects',
type=str,
required=
True,
nargs=
'+',
help=
'List the elf files which are included in the test')
arg_parser.add_argument(
'--format',
type=str,
default=
'html',
help=
'Output format of the "llvm-cov show/export" command. The '
'supported formats are "text", "html" and "lcov".')
arg_parser.add_argument(
'--llvm-dir',
type=str,
default=
'prebuilts/clang/host/linux-x86/llvm-binutils-stable/',
help=
'Provide path to LLVM binary directory to override the default '
'one')
arg_parser.add_argument(
'--profraw-dir',
type=str,
default=
'tmp/',
help=
'Provide path to directory containing .profraw files')
arg_parser.add_argument(
'--output',
type=str,
default=
'out',
help=
'Provide output filename(without extension)')
arg_parser.add_argument(
'--summary-only',
default=
True,
action=argparse.BooleanOptionalAction,
help=
'Flag of whether to enable summary only')
args = arg_parser.parse_args()
if not os.path.isdir(args.llvm_dir):
print(
'Provide path to LLVM binary directory')
return
if not os.path.isdir(args.profraw_dir):
print(
'Provide path to directory containing .profraw files')
return
profrawFiles = [
os.path.join(args.profraw_dir, f)
for f
in os.listdir(args.profraw_dir)
if f.endswith(
'.profraw')]
if len(profrawFiles) ==
0:
print(
'No profraw files found in directory ' + args.profraw_dir)
genProfdata(profrawFiles, args.llvm_dir)
objects = []
for obj
in args.objects:
objects.extend([
'-object', obj])
if args.format ==
'html':
genHtml(args.llvm_dir, objects, args.output)
elif args.format ==
'json':
genJson(args.llvm_dir, objects, args.output, args.summary_only)
elif args.format ==
'lcov':
genLcov(args.llvm_dir, objects, args.output, args.summary_only)
else:
print(
'Only json / html / lcov supported')
return
if __name__ ==
'__main__':
sys.exit(main())