[llvm] r346641 - [GCOV] Add options to filter files which must be instrumented.
Calixte Denizet via llvm-commits
llvm-commits at lists.llvm.org
Mon Nov 12 01:01:43 PST 2018
Author: calixte
Date: Mon Nov 12 01:01:43 2018
New Revision: 346641
URL: http://llvm.org/viewvc/llvm-project?rev=346641&view=rev
Log:
[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
Modified:
llvm/trunk/include/llvm/Transforms/Instrumentation.h
llvm/trunk/lib/Transforms/Instrumentation/GCOVProfiling.cpp
Modified: llvm/trunk/include/llvm/Transforms/Instrumentation.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Transforms/Instrumentation.h?rev=346641&r1=346640&r2=346641&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Transforms/Instrumentation.h (original)
+++ llvm/trunk/include/llvm/Transforms/Instrumentation.h Mon Nov 12 01:01:43 2018
@@ -77,6 +77,12 @@ struct GCOVOptions {
// Emit the exit block immediately after the start block, rather than after
// all of the function body's blocks.
bool ExitBlockBeforeBody;
+
+ // Regexes separated by a semi-colon to filter the files to instrument.
+ std::string Filter;
+
+ // Regexes separated by a semi-colon to filter the files to not instrument.
+ std::string Exclude;
};
ModulePass *createGCOVProfilerPass(const GCOVOptions &Options =
Modified: llvm/trunk/lib/Transforms/Instrumentation/GCOVProfiling.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Instrumentation/GCOVProfiling.cpp?rev=346641&r1=346640&r2=346641&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/Instrumentation/GCOVProfiling.cpp (original)
+++ llvm/trunk/lib/Transforms/Instrumentation/GCOVProfiling.cpp Mon Nov 12 01:01:43 2018
@@ -36,6 +36,7 @@
#include "llvm/Support/Debug.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
+#include "llvm/Support/Regex.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Instrumentation.h"
#include "llvm/Transforms/Instrumentation/GCOVProfiler.h"
@@ -96,6 +97,11 @@ private:
// profiling runtime to emit .gcda files when run.
bool emitProfileArcs();
+ bool isFunctionInstrumented(const Function &F);
+ std::vector<Regex> createRegexesFromString(StringRef RegexesStr);
+ static bool doesFilenameMatchARegex(StringRef Filename,
+ std::vector<Regex> &Regexes);
+
// Get pointers to the functions in the runtime library.
Constant *getStartFileFunc();
Constant *getEmitFunctionFunc();
@@ -125,6 +131,9 @@ private:
const TargetLibraryInfo *TLI;
LLVMContext *Ctx;
SmallVector<std::unique_ptr<GCOVFunction>, 16> Funcs;
+ std::vector<Regex> FilterRe;
+ std::vector<Regex> ExcludeRe;
+ StringMap<bool> InstrumentedFiles;
};
class GCOVProfilerLegacyPass : public ModulePass {
@@ -423,6 +432,72 @@ namespace {
};
}
+// RegexesStr is a string containing differents regex separated by a semi-colon.
+// For example "foo\..*$;bar\..*$".
+std::vector<Regex> GCOVProfiler::createRegexesFromString(StringRef RegexesStr) {
+ std::vector<Regex> Regexes;
+ while (!RegexesStr.empty()) {
+ std::pair<StringRef, StringRef> HeadTail = RegexesStr.split(';');
+ if (!HeadTail.first.empty()) {
+ Regex Re(HeadTail.first);
+ std::string Err;
+ if (!Re.isValid(Err)) {
+ Ctx->emitError(Twine("Regex ") + HeadTail.first +
+ " is not valid: " + Err);
+ }
+ Regexes.emplace_back(std::move(Re));
+ }
+ RegexesStr = HeadTail.second;
+ }
+ return Regexes;
+}
+
+bool GCOVProfiler::doesFilenameMatchARegex(StringRef Filename,
+ std::vector<Regex> &Regexes) {
+ for (Regex &Re : Regexes) {
+ if (Re.match(Filename)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool GCOVProfiler::isFunctionInstrumented(const Function &F) {
+ if (FilterRe.empty() && ExcludeRe.empty()) {
+ return true;
+ }
+ const StringRef Filename = F.getSubprogram()->getFilename();
+ auto It = InstrumentedFiles.find(Filename);
+ if (It != InstrumentedFiles.end()) {
+ return It->second;
+ }
+
+ SmallString<256> RealPath;
+ StringRef RealFilename;
+
+ // Path can be
+ // /usr/lib/gcc/x86_64-linux-gnu/8/../../../../include/c++/8/bits/*.h so for
+ // such a case we must get the real_path.
+ if (sys::fs::real_path(Filename, RealPath)) {
+ // real_path can fail with path like "foo.c".
+ RealFilename = Filename;
+ } else {
+ RealFilename = RealPath;
+ }
+
+ bool ShouldInstrument;
+ if (FilterRe.empty()) {
+ ShouldInstrument = !doesFilenameMatchARegex(RealFilename, ExcludeRe);
+ } else if (ExcludeRe.empty()) {
+ ShouldInstrument = doesFilenameMatchARegex(RealFilename, FilterRe);
+ } else {
+ ShouldInstrument = doesFilenameMatchARegex(RealFilename, FilterRe) &&
+ !doesFilenameMatchARegex(RealFilename, ExcludeRe);
+ }
+ InstrumentedFiles[Filename] = ShouldInstrument;
+ return ShouldInstrument;
+}
+
std::string GCOVProfiler::mangleName(const DICompileUnit *CU,
GCovFileType OutputType) {
bool Notes = OutputType == GCovFileType::GCNO;
@@ -472,6 +547,9 @@ bool GCOVProfiler::runOnModule(Module &M
AddFlushBeforeForkAndExec();
+ FilterRe = createRegexesFromString(Options.Filter);
+ ExcludeRe = createRegexesFromString(Options.Exclude);
+
if (Options.EmitNotes) emitProfileNotes();
if (Options.EmitData) return emitProfileArcs();
return false;
@@ -589,7 +667,8 @@ void GCOVProfiler::emitProfileNotes() {
for (auto &F : M->functions()) {
DISubprogram *SP = F.getSubprogram();
if (!SP) continue;
- if (!functionHasLines(F)) continue;
+ if (!functionHasLines(F) || !isFunctionInstrumented(F))
+ continue;
// TODO: Functions using scope-based EH are currently not supported.
if (isUsingScopeBasedEH(F)) continue;
@@ -673,7 +752,8 @@ bool GCOVProfiler::emitProfileArcs() {
for (auto &F : M->functions()) {
DISubprogram *SP = F.getSubprogram();
if (!SP) continue;
- if (!functionHasLines(F)) continue;
+ if (!functionHasLines(F) || !isFunctionInstrumented(F))
+ continue;
// TODO: Functions using scope-based EH are currently not supported.
if (isUsingScopeBasedEH(F)) continue;
if (!Result) Result = true;
More information about the llvm-commits
mailing list