]> granicus.if.org Git - clang/commitdiff
[Clang] Add options -fprofile-filter-files and -fprofile-exclude-files to filter...
authorCalixte Denizet <cdenizet@mozilla.com>
Mon, 12 Nov 2018 09:12:27 +0000 (09:12 +0000)
committerCalixte Denizet <cdenizet@mozilla.com>
Mon, 12 Nov 2018 09:12:27 +0000 (09:12 +0000)
Summary:
These options are taking regex separated by colons to filter files.
- if both are empty then all files are instrumented
- if -fprofile-filter-files is empty then all the filenames matching any of the regex from exclude are not instrumented
- if -fprofile-exclude-files is empty then all the filenames matching any of the regex from filter are instrumented
- if both aren't empty then all the filenames which match any of the regex in filter and which don't match all the regex in filter are instrumented
- this patch is a follow-up of https://reviews.llvm.org/D52033

Reviewers: marco-c, vsk

Reviewed By: marco-c, vsk

Subscribers: cfe-commits, sylvestre.ledru

Differential Revision: https://reviews.llvm.org/D52034

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@346642 91177308-0d34-0410-b5e6-96231b3b80d8

docs/ReleaseNotes.rst
docs/UsersManual.rst
include/clang/Driver/Options.td
include/clang/Frontend/CodeGenOptions.h
lib/CodeGen/BackendUtil.cpp
lib/Driver/ToolChains/Clang.cpp
lib/Frontend/CompilerInvocation.cpp
test/CodeGen/Inputs/code-coverage-filter1.h [new file with mode: 0644]
test/CodeGen/Inputs/code-coverage-filter2.h [new file with mode: 0644]
test/CodeGen/code-coverage-filter.c [new file with mode: 0644]

index 09f656815d430bd91e4d3a8db6194957b0edbf8e..72b043f28d03cea42e3634341d8ca09b23678f03 100644 (file)
@@ -64,6 +64,12 @@ Non-comprehensive list of changes in this release
 New Compiler Flags
 ------------------
 
+- ``-fprofile-filter-files=[regexes]`` and ``-fprofile-exclude-files=[regexes]``.
+
+  Clang has now options to filter or exclude some files when
+  instrumenting for gcov-based profiling.
+  See the :doc:`UsersManual` for details.
+
 - ...
 
 Deprecated Compiler Flags
index a7f2f8145e87fa8ef945131b8c38c2acc240def3..5c28517bebb0c05363b5f48c5230c9c59c76c361 100644 (file)
@@ -1871,6 +1871,55 @@ using the ``llvm-cxxmap`` and ``llvm-profdata merge`` tools.
   following the Itanium C++ ABI mangling scheme. This covers all C++ targets
   supported by Clang other than Windows.
 
+GCOV-based Profiling
+--------------------
+
+GCOV is a test coverage program, it helps to know how often a line of code
+is executed. When instrumenting the code with ``--coverage`` option, some
+counters are added for each edge linking basic blocks.
+
+At compile time, gcno files are generated containing information about
+blocks and edges between them. At runtime the counters are incremented and at
+exit the counters are dumped in gcda files.
+
+The tool ``llvm-cov gcov`` will parse gcno, gcda and source files to generate
+a report ``.c.gcov``.
+
+.. option:: -fprofile-filter-files=[regexes]
+
+  Define a list of regexes separated by a semi-colon.
+  If a file name matches any of the regexes then the file is instrumented.
+
+   .. code-block:: console
+
+     $ clang --coverage -fprofile-filter-files=".*\.c$" foo.c
+
+  For example, this will only instrument files finishing with ``.c``, skipping ``.h`` files.
+
+.. option:: -fprofile-exclude-files=[regexes]
+
+  Define a list of regexes separated by a semi-colon.
+  If a file name doesn't match all the regexes then the file is instrumented.
+
+  .. code-block:: console
+
+     $ clang --coverage -fprofile-exclude-files="^/usr/include/.*$" foo.c
+
+  For example, this will instrument all the files except the ones in ``/usr/include``.
+
+If both options are used then a file is instrumented if its name matches any
+of the regexes from ``-fprofile-filter-list`` and doesn't match all the regexes
+from ``-fprofile-exclude-list``.
+
+.. code-block:: console
+
+   $ clang --coverage -fprofile-exclude-files="^/usr/include/.*$" \
+           -fprofile-filter-files="^/usr/.*$"
+          
+In that case ``/usr/foo/oof.h`` is instrumented since it matches the filter regex and
+doesn't match the exclude regex, but ``/usr/include/foo.h`` doesn't since it matches
+the exclude regex.
+
 Controlling Debug Information
 -----------------------------
 
index cc9f21e2ad840683239fc29a0d6142adbb889b34..cb070f06b2a0f82bbea88a66cb214d839fa6a314 100644 (file)
@@ -768,6 +768,12 @@ def fno_profile_instr_use : Flag<["-"], "fno-profile-instr-use">,
     HelpText<"Disable using instrumentation data for profile-guided optimization">;
 def fno_profile_use : Flag<["-"], "fno-profile-use">,
     Alias<fno_profile_instr_use>;
+def fprofile_filter_files_EQ : Joined<["-"], "fprofile-filter-files=">,
+    Group<f_Group>, Flags<[CC1Option, CoreOption]>,
+    HelpText<"Instrument only functions from files where names match any regex separated by a semi-colon">;
+def fprofile_exclude_files_EQ : Joined<["-"], "fprofile-exclude-files=">,
+    Group<f_Group>, Flags<[CC1Option, CoreOption]>,
+    HelpText<"Instrument only functions from files where names don't match all the regexes separated by a semi-colon">;
 
 def faddrsig : Flag<["-"], "faddrsig">, Group<f_Group>, Flags<[CoreOption, CC1Option]>,
   HelpText<"Emit an address-significance table">;
index 6cedfdbb17df76d2b62f5eb6c26f46df105aa106..15a6b7ad9760a3b2806f6e458d5085a29f68a1a2 100644 (file)
@@ -127,6 +127,12 @@ public:
   /// The filename with path we use for coverage notes files.
   std::string CoverageNotesFile;
 
+  /// Regexes separated by a semi-colon to filter the files to instrument.
+  std::string ProfileFilterFiles;
+
+  /// Regexes separated by a semi-colon to filter the files to not instrument.
+  std::string ProfileExcludeFiles;
+
   /// The version string to put into coverage files.
   char CoverageVersion[4];
 
index fd9a95b71998b0758ffa468be5265af388b3c202..484a070e5eb9399043825ed8992d6d1e603acbb0 100644 (file)
@@ -503,6 +503,8 @@ static Optional<GCOVOptions> getGCOVOptions(const CodeGenOptions &CodeGenOpts) {
   Options.UseCfgChecksum = CodeGenOpts.CoverageExtraChecksum;
   Options.NoRedZone = CodeGenOpts.DisableRedZone;
   Options.FunctionNamesInData = !CodeGenOpts.CoverageNoFunctionNamesInData;
+  Options.Filter = CodeGenOpts.ProfileFilterFiles;
+  Options.Exclude = CodeGenOpts.ProfileExcludeFiles;
   Options.ExitBlockBeforeBody = CodeGenOpts.CoverageExitBlockBeforeBody;
   return Options;
 }
index c35f7a94053cfaae7eeeade07d6dd9a0ad0eb36e..13036c18652d928576b23b3d762f9d5c316bc38d 100644 (file)
@@ -802,6 +802,29 @@ static void addPGOAndCoverageFlags(Compilation &C, const Driver &D,
     CmdArgs.push_back("-fcoverage-mapping");
   }
 
+  if (Args.hasArg(options::OPT_fprofile_exclude_files_EQ)) {
+    auto *Arg = Args.getLastArg(options::OPT_fprofile_exclude_files_EQ);
+    if (!Args.hasArg(options::OPT_coverage))
+      D.Diag(clang::diag::err_drv_argument_only_allowed_with)
+          << "-fprofile-exclude-files="
+          << "--coverage";
+
+    StringRef v = Arg->getValue();
+    CmdArgs.push_back(
+        Args.MakeArgString(Twine("-fprofile-exclude-files=" + v)));
+  }
+
+  if (Args.hasArg(options::OPT_fprofile_filter_files_EQ)) {
+    auto *Arg = Args.getLastArg(options::OPT_fprofile_exclude_files_EQ);
+    if (!Args.hasArg(options::OPT_coverage))
+      D.Diag(clang::diag::err_drv_argument_only_allowed_with)
+          << "-fprofile-filter-files="
+          << "--coverage";
+
+    StringRef v = Arg->getValue();
+    CmdArgs.push_back(Args.MakeArgString(Twine("-fprofile-filter-files=" + v)));
+  }
+
   if (C.getArgs().hasArg(options::OPT_c) ||
       C.getArgs().hasArg(options::OPT_S)) {
     if (Output.isFilename()) {
index 7be183f9701cb62274e06b77b9c09031a2076258..d43965ce5dfcde2279abce2037c91551c5d95a8d 100644 (file)
@@ -811,6 +811,10 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
     Opts.CoverageExtraChecksum = Args.hasArg(OPT_coverage_cfg_checksum);
     Opts.CoverageNoFunctionNamesInData =
         Args.hasArg(OPT_coverage_no_function_names_in_data);
+    Opts.ProfileFilterFiles =
+        Args.getLastArgValue(OPT_fprofile_filter_files_EQ);
+    Opts.ProfileExcludeFiles =
+        Args.getLastArgValue(OPT_fprofile_exclude_files_EQ);
     Opts.CoverageExitBlockBeforeBody =
         Args.hasArg(OPT_coverage_exit_block_before_body);
     if (Args.hasArg(OPT_coverage_version_EQ)) {
diff --git a/test/CodeGen/Inputs/code-coverage-filter1.h b/test/CodeGen/Inputs/code-coverage-filter1.h
new file mode 100644 (file)
index 0000000..4c0de6c
--- /dev/null
@@ -0,0 +1 @@
+void test1() {}
diff --git a/test/CodeGen/Inputs/code-coverage-filter2.h b/test/CodeGen/Inputs/code-coverage-filter2.h
new file mode 100644 (file)
index 0000000..91e68cc
--- /dev/null
@@ -0,0 +1 @@
+void test2() {}
diff --git a/test/CodeGen/code-coverage-filter.c b/test/CodeGen/code-coverage-filter.c
new file mode 100644 (file)
index 0000000..392d928
--- /dev/null
@@ -0,0 +1,84 @@
+// RUN: %clang_cc1 -emit-llvm -femit-coverage-data -femit-coverage-notes %s -o - \
+// RUN:    | FileCheck -check-prefix=ALL %s
+// RUN: %clang_cc1 -emit-llvm -femit-coverage-data -femit-coverage-notes -fprofile-exclude-files=".*\.h$" %s -o - \
+// RUN:    | FileCheck -check-prefix=NO-HEADER %s
+// RUN: %clang_cc1 -emit-llvm -femit-coverage-data -femit-coverage-notes -fprofile-filter-files=".*\.c$" %s -o - \
+// RUN:    | FileCheck -check-prefix=NO-HEADER %s
+// RUN: %clang_cc1 -emit-llvm -femit-coverage-data -femit-coverage-notes -fprofile-filter-files=".*\.c$;.*1\.h$" %s -o - \
+// RUN:    | FileCheck -check-prefix=NO-HEADER2 %s
+// RUN: %clang_cc1 -emit-llvm -femit-coverage-data -femit-coverage-notes -fprofile-exclude-files=".*2\.h$;.*1\.h$" %s -o - \
+// RUN:    | FileCheck -check-prefix=JUST-C %s
+// RUN: %clang_cc1 -emit-llvm -femit-coverage-data -femit-coverage-notes -fprofile-exclude-files=".*code\-coverage\-filter\.c$" %s -o - \
+// RUN:    | FileCheck -check-prefix=HEADER %s
+// RUN: %clang_cc1 -emit-llvm -femit-coverage-data -femit-coverage-notes -fprofile-filter-files=".*\.c$" -fprofile-exclude-files=".*\.c$" %s -o - \
+// RUN:    | FileCheck -check-prefix=NONE %s
+// RUN: %clang_cc1 -emit-llvm -femit-coverage-data -femit-coverage-notes -fprofile-filter-files=".*\.c$" -fprofile-exclude-files=".*\.h$" %s -o - \
+// RUN:    | FileCheck -check-prefix=JUST-C %s
+
+#include "Inputs/code-coverage-filter1.h"
+#include "Inputs/code-coverage-filter2.h"
+
+void test() {
+  test1();
+  test2();
+}
+
+// ALL: define void @test1() #0 {{.*}}
+// ALL: {{.*}}__llvm_gcov_ctr{{.*}}
+// ALL: ret void
+// ALL: define void @test2() #0 {{.*}}
+// ALL: {{.*}}__llvm_gcov_ctr{{.*}}
+// ALL: ret void
+// ALL: define void @test() #0 {{.*}}
+// ALL: {{.*}}__llvm_gcov_ctr{{.*}}
+// ALL: ret void
+
+// NO-HEADER: define void @test1() #0 {{.*}}
+// NO-HEADER-NOT: {{.*}}__llvm_gcov_ctr{{.*}}
+// NO-HEADER: ret void
+// NO-HEADER: define void @test2() #0 {{.*}}
+// NO-HEADER-NOT: {{.*}}__llvm_gcov_ctr{{.*}}
+// NO-HEADER: ret void
+// NO-HEADER: define void @test() #0 {{.*}}
+// NO-HEADER: {{.*}}__llvm_gcov_ctr{{.*}}
+// NO-HEADER: ret void
+
+// NO-HEADER2: define void @test1() #0 {{.*}}
+// NO-HEADER2: {{.*}}__llvm_gcov_ctr{{.*}}
+// NO-HEADER2: ret void
+// NO-HEADER2: define void @test2() #0 {{.*}}
+// NO-HEADER2-NOT: {{.*}}__llvm_gcov_ctr{{.*}}
+// NO-HEADER2: ret void
+// NO-HEADER2: define void @test() #0 {{.*}}
+// NO-HEADER2: {{.*}}__llvm_gcov_ctr{{.*}}
+// NO-HEADER2: ret void
+
+// JUST-C: define void @test1() #0 {{.*}}
+// JUST-C-NOT: {{.*}}__llvm_gcov_ctr{{.*}}
+// JUST-C: ret void
+// JUST-C: define void @test2() #0 {{.*}}
+// JUST-C-NOT: {{.*}}__llvm_gcov_ctr{{.*}}
+// JUST-C: ret void
+// JUST-C: define void @test() #0 {{.*}}
+// JUST-C: {{.*}}__llvm_gcov_ctr{{.*}}
+// JUST-C: ret void
+
+// HEADER: define void @test1() #0 {{.*}}
+// HEADER: {{.*}}__llvm_gcov_ctr{{.*}}
+// HEADER: ret void
+// HEADER: define void @test2() #0 {{.*}}
+// HEADER: {{.*}}__llvm_gcov_ctr{{.*}}
+// HEADER: ret void
+// HEADER: define void @test() #0 {{.*}}
+// HEADER-NOT: {{.*}}__llvm_gcov_ctr{{.*}}
+// HEADER: ret void
+
+// NONE: define void @test1() #0 {{.*}}
+// NONE-NOT: {{.*}}__llvm_gcov_ctr{{.*}}
+// NONE: ret void
+// NONE: define void @test2() #0 {{.*}}
+// NONE-NOT: {{.*}}__llvm_gcov_ctr{{.*}}
+// NONE: ret void
+// NONE: define void @test() #0 {{.*}}
+// NONE-NOT: {{.*}}__llvm_gcov_ctr{{.*}}
+// NONE: ret void