Skip to content

Commit 5fbd1a3

Browse files
committed
[Coverage] Store compilation dir separately in coverage mapping
We currently always store absolute filenames in coverage mapping. This is problematic for several reasons. It poses a problem for distributed compilation as source location might vary across machines. We are also duplicating the path prefix potentially wasting space. This change modifies how we store filenames in coverage mapping. Rather than absolute paths, it stores the compilation directory and file paths as given to the compiler, either relative or absolute. Later when reading the coverage mapping information, we recombine relative paths with the working directory. This approach is similar to handling ofDW_AT_comp_dir in DWARF. Finally, we also provide a new option, -fprofile-compilation-dir akin to -fdebug-compilation-dir which can be used to manually override the compilation directory which is useful in distributed compilation cases. Differential Revision: https://reviews.llvm.org/D95753
1 parent 62d946e commit 5fbd1a3

File tree

19 files changed

+148
-94
lines changed

19 files changed

+148
-94
lines changed

clang/include/clang/Basic/CodeGenOptions.h

+3
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,9 @@ class CodeGenOptions : public CodeGenOptionsBase {
172172
/// The string to embed in debug information as the current working directory.
173173
std::string DebugCompilationDir;
174174

175+
/// The string to embed in coverage mapping as the current working directory.
176+
std::string ProfileCompilationDir;
177+
175178
/// The string to embed in the debug information for the compile unit, if
176179
/// non-empty.
177180
std::string DwarfDebugFlags;

clang/include/clang/Driver/Options.td

+4
Original file line numberDiff line numberDiff line change
@@ -1103,6 +1103,10 @@ def fdebug_compilation_dir_EQ : Joined<["-"], "fdebug-compilation-dir=">,
11031103
def fdebug_compilation_dir : Separate<["-"], "fdebug-compilation-dir">,
11041104
Group<f_Group>, Flags<[CC1Option, CC1AsOption, CoreOption]>,
11051105
Alias<fdebug_compilation_dir_EQ>;
1106+
def fprofile_compilation_dir_EQ : Joined<["-"], "fprofile-compilation-dir=">,
1107+
Group<f_Group>, Flags<[CC1Option, CC1AsOption, CoreOption]>,
1108+
HelpText<"The compilation directory to embed in the coverage mapping.">,
1109+
MarshallingInfoString<CodeGenOpts<"ProfileCompilationDir">>;
11061110
defm debug_info_for_profiling : BoolFOption<"debug-info-for-profiling",
11071111
CodeGenOpts<"DebugInfoForProfiling">, DefaultFalse,
11081112
PosFlag<SetTrue, [CC1Option], "Emit extra debug info to make sample profile more accurate">,

clang/lib/CodeGen/CoverageMappingGen.cpp

+18-12
Original file line numberDiff line numberDiff line change
@@ -1606,9 +1606,17 @@ CoverageMappingModuleGen::CoverageMappingModuleGen(
16061606
ProfilePrefixMap = CGM.getCodeGenOpts().ProfilePrefixMap;
16071607
}
16081608

1609+
std::string CoverageMappingModuleGen::getCurrentDirname() {
1610+
if (!CGM.getCodeGenOpts().ProfileCompilationDir.empty())
1611+
return CGM.getCodeGenOpts().ProfileCompilationDir;
1612+
1613+
SmallString<256> CWD;
1614+
llvm::sys::fs::current_path(CWD);
1615+
return CWD.str().str();
1616+
}
1617+
16091618
std::string CoverageMappingModuleGen::normalizeFilename(StringRef Filename) {
16101619
llvm::SmallString<256> Path(Filename);
1611-
llvm::sys::fs::make_absolute(Path);
16121620
llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true);
16131621
for (const auto &Entry : ProfilePrefixMap) {
16141622
if (llvm::sys::path::replace_path_prefix(Path, Entry.first, Entry.second))
@@ -1689,18 +1697,17 @@ void CoverageMappingModuleGen::addFunctionMappingRecord(
16891697
// also processed by the CoverageMappingWriter which performs
16901698
// additional minimization operations such as reducing the number of
16911699
// expressions.
1700+
llvm::SmallVector<std::string, 16> FilenameStrs;
16921701
std::vector<StringRef> Filenames;
16931702
std::vector<CounterExpression> Expressions;
16941703
std::vector<CounterMappingRegion> Regions;
1695-
llvm::SmallVector<std::string, 16> FilenameStrs;
1696-
llvm::SmallVector<StringRef, 16> FilenameRefs;
1697-
FilenameStrs.resize(FileEntries.size());
1698-
FilenameRefs.resize(FileEntries.size());
1704+
FilenameStrs.resize(FileEntries.size() + 1);
1705+
FilenameStrs[0] = normalizeFilename(getCurrentDirname());
16991706
for (const auto &Entry : FileEntries) {
17001707
auto I = Entry.second;
17011708
FilenameStrs[I] = normalizeFilename(Entry.first->getName());
1702-
FilenameRefs[I] = FilenameStrs[I];
17031709
}
1710+
ArrayRef<std::string> FilenameRefs = llvm::makeArrayRef(FilenameStrs);
17041711
RawCoverageMappingReader Reader(CoverageMapping, FilenameRefs, Filenames,
17051712
Expressions, Regions);
17061713
if (Reader.read())
@@ -1717,19 +1724,18 @@ void CoverageMappingModuleGen::emit() {
17171724

17181725
// Create the filenames and merge them with coverage mappings
17191726
llvm::SmallVector<std::string, 16> FilenameStrs;
1720-
llvm::SmallVector<StringRef, 16> FilenameRefs;
1721-
FilenameStrs.resize(FileEntries.size());
1722-
FilenameRefs.resize(FileEntries.size());
1727+
FilenameStrs.resize(FileEntries.size() + 1);
1728+
// The first filename is the current working directory.
1729+
FilenameStrs[0] = getCurrentDirname();
17231730
for (const auto &Entry : FileEntries) {
17241731
auto I = Entry.second;
17251732
FilenameStrs[I] = normalizeFilename(Entry.first->getName());
1726-
FilenameRefs[I] = FilenameStrs[I];
17271733
}
17281734

17291735
std::string Filenames;
17301736
{
17311737
llvm::raw_string_ostream OS(Filenames);
1732-
CoverageFilenamesSectionWriter(FilenameRefs).write(OS);
1738+
CoverageFilenamesSectionWriter(FilenameStrs).write(OS);
17331739
}
17341740
auto *FilenamesVal =
17351741
llvm::ConstantDataArray::getString(Ctx, Filenames, false);
@@ -1787,7 +1793,7 @@ unsigned CoverageMappingModuleGen::getFileID(const FileEntry *File) {
17871793
auto It = FileEntries.find(File);
17881794
if (It != FileEntries.end())
17891795
return It->second;
1790-
unsigned FileID = FileEntries.size();
1796+
unsigned FileID = FileEntries.size() + 1;
17911797
FileEntries.insert(std::make_pair(File, FileID));
17921798
return FileID;
17931799
}

clang/lib/CodeGen/CoverageMappingGen.h

+1
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ class CoverageMappingModuleGen {
9595
std::vector<FunctionInfo> FunctionRecords;
9696
std::map<std::string, std::string> ProfilePrefixMap;
9797

98+
std::string getCurrentDirname();
9899
std::string normalizeFilename(StringRef Filename);
99100

100101
/// Emit a function record.

clang/lib/Driver/ToolChains/Clang.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -858,6 +858,13 @@ static void addPGOAndCoverageFlags(const ToolChain &TC, Compilation &C,
858858
CmdArgs.push_back("-fcoverage-mapping");
859859
}
860860

861+
if (Arg *A = Args.getLastArg(options::OPT_fprofile_compilation_dir_EQ)) {
862+
A->render(Args, CmdArgs);
863+
} else if (llvm::ErrorOr<std::string> CWD =
864+
D.getVFS().getCurrentWorkingDirectory()) {
865+
Args.MakeArgString("-fprofile-compilation-dir=" + *CWD);
866+
}
867+
861868
if (Args.hasArg(options::OPT_fprofile_exclude_files_EQ)) {
862869
auto *Arg = Args.getLastArg(options::OPT_fprofile_exclude_files_EQ);
863870
if (!Args.hasArg(options::OPT_coverage))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// RUN: mkdir -p %t.dir && cd %t.dir
2+
// RUN: cp %s rel.c
3+
// RUN: %clang_cc1 -fprofile-instrument=clang -fprofile-compilation-dir=/nonsense -fcoverage-mapping -emit-llvm -mllvm -enable-name-compression=false rel.c -o - | FileCheck -check-prefix=CHECK-NONSENSE %s
4+
5+
// CHECK-NONSENSE: nonsense
6+
7+
void f() {}
+8-4
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
11
// RUN: %clang_cc1 -mllvm -emptyline-comment-coverage=false -fprofile-instrument=clang -fcoverage-mapping -mllvm -enable-name-compression=false -emit-llvm -main-file-name abspath.cpp %S/Inputs/../abspath.cpp -o - | FileCheck -check-prefix=RMDOTS %s
22

3-
// RMDOTS: @__llvm_coverage_mapping = {{.*}}"\01
3+
// RMDOTS: @__llvm_coverage_mapping = {{.*}}"\02
44
// RMDOTS-NOT: Inputs
55
// RMDOTS: "
66

77
// RUN: mkdir -p %t/test && cd %t/test
88
// RUN: echo "void f1() {}" > f1.c
9-
// RUN: %clang_cc1 -mllvm -emptyline-comment-coverage=false -fprofile-instrument=clang -fcoverage-mapping -mllvm -enable-name-compression=false -emit-llvm -main-file-name abspath.cpp ../test/f1.c -o - | FileCheck -check-prefix=RELPATH %s
9+
// RUN: %clang_cc1 -mllvm -emptyline-comment-coverage=false -fprofile-instrument=clang -fcoverage-mapping -mllvm -enable-name-compression=false -emit-llvm -main-file-name abspath.cpp %t/test/f1.c -o - | FileCheck -check-prefix=ABSPATH %s
1010

11-
// RELPATH: @__llvm_coverage_mapping = {{.*}}"\01
12-
// RELPATH: {{[/\\].*(/|\\\\)test(/|\\\\)f1}}.c
11+
// RELPATH: @__llvm_coverage_mapping = {{.*}}"\02
12+
// RELPATH: {{..(/|\\\\)test(/|\\\\)f1}}.c
1313
// RELPATH: "
1414

15+
// ABSPATH: @__llvm_coverage_mapping = {{.*}}"\02
16+
// ABSPATH: {{[/\\].*(/|\\\\)test(/|\\\\)f1}}.c
17+
// ABSPATH: "
18+
1519
void f1() {}

clang/test/Profile/profile-prefix-map.c

+8-4
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,14 @@
55
// RUN: echo "void f1() {}" > %t/root/nested/profile-prefix-map.c
66
// RUN: cd %t/root
77

8-
// RUN: %clang_cc1 -fprofile-instrument=clang -fcoverage-mapping -emit-llvm -mllvm -enable-name-compression=false -main-file-name profile-prefix-map.c nested/profile-prefix-map.c -o - | FileCheck --check-prefix=ABSOLUTE %s
8+
// RUN: %clang_cc1 -fprofile-instrument=clang -fcoverage-mapping -emit-llvm -mllvm -enable-name-compression=false -main-file-name profile-prefix-map.c %t/root/nested/profile-prefix-map.c -o - | FileCheck --check-prefix=ABSOLUTE %s
99
//
10-
// ABSOLUTE: @__llvm_coverage_mapping = {{.*"\\01.*root.*nested.*profile-prefix-map\.c}}
10+
// ABSOLUTE: @__llvm_coverage_mapping = {{.*"\\02.*root.*nested.*profile-prefix-map\.c}}
1111

12-
// RUN: %clang_cc1 -fprofile-instrument=clang -fcoverage-mapping -emit-llvm -mllvm -enable-name-compression=false -main-file-name profile-prefix-map.c nested/profile-prefix-map.c -fprofile-prefix-map=%/t/root=. -o - | FileCheck --check-prefix=PROFILE-PREFIX-MAP %s --implicit-check-not=root
12+
// RUN: %clang_cc1 -fprofile-instrument=clang -fcoverage-mapping -emit-llvm -mllvm -enable-name-compression=false -main-file-name profile-prefix-map.c ../root/nested/profile-prefix-map.c -o - | FileCheck --check-prefix=RELATIVE %s
1313
//
14-
// PROFILE-PREFIX-MAP: @__llvm_coverage_mapping = {{.*"\\01[^/]*}}.{{/|\\+}}nested{{.*profile-prefix-map\.c}}
14+
// RELATIVE: @__llvm_coverage_mapping = {{.*"\\02.*}}..{{/|\\+}}root{{/|\\+}}nested{{.*profile-prefix-map\.c}}
15+
16+
// RUN: %clang_cc1 -fprofile-instrument=clang -fcoverage-mapping -emit-llvm -mllvm -enable-name-compression=false -main-file-name profile-prefix-map.c %t/root/nested/profile-prefix-map.c -fprofile-prefix-map=%/t/root=. -o - | FileCheck --check-prefix=PROFILE-PREFIX-MAP %s
17+
// RUN: %clang_cc1 -fprofile-instrument=clang -fcoverage-mapping -emit-llvm -mllvm -enable-name-compression=false -main-file-name profile-prefix-map.c ../root/nested/profile-prefix-map.c -fprofile-prefix-map=../root=. -o - | FileCheck --check-prefix=PROFILE-PREFIX-MAP %s
18+
// PROFILE-PREFIX-MAP: @__llvm_coverage_mapping = {{.*"\\02.*}}.{{/|\\+}}nested{{.*profile-prefix-map\.c}}

compiler-rt/include/profile/InstrProfData.inc

+1-1
Original file line numberDiff line numberDiff line change
@@ -649,7 +649,7 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
649649
/* Indexed profile format version (start from 1). */
650650
#define INSTR_PROF_INDEX_VERSION 7
651651
/* Coverage mapping format version (start from 0). */
652-
#define INSTR_PROF_COVMAP_VERSION 4
652+
#define INSTR_PROF_COVMAP_VERSION 5
653653

654654
/* Profile version is always of type uint64_t. Reserve the upper 8 bits in the
655655
* version for other variants of profile. We set the lowest bit of the upper 8

llvm/docs/CoverageMappingFormat.rst

+10-1
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,16 @@ too deeply).
266266
[32 x i8] c"..." ; Encoded data (dissected later)
267267
}, section "__llvm_covmap", align 8
268268
269-
The current version of the format is version 5. There is one difference from version 4:
269+
The current version of the format is version 6.
270+
271+
There is one difference between versions 6 and 5:
272+
273+
* The first entry in the filename list is the compilation directory. When the
274+
filename is relative, the compilation directory is combined with the relative
275+
path to get an absolute path. This can reduce size by omitting the duplicate
276+
prefix in filenames.
277+
278+
There is one difference between versions 5 and 4:
270279

271280
* The notion of branch region has been introduced along with a corresponding
272281
region kind. Branch regions encode two counters, one to track how many

llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h

+4-1
Original file line numberDiff line numberDiff line change
@@ -996,7 +996,10 @@ enum CovMapVersion {
996996
Version4 = 3,
997997
// Branch regions referring to two counters are added
998998
Version5 = 4,
999-
// The current version is Version5.
999+
// Compilation directory is stored separately and combined with relative
1000+
// filenames to produce an absolute file path.
1001+
Version6 = 5,
1002+
// The current version is Version6.
10001003
CurrentVersion = INSTR_PROF_COVMAP_VERSION
10011004
};
10021005

llvm/include/llvm/ProfileData/Coverage/CoverageMappingReader.h

+8-14
Original file line numberDiff line numberDiff line change
@@ -125,14 +125,14 @@ class RawCoverageMappingDummyChecker : public RawCoverageReader {
125125

126126
/// Reader for the raw coverage mapping data.
127127
class RawCoverageMappingReader : public RawCoverageReader {
128-
ArrayRef<StringRef> TranslationUnitFilenames;
128+
ArrayRef<std::string> &TranslationUnitFilenames;
129129
std::vector<StringRef> &Filenames;
130130
std::vector<CounterExpression> &Expressions;
131131
std::vector<CounterMappingRegion> &MappingRegions;
132132

133133
public:
134134
RawCoverageMappingReader(StringRef MappingData,
135-
ArrayRef<StringRef> TranslationUnitFilenames,
135+
ArrayRef<std::string> &TranslationUnitFilenames,
136136
std::vector<StringRef> &Filenames,
137137
std::vector<CounterExpression> &Expressions,
138138
std::vector<CounterMappingRegion> &MappingRegions)
@@ -174,10 +174,8 @@ class BinaryCoverageReader : public CoverageMappingReader {
174174
FilenamesBegin(FilenamesBegin), FilenamesSize(FilenamesSize) {}
175175
};
176176

177-
using DecompressedData = std::vector<std::unique_ptr<SmallVector<char, 0>>>;
178-
179177
private:
180-
std::vector<StringRef> Filenames;
178+
std::vector<std::string> Filenames;
181179
std::vector<ProfileMappingRecord> MappingRecords;
182180
InstrProfSymtab ProfileNames;
183181
size_t CurrentRecord = 0;
@@ -190,10 +188,6 @@ class BinaryCoverageReader : public CoverageMappingReader {
190188
// D69471, which can split up function records into multiple sections on ELF.
191189
std::string FuncRecords;
192190

193-
// Used to tie the lifetimes of decompressed strings to the lifetime of this
194-
// BinaryCoverageReader instance.
195-
DecompressedData Decompressed;
196-
197191
BinaryCoverageReader(std::string &&FuncRecords)
198192
: FuncRecords(std::move(FuncRecords)) {}
199193

@@ -216,20 +210,20 @@ class BinaryCoverageReader : public CoverageMappingReader {
216210

217211
/// Reader for the raw coverage filenames.
218212
class RawCoverageFilenamesReader : public RawCoverageReader {
219-
std::vector<StringRef> &Filenames;
213+
std::vector<std::string> &Filenames;
220214

221215
// Read an uncompressed sequence of filenames.
222-
Error readUncompressed(uint64_t NumFilenames);
216+
Error readUncompressed(CovMapVersion Version, uint64_t NumFilenames);
223217

224218
public:
225-
RawCoverageFilenamesReader(StringRef Data, std::vector<StringRef> &Filenames)
219+
RawCoverageFilenamesReader(StringRef Data,
220+
std::vector<std::string> &Filenames)
226221
: RawCoverageReader(Data), Filenames(Filenames) {}
227222
RawCoverageFilenamesReader(const RawCoverageFilenamesReader &) = delete;
228223
RawCoverageFilenamesReader &
229224
operator=(const RawCoverageFilenamesReader &) = delete;
230225

231-
Error read(CovMapVersion Version,
232-
BinaryCoverageReader::DecompressedData &Decompressed);
226+
Error read(CovMapVersion Version);
233227
};
234228

235229
} // end namespace coverage

llvm/include/llvm/ProfileData/Coverage/CoverageMappingWriter.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@ namespace coverage {
2727
/// Writer of the filenames section for the instrumentation
2828
/// based code coverage.
2929
class CoverageFilenamesSectionWriter {
30-
ArrayRef<StringRef> Filenames;
30+
ArrayRef<std::string> Filenames;
3131

3232
public:
33-
CoverageFilenamesSectionWriter(ArrayRef<StringRef> Filenames);
33+
CoverageFilenamesSectionWriter(ArrayRef<std::string> Filenames);
3434

3535
/// Write encoded filenames to the given output stream. If \p Compress is
3636
/// true, attempt to compress the filenames.

llvm/include/llvm/ProfileData/InstrProfData.inc

+1-1
Original file line numberDiff line numberDiff line change
@@ -649,7 +649,7 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
649649
/* Indexed profile format version (start from 1). */
650650
#define INSTR_PROF_INDEX_VERSION 7
651651
/* Coverage mapping format version (start from 0). */
652-
#define INSTR_PROF_COVMAP_VERSION 4
652+
#define INSTR_PROF_COVMAP_VERSION 5
653653

654654
/* Profile version is always of type uint64_t. Reserve the upper 8 bits in the
655655
* version for other variants of profile. We set the lowest bit of the upper 8

0 commit comments

Comments
 (0)