1#
2# Copyright (C) 2023 The Android Open Source Project
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8#      http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
16"""
17This script helps to generate source based code coverage report.
18
19Usage:
20    python genReport.py --objects [OBJECTS] --format [FORMAT]
21
22"""
23
24import argparse
25import os
26import subprocess
27import sys
28import pathlib
29
30def genProfdata(files, llvmDir):
31    llvmProfdataBin = str(str(os.path.join(llvmDir, "./llvm-profdata")))
32    subprocess_cmd = [llvmProfdataBin, 'merge']
33
34    subprocess_cmd.extend(files)
35    subprocess_cmd.extend(['-o=out.profdata'])
36
37    subprocess.call(subprocess_cmd)
38
39def genHtml(llvmDir, objects, out):
40    llvmCovBin = str(str(os.path.join(llvmDir, "./llvm-cov")))
41    subprocess_cmd = [llvmCovBin, 'show', '-instr-profile=out.profdata', '-object']
42
43    subprocess_cmd.extend(objects)
44    subprocess_cmd.extend(['-use-color', '--format=html'])
45    with(open(out+".html", "w")) as f:
46        output = subprocess.call(subprocess_cmd, stdout=f)
47
48def genJson(llvmDir, objects, out):
49    llvmCovBin = str(str(os.path.join(llvmDir, "./llvm-cov")))
50    subprocess_cmd = [llvmCovBin, 'export', '-summary-only',
51                       '-instr-profile=out.profdata', '-object']
52
53    subprocess_cmd.extend(objects)
54    with(open(out+".json", "w")) as f:
55        output = subprocess.call(subprocess_cmd, stdout=f)
56
57
58def main():
59    arg_parser = argparse.ArgumentParser()
60
61    arg_parser.add_argument(
62        '--objects',
63        type=str,
64        required=True,
65        nargs='+',
66        help='List the elf files which are included in the test')
67
68    arg_parser.add_argument(
69        '--format',
70        type=str,
71        default='html',
72        help='Output format of the "llvm-cov show/export" command. The '
73        'supported formats are "text", "html" and "lcov".')
74
75    arg_parser.add_argument(
76        '--llvm-dir',
77        type=str,
78        default="prebuilts/clang/host/linux-x86/llvm-binutils-stable/",
79        help='Provide path to LLVM binary directory to override the default one')
80
81    arg_parser.add_argument(
82        '--profraw-dir',
83        type=str,
84        default="tmp/",
85        help='Provide path to directory containing .profraw files')
86
87    arg_parser.add_argument(
88        '--output',
89        type=str,
90        default="out",
91        help='provide output filename(without extension)')
92
93
94    args = arg_parser.parse_args()
95
96    if (not os.path.isdir(args.llvm_dir)):
97        print("Provide path to LLVM binary directory")
98        return
99
100    if (not os.path.isdir(args.profraw_dir)):
101        print("Provide path to directory containing .profraw files")
102        return
103
104    profrawFiles = [str(os.path.join(args.profraw_dir, f))
105                        for f in os.listdir(args.profraw_dir) if f.endswith('.profraw')]
106    if (len(profrawFiles) == 0):
107        print("No profraw files found in directory " + args.profraw_dir)
108
109    genProfdata(profrawFiles, args.llvm_dir)
110
111    if (args.format == "html"):
112        genHtml(args.llvm_dir, args.objects, args.output)
113
114    elif (args.format == "json"):
115        genJson(args.llvm_dir, args.objects, args.output)
116
117    else:
118        print("Only json and html supported")
119        return
120
121if __name__ == '__main__':
122    sys.exit(main())