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

2013-05-13 Thread Xinliang David Li
The MV testing support includes 3 logical parts:
1) runtime APIs to check mocked CPU types and features
(__builtin_mock_cpu_supports ..)
2) runtime APIs to do CPU mocking;
3) compile time option to do lazy dispatching (instead of using IFUNC).

3)  can be used to also support target without IFUNC support, but it
should be handled differently -- for instance, it does not need an
option, nor should it use the mock version of the feature testing.

I like the flexibility the patch provides for testing -- it allows
global mocking via environment variable, and fine grain mocking at
each callsite. The former is good for application testing, and latter
is suitable for unit testing.

What is the design of the environment variable used to control the
behavior of __builtin_mock_cpu...? They are part of the user interface
and should be documented somewhere.

thanks,

David


On Thu, May 9, 2013 at 7:30 PM, Sriraman Tallam  wrote:
> 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:

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

2013-05-10 Thread Joseph S. Myers
On Fri, 10 May 2013, Sriraman Tallam wrote:

> On Fri, May 10, 2013 at 6:34 AM, Joseph S. Myers
>  wrote:
> > On Thu, 9 May 2013, Sriraman Tallam wrote:
> >
> >> 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.
> >
> > Those names are in the user's namespace; I think libgcc should only
> > provide or use symbols in the implementation namespace.
> 
> Shall I just use __builtin prefixes for these too?, would that work?

I'm not sure if that's a good idea for something that's actually a library 
function (we've previously discussed rejecting explicit declarations of 
__builtin_* identifiers to some extent - see bug 32455 - which would be an 
issue for defining library functions with such a name if we do decide in 
future to reject such declarations), but use __ prefixes in some form, 
certainly.

-- 
Joseph S. Myers
jos...@codesourcery.com


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

2013-05-10 Thread Sriraman Tallam
On Fri, May 10, 2013 at 6:34 AM, Joseph S. Myers
 wrote:
> On Thu, 9 May 2013, Sriraman Tallam wrote:
>
>> 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.
>
> Those names are in the user's namespace; I think libgcc should only
> provide or use symbols in the implementation namespace.

Shall I just use __builtin prefixes for these too?, would that work?

Thanks
Sri

>
> --
> Joseph S. Myers
> jos...@codesourcery.com


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

2013-05-10 Thread Joseph S. Myers
On Thu, 9 May 2013, Sriraman Tallam wrote:

> 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.

Those names are in the user's namespace; I think libgcc should only 
provide or use symbols in the implementation namespace.

-- 
Joseph S. Myers
jos...@codesourcery.com


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

2013-05-09 Thread Sriraman Tallam
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
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.

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 p