This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Dynamic dispatch of multiversioned functions and CPU mocks for code coverage.


Hi,

   This patch is an enhancement to the Function Multiversioning
feature. This patch achieves two things:

*  Primarily, this patch makes it easy to test for code coverage
   of multiversioned functions.
*  Secondary, It makes function multiversioning work when there
   is no ifunc support. Since it invokes the dispatcher for every
   call, it is possible to execute different function versions every
   time. This incurs a performance penalty.

This patch makes it easy to
test for code coverage of multiversioned functions. Here is a
motivating example:

__attribute__((target ("default"))) int foo () { ... return 0; }
__attribute__((target ("sse"))) int foo () { ... return 1; }
__attribute__((target ("popcnt"))) int foo () { ... return 2; }

int main ()
{
  return foo();
}

Lets say your test CPU supports popcnt.  A run of this program will
invoke the popcnt version of foo (). Then, how do we test the sse
version of foo()? To do that for the above example, we need to run
this code on a CPU that has sse support but no popcnt support.
Otherwise, we need to comment out the popcnt version and run this
example. This can get painful when there are many versions. The same
argument applies to testing  the default version of foo.

So, I am introducing the ability to mock a CPU. If the CPU you are
testing on supports sse, you should be able to test the sse version.

First, I have introduced a new flag called -fmultiversion-dynamic-dispatch.
This patch invokes the function version dispatcher every time a call to
a foo () is made. Without that flag, the version dispatch happens once at
startup time via the IFUNC mechanism.

Also, with -fmultiversion-dynamic-dispatch, the version dispatcher uses
the two new builtins "__builtin_mock_cpu_is" and "__builtin_mock_cpu_supports"
to check the cpu type and cpu isa.

Then, I plan to add the following hooks to libgcc (in a different patch) :

int set_mock_cpu_is (const char *cpu);
int set_mock_cpu_supports (const char *isa);
int init_mock_cpu (); // Clear the values of the mock cpu.

With this support, here is how you can test for code coverage of the
"sse" version and "default version of foo in the above example:

int main ()
{
  // Test SSE version.
   if (__builtin_cpu_supports ("sse"))
   {
     init_mock_cpu();
     set_mock_cpu_supports ("sse");
     assert (foo () == 1);
   }
  // Test default version.
  init_mock_cpu();
  assert (foo () == 0);
}

Invoking a multiversioned binary several times with appropriate mock
cpu values for the various ISAs and CPUs will give the complete code
coverage desired. Ofcourse, the underlying platform should be able to
support the various features.

Note that the above test will work only with -fmultiversion-dynamic-dispatch
as the dispatcher must be invoked on every multiversioned call to be able to
dynamically change the version.

Multiple ISA features can be set in the mock cpu by calling
"set_mock_cpu_supports" several times with different ISA names.
Calling "init_mock_cpu" will clear all the values. "set_mock_cpu_is"
will set the CPU type.

This patch only includes the gcc changes.  I will separately prepare a
patch for the libgcc changes. Right now, since the libgcc changes are
not available the two new mock cpu builtins check the real CPU like
"__builtin_cpu_is" and "__builtin_cpu_supports".

Patch attached.  Please look at mv14_debug_code_coverage.C for an
exhaustive example of testing for code coverage in the presence of
multiple versions.

This patch was already discussed when sent earlier to google/gcc-4_7
branch.  That is here: http://gcc.gnu.org/ml/gcc-patches/2013-03/msg00557.html

Some of the alternative suggested here are:

* Lazy IFUNC relocation, which got shot down due to problems with bad
interactions with other shared libraries.
* Using environment variables to mock CPU architectures:  This may still be
plausible. For instance:
LD_CPU_FEATURES=sse,sse2 ./a.out  # run as if only sse and sse2 are available

However, with dynamic dispatch, there is the unique advantage of executing
different function versions in the same execution.


Patch attached.  Comments please.

Thanks
Sri

Attachment: function_mv_dynamic_dispatch.txt
Description: Text document


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]