Skip to content

Commit c6fabea

Browse files
committedNov 12, 2018
[GCOV] Add options to filter files which must be instrumented.
Summary: When making code coverage, a lot of files (like the ones coming from /usr/include) are removed when post-processing gcno/gcda so finally they doen't need to be instrumented nor to appear in gcno/gcda. The goal of the patch is to be able to filter the files we want to instrument, there are several advantages to do that: - improve speed (no overhead due to instrumentation on files we don't care) - reduce gcno/gcda size - it gives the possibility to easily instrument only few files (e.g. ones modified in a patch) without changing the build system - need to accept this patch to be enabled in clang: https://reviews.llvm.org/D52034 Reviewers: marco-c, vsk Reviewed By: marco-c Subscribers: llvm-commits, sylvestre.ledru Differential Revision: https://reviews.llvm.org/D52033 llvm-svn: 346641
1 parent a97c4e3 commit c6fabea

File tree

2 files changed

+88
-2
lines changed

2 files changed

+88
-2
lines changed
 

‎llvm/include/llvm/Transforms/Instrumentation.h

+6
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,12 @@ struct GCOVOptions {
7777
// Emit the exit block immediately after the start block, rather than after
7878
// all of the function body's blocks.
7979
bool ExitBlockBeforeBody;
80+
81+
// Regexes separated by a semi-colon to filter the files to instrument.
82+
std::string Filter;
83+
84+
// Regexes separated by a semi-colon to filter the files to not instrument.
85+
std::string Exclude;
8086
};
8187

8288
ModulePass *createGCOVProfilerPass(const GCOVOptions &Options =

‎llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp

+82-2
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include "llvm/Support/Debug.h"
3737
#include "llvm/Support/FileSystem.h"
3838
#include "llvm/Support/Path.h"
39+
#include "llvm/Support/Regex.h"
3940
#include "llvm/Support/raw_ostream.h"
4041
#include "llvm/Transforms/Instrumentation.h"
4142
#include "llvm/Transforms/Instrumentation/GCOVProfiler.h"
@@ -96,6 +97,11 @@ class GCOVProfiler {
9697
// profiling runtime to emit .gcda files when run.
9798
bool emitProfileArcs();
9899

100+
bool isFunctionInstrumented(const Function &F);
101+
std::vector<Regex> createRegexesFromString(StringRef RegexesStr);
102+
static bool doesFilenameMatchARegex(StringRef Filename,
103+
std::vector<Regex> &Regexes);
104+
99105
// Get pointers to the functions in the runtime library.
100106
Constant *getStartFileFunc();
101107
Constant *getEmitFunctionFunc();
@@ -125,6 +131,9 @@ class GCOVProfiler {
125131
const TargetLibraryInfo *TLI;
126132
LLVMContext *Ctx;
127133
SmallVector<std::unique_ptr<GCOVFunction>, 16> Funcs;
134+
std::vector<Regex> FilterRe;
135+
std::vector<Regex> ExcludeRe;
136+
StringMap<bool> InstrumentedFiles;
128137
};
129138

130139
class GCOVProfilerLegacyPass : public ModulePass {
@@ -423,6 +432,72 @@ namespace {
423432
};
424433
}
425434

435+
// RegexesStr is a string containing differents regex separated by a semi-colon.
436+
// For example "foo\..*$;bar\..*$".
437+
std::vector<Regex> GCOVProfiler::createRegexesFromString(StringRef RegexesStr) {
438+
std::vector<Regex> Regexes;
439+
while (!RegexesStr.empty()) {
440+
std::pair<StringRef, StringRef> HeadTail = RegexesStr.split(';');
441+
if (!HeadTail.first.empty()) {
442+
Regex Re(HeadTail.first);
443+
std::string Err;
444+
if (!Re.isValid(Err)) {
445+
Ctx->emitError(Twine("Regex ") + HeadTail.first +
446+
" is not valid: " + Err);
447+
}
448+
Regexes.emplace_back(std::move(Re));
449+
}
450+
RegexesStr = HeadTail.second;
451+
}
452+
return Regexes;
453+
}
454+
455+
bool GCOVProfiler::doesFilenameMatchARegex(StringRef Filename,
456+
std::vector<Regex> &Regexes) {
457+
for (Regex &Re : Regexes) {
458+
if (Re.match(Filename)) {
459+
return true;
460+
}
461+
}
462+
return false;
463+
}
464+
465+
bool GCOVProfiler::isFunctionInstrumented(const Function &F) {
466+
if (FilterRe.empty() && ExcludeRe.empty()) {
467+
return true;
468+
}
469+
const StringRef Filename = F.getSubprogram()->getFilename();
470+
auto It = InstrumentedFiles.find(Filename);
471+
if (It != InstrumentedFiles.end()) {
472+
return It->second;
473+
}
474+
475+
SmallString<256> RealPath;
476+
StringRef RealFilename;
477+
478+
// Path can be
479+
// /usr/lib/gcc/x86_64-linux-gnu/8/../../../../include/c++/8/bits/*.h so for
480+
// such a case we must get the real_path.
481+
if (sys::fs::real_path(Filename, RealPath)) {
482+
// real_path can fail with path like "foo.c".
483+
RealFilename = Filename;
484+
} else {
485+
RealFilename = RealPath;
486+
}
487+
488+
bool ShouldInstrument;
489+
if (FilterRe.empty()) {
490+
ShouldInstrument = !doesFilenameMatchARegex(RealFilename, ExcludeRe);
491+
} else if (ExcludeRe.empty()) {
492+
ShouldInstrument = doesFilenameMatchARegex(RealFilename, FilterRe);
493+
} else {
494+
ShouldInstrument = doesFilenameMatchARegex(RealFilename, FilterRe) &&
495+
!doesFilenameMatchARegex(RealFilename, ExcludeRe);
496+
}
497+
InstrumentedFiles[Filename] = ShouldInstrument;
498+
return ShouldInstrument;
499+
}
500+
426501
std::string GCOVProfiler::mangleName(const DICompileUnit *CU,
427502
GCovFileType OutputType) {
428503
bool Notes = OutputType == GCovFileType::GCNO;
@@ -472,6 +547,9 @@ bool GCOVProfiler::runOnModule(Module &M, const TargetLibraryInfo &TLI) {
472547

473548
AddFlushBeforeForkAndExec();
474549

550+
FilterRe = createRegexesFromString(Options.Filter);
551+
ExcludeRe = createRegexesFromString(Options.Exclude);
552+
475553
if (Options.EmitNotes) emitProfileNotes();
476554
if (Options.EmitData) return emitProfileArcs();
477555
return false;
@@ -589,7 +667,8 @@ void GCOVProfiler::emitProfileNotes() {
589667
for (auto &F : M->functions()) {
590668
DISubprogram *SP = F.getSubprogram();
591669
if (!SP) continue;
592-
if (!functionHasLines(F)) continue;
670+
if (!functionHasLines(F) || !isFunctionInstrumented(F))
671+
continue;
593672
// TODO: Functions using scope-based EH are currently not supported.
594673
if (isUsingScopeBasedEH(F)) continue;
595674

@@ -673,7 +752,8 @@ bool GCOVProfiler::emitProfileArcs() {
673752
for (auto &F : M->functions()) {
674753
DISubprogram *SP = F.getSubprogram();
675754
if (!SP) continue;
676-
if (!functionHasLines(F)) continue;
755+
if (!functionHasLines(F) || !isFunctionInstrumented(F))
756+
continue;
677757
// TODO: Functions using scope-based EH are currently not supported.
678758
if (isUsingScopeBasedEH(F)) continue;
679759
if (!Result) Result = true;

0 commit comments

Comments
 (0)
Please sign in to comment.