Hi Jan/Tom,

Sorry to resurrect an ancient thread, but I was poking at the piglit CL ULP
issue last night, and thought I'd try to get us closer to a solution after
dropping the matter for too long.

I've modified your test program with what I was thinking of trying, and I
wouldn't mind your feedback.

I realize that we still have issues with discrepancies between
python-generated expected results based on cpu/rounding mode and the , but
I'd at least like for us to be able to nail down the C portion before we
start redefining all of our expected test results.  In the long term, we
probably want to hand-select our inputs/outputs instead of trusting python,
but I don't necessarily think that we should block fixing our ULP
calculations on getting that done.

For now, I'm still ignoring the half-ULP possibility, and just generating a
minimum/maximum allowed value based on running nextafterf(expected, POS/NEG
INFINITY) in a loop for ULP iterations. Does that sound like a tenable
solution?

--Aaron

On Sun, Jun 14, 2015 at 4:19 PM, Jan Vesely <[email protected]> wrote:

> On Sat, 2015-06-13 at 21:22 -0500, Aaron Watry wrote:
> > Meh, this still feels broken.  Give me a bit longer.
>
> and it is :). I don't think this can work based on abs(expected - real),
> since ULP depends on the magnitude of the numbers. This information is
> lost after subtraction.
>
> I had an idea some time back to implement this using nextafterf in both
> directions and checking whether the result falls in that interval.
> However, there is still a problem. Some of the expected values are
> already rounded (I'm not sure what rounding mode is used by python by
> default), but unless it always rounds in one direction, we'll still get
> slight differences based on whether the actual value was rounded up or
> down.
>
> I have attached a small test program that shows the deficiencies of
> fabsf based approaches.
>
> regards,
> Jan
>
> >
> > --Aaron
> >
> > On Sat, Jun 13, 2015 at 2:28 PM, Aaron Watry <[email protected]> wrote:
> >
> > > We need to actually check against the float value from the union,
> > > instead of just doing (diff > ulp), which seems to cast the diff to
> > > an int before checking against ulp.
> > >
> > > Signed-off-by: Aaron Watry <[email protected]>
> > > CC: Tom Stellard <[email protected]>
> > > CC: Jan Vesely <[email protected]>
> > > ---
> > >  tests/util/piglit-util-cl.c | 28 ++++++++++++++--------------
> > >  1 file changed, 14 insertions(+), 14 deletions(-)
> > >
> > > diff --git a/tests/util/piglit-util-cl.c b/tests/util/piglit-util-cl.c
> > > index 47e0c7a..6cdd718 100644
> > > --- a/tests/util/piglit-util-cl.c
> > > +++ b/tests/util/piglit-util-cl.c
> > > @@ -80,7 +80,7 @@ piglit_cl_probe_floating(float value, float expect,
> > > uint32_t ulp)
> > >
> > >         diff = fabsf(value - expect);
> > >
> > > -       if(diff > ulp || isnan(value)) {
> > > +       if (diff > t.f || isnan(value)) {
> > >                 printf("Expecting %f (0x%x) with tolerance %f (%u
> ulps),
> > > but got %f (0x%x)\n",
> > >                        e.f, e.u, t.f, t.u, v.f, v.u);
> > >                 return false;
> > > @@ -108,7 +108,7 @@ piglit_cl_probe_double(double value, double expect,
> > > uint64_t ulp)
> > >
> > >         diff = fabsl(value - expect);
> > >
> > > -       if(diff > ulp || isnan(value)) {
> > > +       if (diff > t.f || isnan(value)) {
> > >                 printf("Expecting %f (0x%lx) with tolerance %f (%lu
> ulps),
> > > but got %f (0x%lx)\n",
> > >                        e.f, e.u, t.f, t.u, v.f, v.u);
> > >                 return false;
> > > @@ -162,7 +162,7 @@ piglit_cl_get_platform_version(cl_platform_id
> platform)
> > >         int scanf_count;
> > >         int major;
> > >         int minor;
> > > -
> > > +
> > >         /*
> > >          * Returned format:
> > >          *
> > >  OpenCL<space><major_version.minor_version><space><platform-specific
> > > information>
> > > @@ -353,7 +353,7 @@ piglit_cl_get_info(void* fn_ptr, void* obj, cl_uint
> > > param)
> > >
> > >         if(errNo == CL_SUCCESS) {
> > >                 param_ptr = calloc(param_size, sizeof(char));
> > > -
> > > +
> > >                 /* retrieve param */
> > >                 if(fn_ptr == clGetPlatformInfo) {
> > >                         errNo =
> clGetPlatformInfo(*(cl_platform_id*)obj,
> > > param,
> > > @@ -463,7 +463,7 @@ piglit_cl_get_program_build_info(cl_program
> program,
> > > cl_device_id device,
> > >                 .program = program,
> > >                 .device = device
> > >         };
> > > -
> > > +
> > >         return piglit_cl_get_info(clGetProgramBuildInfo, &args, param);
> > >  }
> > >
> > > @@ -479,7 +479,7 @@ piglit_cl_get_kernel_work_group_info(cl_kernel
> kernel,
> > > cl_device_id device,
> > >                 .kernel = kernel,
> > >                 .device = device
> > >         };
> > > -
> > > +
> > >         return piglit_cl_get_info(clGetKernelWorkGroupInfo, &args,
> param);
> > >  }
> > >
> > > @@ -620,7 +620,7 @@ piglit_cl_get_device_ids(cl_platform_id
> platform_id,
> > > cl_device_type device_type,
> > >
>  piglit_cl_get_error_name(errNo));
> > >                                 return 0;
> > >                         }
> > > -
> > > +
> > >                         /* get device list */
> > >                         if(device_ids != NULL && num_device_ids > 0) {
> > >                                 *device_ids = malloc(num_device_ids *
> > > sizeof(cl_device_id));
> > > @@ -761,7 +761,7 @@
> > > piglit_cl_build_program_with_source_extended(piglit_cl_context context,
> > >                         piglit_cl_get_error_name(errNo));
> > >                 return NULL;
> > >         }
> > > -
> > > +
> > >         errNo = clBuildProgram(program,
> > >                                context->num_devices,
> > >                                context->device_ids,
> > > @@ -788,7 +788,7 @@
> > > piglit_cl_build_program_with_source_extended(piglit_cl_context context,
> > >                         char* log =
> > > piglit_cl_get_program_build_info(program,
> > >
> > >  context->device_ids[i],
> > >
> > >  CL_PROGRAM_BUILD_LOG);
> > > -
> > > +
> > >                         printf("Build log for device %s:\n --------
> \n%s\n
> > > -------- \n",
> > >                                device_name,
> > >                                log);
> > > @@ -848,11 +848,11 @@
> > > piglit_cl_build_program_with_binary_extended(piglit_cl_context context,
> > >                 for(i = 0; i < context->num_devices; i++) {
> > >                         char* device_name =
> > > piglit_cl_get_device_info(context->device_ids[i],
> > >
> > > CL_DEVICE_NAME);
> > > -
> > > +
> > >                         printf("Error for %s: %s\n",
> > >                                device_name,
> > >
> piglit_cl_get_error_name(binary_status[i]));
> > > -
> > > +
> > >                         free(device_name);
> > >                 }
> > >
> > > @@ -860,7 +860,7 @@
> > > piglit_cl_build_program_with_binary_extended(piglit_cl_context context,
> > >                 return NULL;
> > >         }
> > >         free(binary_status);
> > > -
> > > +
> > >         errNo = clBuildProgram(program,
> > >                                context->num_devices,
> > >                                context->device_ids,
> > > @@ -884,11 +884,11 @@
> > > piglit_cl_build_program_with_binary_extended(piglit_cl_context context,
> > >                         char* log =
> > > piglit_cl_get_program_build_info(program,
> > >
> > >  context->device_ids[i],
> > >
> > >  CL_PROGRAM_BUILD_LOG);
> > > -
> > > +
> > >                         printf("Build log for device %s:\n --------
> \n%s\n
> > > -------- \n",
> > >                                device_name,
> > >                                log);
> > > -
> > > +
> > >                         free(device_name);
> > >                         free(log);
> > >                 }
> > > --
> > > 2.1.4
> > >
> > >
>
>
> --
> Jan Vesely <[email protected]>
>
#include <stdio.h>
#include <stdint.h>
#include <math.h>

typedef union {
	uint32_t u;
	float f;
} number_t;

enum {
	ULP = 2
};

int new_ulp_check(float value, float expect, uint32_t ulp){
    union {
		float f;
		uint32_t u;
	} v, e, min, max;

    v.f = value;
	e.f = expect;
	max.f = min.f = expect;
	for(uint32_t i = 0; i < ulp; i++){
		min.f = nextafterf(min.f, -INFINITY);
		max.f = nextafterf(max.f, INFINITY);
	}

	if(v.f < min.f || v.f > max.f || isnan(v.f)) {
        return 0; //fail
    }
    return 1; //success
}

int test(float res)
{
	number_t num, numfail,  expected, diff, faildiff, ulp;

	expected.f = res;
	// assume we are off by 1 ulp
	num.f = nextafterf(res, 0.0f);

	// fail is off by 3
	numfail.f = nextafterf(num.f, 0.0f);
	numfail.f = nextafterf(numfail.f, 0.0f);

	diff.f = fabsf(num.f - expected.f);
	faildiff.f = fabsf(numfail.f - expected.f);
	ulp.u = ULP;

	printf("expected: %.17e, %x\n", expected.f, expected.u);
	printf("num: %.17e, %x\n", num.f, num.u);
	printf("numfail: %.17e, %x\n", numfail.f, numfail.u);

	printf("diff: %.17e, %x\n", diff.f, diff.u);
	printf("faildiff: %.17e, %x\n", faildiff.f, faildiff.u);
	printf("ulp: %.17e, %x\n", ulp.f, ulp.u);

	if (diff.f < ulp.f && faildiff.f >= ulp.f)
		printf("New way PASSED\n");
	else
		printf("New way FAILED when it should have PASSED\n");

	if (diff.f < ULP && faildiff.f >= ULP)
		printf("Old way PASSED\n");
	else
		printf("Old way FAILED when it should have PASSED\n");

    if (new_ulp_check(num.f, expected.f, ulp.u))
        printf("new_ulp_check PASSED\n");
    else
        printf("new_ulp_check FAILED\n");

	return 0;
}

int main(void)
{
	test(2 << 30);
	printf("\n");

	test(0.00000000001f);
	printf("\n");

	test(4.0f);
	printf("\n");

	test(1.0f);
	printf("\n");

	test(2 << 24);
	printf("\n");

	test(2 << 23);
	printf("\n");
}
_______________________________________________
Piglit mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/piglit

Reply via email to