Ok. If the use case is to enable the test of  the same application
binary (not the per function unit test) with CPU mocking at runtime
(via environment variable or application specific flags), the proposed
changes make sense.

David

On Fri, Mar 15, 2013 at 3:49 PM, Sriraman Tallam <tmsri...@google.com> wrote:
> On Fri, Mar 15, 2013 at 3:37 PM, Xinliang David Li <davi...@google.com> wrote:
>> On Fri, Mar 15, 2013 at 2:55 PM, Sriraman Tallam <tmsri...@google.com> wrote:
>>> Hi,
>>>
>>>    This patch is meant for google/gcc-4_7 but I want this to be
>>> considered for trunk when it opens again. 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 -fmv-debug.  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 -fmv-debug, 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.
>>
>> With this option, compiler probably can also define some macros so
>> that if user can use to write overriding hooks.
>>
>>>
>>> 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.
>>>
>>
>> It is the other way around -- it simplifies unit test writing and
>> running -- one unit test just need to be run on the same hardware
>> (with the most hw features) *ONCE* and all the versions can be
>> covered.
>
>
> Yes,  the test needs to run just once, potentially, if the test
> platform can support all of the features.
>
>>
>>
>>
>>> Note that the above test will work only with -fmv-debug 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.
>>>
>>
>>
>> Just through about another idea. Is it possible for compiler to create
>> some alias for each version so that they can be accessed explicitly,
>> just like the use of :: ?
>>
>> if (__buitin_cpu_supports ("sse"))
>>    CHECK_RESULT (foo_sse (...));
>>
>> CHECK_RESULT (foo_default(...));
>
> This will work for this example. But, in general, this means changing
> the call site of every multiversioned call and that can become
> infeasible.
>
> Thanks
> Sri
>
>
>>
>> ...
>>
>> David
>>
>>
>>> 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.
>>>
>>> Comments please.
>>>
>>> Thanks
>>> Sri

Reply via email to