197 lines · python
1#!/usr/bin/env python32 3"""Prepare a code coverage artifact.4 5- Collate raw profiles into one indexed profile.6- Generate html reports for the given binaries.7 8Caution: The positional arguments to this script must be specified before any 9optional arguments, such as --restrict.10"""11 12import argparse13import glob14import os15import subprocess16import sys17 18 19def merge_raw_profiles(host_llvm_profdata, profile_data_dir, preserve_profiles):20 print(":: Merging raw profiles...", end="")21 sys.stdout.flush()22 raw_profiles = glob.glob(os.path.join(profile_data_dir, "*.profraw"))23 manifest_path = os.path.join(profile_data_dir, "profiles.manifest")24 profdata_path = os.path.join(profile_data_dir, "Coverage.profdata")25 with open(manifest_path, "w") as manifest:26 manifest.write("\n".join(raw_profiles))27 subprocess.check_call(28 [29 host_llvm_profdata,30 "merge",31 "-sparse",32 "-f",33 manifest_path,34 "-o",35 profdata_path,36 ]37 )38 if not preserve_profiles:39 for raw_profile in raw_profiles:40 os.remove(raw_profile)41 os.remove(manifest_path)42 print("Done!")43 return profdata_path44 45 46def prepare_html_report(47 host_llvm_cov, profile, report_dir, binaries, restricted_dirs, compilation_dir48):49 print(":: Preparing html report for {0}...".format(binaries), end="")50 sys.stdout.flush()51 objects = []52 for i, binary in enumerate(binaries):53 if i == 0:54 objects.append(binary)55 else:56 objects.extend(("-object", binary))57 invocation = (58 [host_llvm_cov, "show"]59 + objects60 + [61 "-format",62 "html",63 "-instr-profile",64 profile,65 "-o",66 report_dir,67 "-show-line-counts-or-regions",68 "-show-directory-coverage",69 "-Xdemangler",70 "c++filt",71 "-Xdemangler",72 "-n",73 ]74 + restricted_dirs75 )76 if compilation_dir:77 invocation += ["-compilation-dir=" + compilation_dir]78 subprocess.check_call(invocation)79 with open(os.path.join(report_dir, "summary.txt"), "wb") as Summary:80 subprocess.check_call(81 [host_llvm_cov, "report"]82 + objects83 + ["-instr-profile", profile]84 + restricted_dirs,85 stdout=Summary,86 )87 print("Done!")88 89 90def prepare_html_reports(91 host_llvm_cov,92 profdata_path,93 report_dir,94 binaries,95 unified_report,96 restricted_dirs,97 compilation_dir,98):99 if unified_report:100 prepare_html_report(101 host_llvm_cov,102 profdata_path,103 report_dir,104 binaries,105 restricted_dirs,106 compilation_dir,107 )108 else:109 for binary in binaries:110 binary_report_dir = os.path.join(report_dir, os.path.basename(binary))111 prepare_html_report(112 host_llvm_cov,113 profdata_path,114 binary_report_dir,115 [binary],116 restricted_dirs,117 compilation_dir,118 )119 120 121if __name__ == "__main__":122 parser = argparse.ArgumentParser(description=__doc__)123 parser.add_argument("host_llvm_profdata", help="Path to llvm-profdata")124 parser.add_argument("host_llvm_cov", help="Path to llvm-cov")125 parser.add_argument(126 "profile_data_dir", help="Path to the directory containing the raw profiles"127 )128 parser.add_argument(129 "report_dir", help="Path to the output directory for html reports"130 )131 parser.add_argument(132 "binaries",133 metavar="B",134 type=str,135 nargs="*",136 help="Path to an instrumented binary",137 )138 parser.add_argument(139 "--only-merge",140 action="store_true",141 help="Only merge raw profiles together, skip report " "generation",142 )143 parser.add_argument(144 "--preserve-profiles", help="Do not delete raw profiles", action="store_true"145 )146 parser.add_argument(147 "--use-existing-profdata", help="Specify an existing indexed profile to use"148 )149 parser.add_argument(150 "--unified-report",151 action="store_true",152 help="Emit a unified report for all binaries",153 )154 parser.add_argument(155 "--restrict",156 metavar="R",157 type=str,158 nargs="*",159 default=[],160 help="Restrict the reporting to the given source paths"161 " (must be specified after all other positional arguments)",162 )163 parser.add_argument(164 "-C",165 "--compilation-dir",166 type=str,167 default="",168 help="The compilation directory of the binary",169 )170 args = parser.parse_args()171 172 if args.use_existing_profdata and args.only_merge:173 print("--use-existing-profdata and --only-merge are incompatible")174 exit(1)175 176 if args.use_existing_profdata:177 profdata_path = args.use_existing_profdata178 else:179 profdata_path = merge_raw_profiles(180 args.host_llvm_profdata, args.profile_data_dir, args.preserve_profiles181 )182 183 if not len(args.binaries):184 print("No binaries specified, no work to do!")185 exit(1)186 187 if not args.only_merge:188 prepare_html_reports(189 args.host_llvm_cov,190 profdata_path,191 args.report_dir,192 args.binaries,193 args.unified_report,194 args.restrict,195 args.compilation_dir,196 )197