Skip to content

Commit

Permalink
[Clang] Add options -fprofile-filter-files and -fprofile-exclude-file…
Browse files Browse the repository at this point in the history
…s to filter the files to instrument with gcov (after revert https://reviews.llvm.org/rL346659)

Summary:
the previous patch (https://reviews.llvm.org/rC346642) has been reverted because of test failure under windows.
So this patch fix the test cfe/trunk/test/CodeGen/code-coverage-filter.c.

Reviewers: marco-c

Reviewed By: marco-c

Subscribers: cfe-commits, sylvestre.ledru

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

llvm-svn: 347144
  • Loading branch information
calixteman committed Nov 17, 2018
1 parent 0438d79 commit f4bf671
Show file tree
Hide file tree
Showing 10 changed files with 182 additions and 0 deletions.
6 changes: 6 additions & 0 deletions clang/docs/ReleaseNotes.rst
Expand Up @@ -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
Expand Down
49 changes: 49 additions & 0 deletions clang/docs/UsersManual.rst
Expand Up @@ -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
-----------------------------

Expand Down
6 changes: 6 additions & 0 deletions clang/include/clang/Driver/Options.td
Expand Up @@ -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">;
Expand Down
6 changes: 6 additions & 0 deletions clang/include/clang/Frontend/CodeGenOptions.h
Expand Up @@ -129,6 +129,12 @@ class CodeGenOptions : public CodeGenOptionsBase {
/// 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];

Expand Down
2 changes: 2 additions & 0 deletions clang/lib/CodeGen/BackendUtil.cpp
Expand Up @@ -504,6 +504,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;
}
Expand Down
23 changes: 23 additions & 0 deletions clang/lib/Driver/ToolChains/Clang.cpp
Expand Up @@ -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_filter_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()) {
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Frontend/CompilerInvocation.cpp
Expand Up @@ -829,6 +829,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)) {
Expand Down
1 change: 1 addition & 0 deletions clang/test/CodeGen/Inputs/code-coverage-filter1.h
@@ -0,0 +1 @@
void test1() {}
1 change: 1 addition & 0 deletions clang/test/CodeGen/Inputs/code-coverage-filter2.h
@@ -0,0 +1 @@
void test2() {}
84 changes: 84 additions & 0 deletions clang/test/CodeGen/code-coverage-filter.c
@@ -0,0 +1,84 @@
// RUN: %clang -S -emit-llvm --coverage %s -o %t
// RUN: FileCheck -check-prefix=ALL < %t %s
// RUN: %clang -S -emit-llvm --coverage -fprofile-exclude-files=".*\.h$" %s -o %t
// RUN: FileCheck -check-prefix=NO-HEADER < %t %s
// RUN: %clang -S -emit-llvm --coverage -fprofile-filter-files=".*\.c$" %s -o %t
// RUN: FileCheck -check-prefix=NO-HEADER < %t %s
// RUN: %clang -S -emit-llvm --coverage -fprofile-filter-files=".*\.c$;.*1\.h$" %s -o %t
// RUN: FileCheck -check-prefix=NO-HEADER2 < %t %s
// RUN: %clang -S -emit-llvm --coverage -fprofile-exclude-files=".*2\.h$;.*1\.h$" %s -o %t
// RUN: FileCheck -check-prefix=JUST-C < %t %s
// RUN: %clang -S -emit-llvm --coverage -fprofile-exclude-files=".*code\-coverage\-filter\.c$" %s -o %t
// RUN: FileCheck -check-prefix=HEADER < %t %s
// RUN: %clang -S -emit-llvm --coverage -fprofile-filter-files=".*\.c$" -fprofile-exclude-files=".*\.c$" %s -o %t
// RUN: FileCheck -check-prefix=NONE < %t %s
// RUN: %clang -S -emit-llvm --coverage -fprofile-filter-files=".*\.c$" -fprofile-exclude-files=".*\.h$" %s -o %t
// RUN: FileCheck -check-prefix=JUST-C < %t %s

#include "Inputs/code-coverage-filter1.h"
#include "Inputs/code-coverage-filter2.h"

void test() {
test1();
test2();
}

// ALL: void @test1() #0 {{.*}}
// ALL: {{.*}}__llvm_gcov_ctr{{.*}}
// ALL: ret void
// ALL: void @test2() #0 {{.*}}
// ALL: {{.*}}__llvm_gcov_ctr{{.*}}
// ALL: ret void
// ALL: void @test() #0 {{.*}}
// ALL: {{.*}}__llvm_gcov_ctr{{.*}}
// ALL: ret void

// NO-HEADER: void @test1() #0 {{.*}}
// NO-HEADER-NOT: {{.*}}__llvm_gcov_ctr{{.*}}
// NO-HEADER: ret void
// NO-HEADER: void @test2() #0 {{.*}}
// NO-HEADER-NOT: {{.*}}__llvm_gcov_ctr{{.*}}
// NO-HEADER: ret void
// NO-HEADER: void @test() #0 {{.*}}
// NO-HEADER: {{.*}}__llvm_gcov_ctr{{.*}}
// NO-HEADER: ret void

// NO-HEADER2: void @test1() #0 {{.*}}
// NO-HEADER2: {{.*}}__llvm_gcov_ctr{{.*}}
// NO-HEADER2: ret void
// NO-HEADER2: void @test2() #0 {{.*}}
// NO-HEADER2-NOT: {{.*}}__llvm_gcov_ctr{{.*}}
// NO-HEADER2: ret void
// NO-HEADER2: void @test() #0 {{.*}}
// NO-HEADER2: {{.*}}__llvm_gcov_ctr{{.*}}
// NO-HEADER2: ret void

// JUST-C: void @test1() #0 {{.*}}
// JUST-C-NOT: {{.*}}__llvm_gcov_ctr{{.*}}
// JUST-C: ret void
// JUST-C: void @test2() #0 {{.*}}
// JUST-C-NOT: {{.*}}__llvm_gcov_ctr{{.*}}
// JUST-C: ret void
// JUST-C: void @test() #0 {{.*}}
// JUST-C: {{.*}}__llvm_gcov_ctr{{.*}}
// JUST-C: ret void

// HEADER: void @test1() #0 {{.*}}
// HEADER: {{.*}}__llvm_gcov_ctr{{.*}}
// HEADER: ret void
// HEADER: void @test2() #0 {{.*}}
// HEADER: {{.*}}__llvm_gcov_ctr{{.*}}
// HEADER: ret void
// HEADER: void @test() #0 {{.*}}
// HEADER-NOT: {{.*}}__llvm_gcov_ctr{{.*}}
// HEADER: ret void

// NONE: void @test1() #0 {{.*}}
// NONE-NOT: {{.*}}__llvm_gcov_ctr{{.*}}
// NONE: ret void
// NONE: void @test2() #0 {{.*}}
// NONE-NOT: {{.*}}__llvm_gcov_ctr{{.*}}
// NONE: ret void
// NONE: void @test() #0 {{.*}}
// NONE-NOT: {{.*}}__llvm_gcov_ctr{{.*}}
// NONE: ret void

0 comments on commit f4bf671

Please sign in to comment.