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 <tmsri...@google.com> 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:
> 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

Reply via email to