--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/genericopenlibs/liboil/src/liboiltest.c Fri Apr 16 16:46:38 2010 +0300
@@ -0,0 +1,778 @@
+/*
+ * LIBOIL - Library of Optimized Inner Loops
+ * Copyright (c) 2003,2004 David A. Schleef <ds@schleef.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+//Portions Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved.
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <liboil/liboiltest.h>
+#include <liboil/liboildebug.h>
+#include <liboil/liboilrandom.h>
+#include <liboil/liboilprofile.h>
+#include <liboil/liboilfault.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <math.h>
+
+#ifdef __SYMBIAN32__
+#ifdef __WINSCW__
+#pragma warn_unusedarg off
+#endif//__WINSCW__
+#endif//__SYMBIAN32__
+
+#define MAX_PARAMS 20
+
+/**
+ * SECTION:liboiltest
+ * @title:OilTest
+ * @short_description: Test and profile function implementations.
+ *
+ */
+static void oil_test_init_params (OilTest *test);
+static void fill_array (void *ptr, OilType type, int pre_n, int stride,
+ int post_n);
+static double check_array (void *data, void *ref, OilType type, int pre_n,
+ int stride, int post_n);
+static int check_holes (void *data, OilType type, int pre_n,
+ int stride, int post_n, int guard);
+
+/**
+ * oil_test_new:
+ * @klass: an OilFunctionClass
+ *
+ * Creates a new OilTest for the OilFunctionClass represented by @klass.
+ *
+ * Returns: the new OilTest
+ */
+#ifdef __SYMBIAN32__
+EXPORT_C
+#endif
+OilTest *
+oil_test_new (OilFunctionClass *klass)
+{
+ OilTest *test;
+ OilPrototype *proto;
+ int i;
+
+ if (klass == NULL) return NULL;
+
+ proto = oil_prototype_from_string (klass->prototype);
+ if (proto == NULL) return NULL;
+
+ test = malloc (sizeof (OilTest));
+ memset (test, 0, sizeof (OilTest));
+
+ test->klass = klass;
+ test->proto = proto;
+ test->impl = klass->reference_impl;
+ test->tolerance = 0.0;
+
+ for (i=0;i<proto->n_params;i++){
+ if (proto->params[i].parameter_type == OIL_ARG_UNKNOWN) {
+ return NULL;
+ }
+ if (oil_type_is_floating_point(proto->params[i].type)) {
+ test->tolerance = 0.001;
+ }
+ memcpy (&test->params[proto->params[i].parameter_type], &proto->params[i],
+ sizeof(OilParameter));
+ }
+ for (i=0;i<OIL_ARG_LAST;i++){
+ test->params[i].src_data = NULL;
+ test->params[i].ref_data = NULL;
+ test->params[i].test_data = NULL;
+ test->params[i].test_header = OIL_TEST_HEADER;
+ test->params[i].test_footer = OIL_TEST_FOOTER;
+ }
+
+ test->iterations = 10;
+ test->n = 100;
+ test->m = 100;
+
+ return test;
+}
+
+/**
+ * oil_test_free:
+ * @test: the OilTest
+ *
+ * Frees memory associated with @test.
+ */
+ #ifdef __SYMBIAN32__
+EXPORT_C
+#endif
+void
+oil_test_free (OilTest *test)
+{
+ int i;
+
+ if (test->proto) {
+ oil_prototype_free (test->proto);
+ }
+
+ for(i=0;i<OIL_ARG_LAST;i++){
+ if (test->params[i].src_data) {
+ free (test->params[i].src_data);
+ }
+ if (test->params[i].ref_data) {
+ free (test->params[i].ref_data);
+ }
+ if (test->params[i].test_data) {
+ free (test->params[i].test_data);
+ }
+ }
+
+ free(test);
+}
+
+/**
+ * oil_test_set_impl:
+ * @test: the OilTest
+ * @impl: an OilFunctionImpl to set
+ *
+ * Sets the current implementation of @test to @impl.
+ */
+ #ifdef __SYMBIAN32__
+ EXPORT_C
+#endif
+void
+oil_test_set_impl (OilTest *test, OilFunctionImpl *impl)
+{
+ test->impl = impl;
+}
+
+/**
+ * oil_test_set_iterations:
+ * @test: the OilTest
+ * @iterations: the number of iterations
+ *
+ * Sets the number of iterations of @test to @iterations.
+ */
+ #ifdef __SYMBIAN32__
+ EXPORT_C
+#endif
+void
+oil_test_set_iterations (OilTest *test, int iterations)
+{
+ test->iterations = iterations;
+}
+
+/**
+ * oil_test_set_test_header:
+ * @test: the OilTest
+ * @p: the OilParameter to change the header for
+ * @test_header: the number of bytes of guard header
+ *
+ * Sets the number of bytes of guard header for @p to @test_header.
+ */
+ #ifdef __SYMBIAN32__
+ EXPORT_C
+#endif
+void
+oil_test_set_test_header (OilTest *test, OilParameter *p, int test_header)
+{
+ p->test_header = test_header;
+}
+
+/**
+ * oil_test_set_test_footer:
+ * @test: the OilTest
+ * @p: the OilParameter to change the footer for
+ * @test_footer: the number of bytes of guard footer
+ *
+ * Sets the number of bytes of guard footer for @p to @test_footer.
+ */
+ #ifdef __SYMBIAN32__
+ EXPORT_C
+#endif
+void
+oil_test_set_test_footer (OilTest *test, OilParameter *p, int test_footer)
+{
+ p->test_footer = test_footer;
+}
+
+/**
+ * oil_test_init:
+ * @test: the OilTest
+ *
+ * Intializes @test.
+ *
+ * FIXME: needs work
+ */
+ #ifdef __SYMBIAN32__
+ EXPORT_C
+#endif
+void
+oil_test_init (OilTest *test)
+{
+ if (test->inited) {
+ return;
+ }
+
+ oil_test_init_params(test);
+
+ test->params[OIL_ARG_N].value = test->n;
+
+ test->inited = 1;
+
+ if (test->klass->test_func) {
+ test->klass->test_func (test);
+ }
+}
+
+#ifdef __WINSCW__
+#pragma suppress_warnings on
+#endif//__WINSCW__
+#ifdef __ARMCC__
+#pragma diag_remark 188
+#endif//__ARMCC__
+
+static void
+oil_test_check_function (void * priv)
+{
+ OilTest *test = priv;
+ int i;
+ int j;
+ unsigned long args[MAX_PARAMS];
+ unsigned int pointer_mask;
+
+ oil_test_init (test);
+
+ OIL_LOG("calling function %s", test->impl->name);
+
+ pointer_mask = 1;
+ for(i=0;i<test->proto->n_params;i++){
+ OilParameter *p;
+ j = test->proto->params[i].parameter_type;
+ p = &test->params[j];
+
+ pointer_mask <<= 1;
+ OIL_LOG(" %s: 0x%08lx (%ld)", oil_arg_type_name (j), p->value, p->value);
+ if (p->is_pointer) {
+ pointer_mask |= 1;
+ if (p->direction == 's') {
+ args[i] = (unsigned long)p->src_data + p->test_header;
+ } else if (p->direction == 'i') {
+ memcpy (p->test_data, p->src_data, p->size);
+ args[i] = (unsigned long)p->test_data + p->test_header;
+ } else if (p->direction == 'd') {
+ memset (p->test_data, p->guard, p->size);
+ args[i] = (unsigned long)p->test_data + p->test_header;
+ } else {
+ OIL_ERROR ("not reached");
+ }
+ } else {
+ args[i] = p->value;
+ }
+ }
+#ifdef __WINSCW__
+#pragma suppress_warnings off
+#endif//__WINSCW__
+
+ oil_profile_init (&test->prof);
+ for(i=0;i<test->iterations;i++){
+ int k;
+
+ for(k=0;k<test->proto->n_params;k++){
+ OilParameter *p;
+ j = test->proto->params[k].parameter_type;
+ p = &test->params[j];
+ if (p->direction == 'i') {
+ memcpy (p->test_data, p->src_data, p->size);
+ }
+ }
+ _oil_test_marshal_function (test->impl->func, args, test->proto->n_params,
+ pointer_mask, &test->prof);
+ }
+
+ oil_profile_get_ave_std (&test->prof, &test->profile_ave,
+ &test->profile_std);
+}
+
+/**
+ * oil_test_check_ref:
+ * @test: the OilTest
+ *
+ * Runs the test specified by @test on the reference function of the
+ * class being tested.
+ */
+ #ifdef __SYMBIAN32__
+ EXPORT_C
+#endif
+void
+oil_test_check_ref (OilTest *test)
+{
+ int i;
+
+ if (test->proto->n_params > MAX_PARAMS) {
+ OIL_ERROR ("function class %s has too many parameters",
+ test->klass->name);
+ return;
+ }
+ if (test->klass->reference_impl == NULL) {
+ OIL_ERROR ("function class %s has no reference implementation",
+ test->klass->name);
+ return;
+ }
+
+ test->impl = test->klass->reference_impl;
+
+ oil_test_check_function (test);
+
+ for(i=0;i<OIL_ARG_LAST;i++){
+ OilParameter *p = &test->params[i];
+
+ if (p->is_pointer) {
+ if (p->direction == 'i' || p->direction == 'd') {
+ memcpy (p->ref_data, p->test_data, p->size);
+ }
+ }
+ }
+
+ test->tested_ref = 1;
+}
+
+static int
+check_guard (uint8_t *data, int n, int guard)
+{
+ int i;
+ for(i=0;i<n;i++) {
+ if (data[i] != guard) return 0;
+ }
+ return 1;
+}
+
+/**
+ * oil_test_check_impl:
+ * @test: the OilTest
+ * @impl: an OilFunctionImpl
+ *
+ * Runs the testing procedure described by @test on the implementation
+ * @impl.
+ *
+ * Returns: 1 if @impl passes the test, 0 if it fails
+ */
+ #ifdef __SYMBIAN32__
+ EXPORT_C
+#endif
+int
+oil_test_check_impl (OilTest *test, OilFunctionImpl *impl)
+{
+ double x;
+ int i;
+ int n;
+ int fail = 0;
+ int ret;
+
+ if (test->proto->n_params > MAX_PARAMS) {
+ OIL_ERROR ("function has too many parameters");
+ return 0;
+ }
+
+ if (!test->inited || !test->tested_ref) {
+ oil_test_check_ref(test);
+ }
+
+ test->impl = impl;
+ ret = oil_fault_check_try (oil_test_check_function, test);
+ if (!ret) {
+ OIL_ERROR ("illegal instruction in %s", test->impl->name);
+ test->profile_ave = 0;
+ test->profile_std = 0;
+
+ return 0;
+ }
+
+ x = 0;
+ n = 0;
+ for(i=0;i<OIL_ARG_LAST;i++){
+ OilParameter *p = &test->params[i];
+
+ if (p->is_pointer) {
+ if (p->direction == 'i' || p->direction == 'd') {
+ x += check_array (p->test_data + p->test_header,
+ p->ref_data + p->test_header, p->type, p->pre_n, p->stride,
+ p->post_n);
+ n += p->pre_n * p->post_n;
+ if (!check_guard (p->test_data, p->test_header, p->guard)) {
+ fail = 1;
+ OIL_ERROR("function %s wrote before area for parameter %s",
+ test->impl->name, p->parameter_name);
+ }
+ if (!check_guard ((uint8_t *)p->test_data + p->size - p->test_footer,
+ p->test_footer, p->guard)) {
+ fail = 1;
+ OIL_ERROR("function %s wrote after area for parameter %s",
+ test->impl->name, p->parameter_name);
+ }
+ if (!check_holes (p->test_data, p->type, p->pre_n, p->stride,
+ p->post_n, p->guard)) {
+ fail = 1;
+ OIL_ERROR("function %s wrote in interstitial area for parameter %s",
+ test->impl->name, p->parameter_name);
+ }
+ }
+ }
+ }
+ OIL_DEBUG("sum of absolute differences %g for %d values", x, n);
+ test->sum_abs_diff = x;
+ test->n_points = n;
+
+ if (x > test->tolerance * n || fail) {
+ OIL_ERROR ("function %s in class %s failed check (%g > %g) || (outside=%d)",
+ test->impl->name, test->klass->name, x, test->tolerance * n, fail);
+ return 0;
+ }
+
+ return 1;
+}
+
+/**
+ * oil_test_cleanup
+ * @test: the OilTest
+ *
+ * Cleans up @test.
+ *
+ * FIXME: needs work
+ */
+ #ifdef __SYMBIAN32__
+ EXPORT_C
+#endif
+void
+oil_test_cleanup (OilTest *test)
+{
+ OilParameter *params = test->params;
+
+ /* src1 */
+ if(params[OIL_ARG_SRC1].type) {
+ if (!params[OIL_ARG_SSTR1].type) {
+ params[OIL_ARG_SSTR1].value = oil_type_sizeof (params[OIL_ARG_SRC1].type);
+ }
+ }
+
+ /* src2 */
+ if(params[OIL_ARG_SRC2].type) {
+ if (!params[OIL_ARG_SSTR2].type) {
+ params[OIL_ARG_SSTR2].value = oil_type_sizeof (params[OIL_ARG_SRC2].type);
+ }
+ }
+
+ /* src3 */
+ if(params[OIL_ARG_SRC3].type) {
+ if (!params[OIL_ARG_SSTR3].type) {
+ params[OIL_ARG_SSTR3].value = oil_type_sizeof (params[OIL_ARG_SRC3].type);
+ }
+ }
+
+ /* dest1 */
+ if(params[OIL_ARG_DEST1].type) {
+ if (!params[OIL_ARG_DSTR1].type) {
+ params[OIL_ARG_DSTR1].value = oil_type_sizeof (params[OIL_ARG_DEST1].type);
+ }
+ }
+
+ /* dest2 */
+ if(params[OIL_ARG_DEST2].type) {
+ if (!params[OIL_ARG_DSTR2].type) {
+ params[OIL_ARG_DSTR2].value = oil_type_sizeof (params[OIL_ARG_DEST2].type);
+ }
+ }
+
+ /* dest3 */
+ if(params[OIL_ARG_DEST3].type) {
+ if (!params[OIL_ARG_DSTR3].type) {
+ params[OIL_ARG_DSTR3].value = oil_type_sizeof (params[OIL_ARG_DEST3].type);
+ }
+ }
+
+}
+
+
+static void
+init_parameter (OilTest *test, OilParameter *p, OilParameter *ps)
+{
+ if (!p->type) return;
+
+ p->pre_n = p->prestride_length;
+ if (p->prestride_var == 1) {
+ p->pre_n += test->n;
+ }
+ if (p->prestride_var == 2) {
+ p->pre_n += test->m;
+ }
+
+ if (ps->value) {
+ p->stride = ps->value;
+ } else {
+ p->stride = oil_type_sizeof (p->type) * p->pre_n;
+ ps->value = p->stride;
+ }
+
+ p->post_n = p->poststride_length;
+ if (p->poststride_var == 1) {
+ p->post_n += test->n;
+ }
+ if (p->poststride_var == 2) {
+ p->post_n += test->m;
+ }
+
+ p->size = p->stride * p->post_n + p->test_header + p->test_footer;
+ p->guard = oil_rand_u8();
+
+ if (p->direction == 'i' || p->direction == 's') {
+ if (p->src_data) free (p->src_data);
+
+ OIL_DEBUG("allocating %d bytes for src_data for %s", p->size, p->parameter_name);
+ p->src_data = malloc (p->size);
+ memset (p->src_data, p->guard, p->size);
+ fill_array (p->src_data + p->test_header, p->type, p->pre_n, p->stride, p->post_n);
+ }
+
+ if (p->direction == 'i' || p->direction == 'd') {
+ if (p->ref_data) free (p->ref_data);
+ p->ref_data = malloc (p->size);
+ memset (p->ref_data, p->guard, p->size);
+ OIL_DEBUG("allocating %d bytes for ref_data and test_data for %s", p->size, p->parameter_name);
+
+ if (p->test_data) free (p->test_data);
+ p->test_data = malloc (p->size);
+ memset (p->test_data, p->guard, p->size);
+ }
+}
+
+static void
+oil_test_init_params (OilTest *test)
+{
+ init_parameter (test, &test->params[OIL_ARG_DEST1],
+ &test->params[OIL_ARG_DSTR1]);
+ init_parameter (test, &test->params[OIL_ARG_DEST2],
+ &test->params[OIL_ARG_DSTR2]);
+ init_parameter (test, &test->params[OIL_ARG_DEST3],
+ &test->params[OIL_ARG_DSTR3]);
+
+ init_parameter (test, &test->params[OIL_ARG_SRC1],
+ &test->params[OIL_ARG_SSTR1]);
+ init_parameter (test, &test->params[OIL_ARG_SRC2],
+ &test->params[OIL_ARG_SSTR2]);
+ init_parameter (test, &test->params[OIL_ARG_SRC3],
+ &test->params[OIL_ARG_SSTR3]);
+ init_parameter (test, &test->params[OIL_ARG_SRC4],
+ &test->params[OIL_ARG_SSTR4]);
+ init_parameter (test, &test->params[OIL_ARG_SRC5],
+ &test->params[OIL_ARG_SSTR5]);
+
+ init_parameter (test, &test->params[OIL_ARG_INPLACE1],
+ &test->params[OIL_ARG_ISTR1]);
+ init_parameter (test, &test->params[OIL_ARG_INPLACE2],
+ &test->params[OIL_ARG_ISTR2]);
+}
+
+static void
+fill_array (void *data, OilType type, int pre_n, int stride, int post_n)
+{
+ int i;
+
+#define FILL(type,func) do {\
+ for(i=0;i<post_n;i++){ \
+ func (OIL_OFFSET(data, i*stride), pre_n); \
+ } \
+}while(0)
+
+ switch (type) {
+ case OIL_TYPE_s8p:
+ FILL(int8_t,oil_random_s8);
+ break;
+ case OIL_TYPE_u8p:
+ FILL(uint8_t,oil_random_u8);
+ break;
+ case OIL_TYPE_s16p:
+ FILL(int16_t,oil_random_s16);
+ break;
+ case OIL_TYPE_u16p:
+ FILL(uint16_t,oil_random_u16);
+ break;
+ case OIL_TYPE_s32p:
+ FILL(int32_t,oil_random_s32);
+ break;
+ case OIL_TYPE_u32p:
+ FILL(uint32_t,oil_random_u32);
+ break;
+ case OIL_TYPE_s64p:
+ FILL(int64_t,oil_random_s64);
+ break;
+ case OIL_TYPE_u64p:
+ FILL(uint64_t,oil_random_u64);
+ break;
+ case OIL_TYPE_f32p:
+ FILL(float,oil_random_f32);
+ break;
+ case OIL_TYPE_f64p:
+ FILL(double,oil_random_f64);
+ break;
+ default:
+ OIL_ERROR ("should not be reached (type == %d)", type);
+ return;
+ break;
+ }
+}
+
+static double
+check_array (void *data, void *ref, OilType type, int pre_n, int stride, int post_n)
+{
+ int i;
+ int j;
+ int s2 = oil_type_sizeof (type);
+ double x = 0;
+
+#if 0
+ OIL_ERROR ("check array pre_n=%d stride=%d post_n=%d",
+ pre_n, stride, post_n);
+#endif
+
+#define CHECK(type) do {\
+ for(i=0;i<post_n;i++){ \
+ for(j=0;j<pre_n;j++){ \
+ x += fabs((double)OIL_GET(data, i*stride + j*s2, type) - \
+ (double)OIL_GET(ref, i*stride + j*s2, type)); \
+ } \
+ } \
+}while(0)
+
+ switch (type) {
+ case OIL_TYPE_s8p:
+ CHECK(int8_t);
+ break;
+ case OIL_TYPE_u8p:
+ CHECK(uint8_t);
+ break;
+ case OIL_TYPE_s16p:
+ CHECK(int16_t);
+ break;
+ case OIL_TYPE_u16p:
+ CHECK(uint16_t);
+ break;
+ case OIL_TYPE_s32p:
+ CHECK(int32_t);
+ break;
+ case OIL_TYPE_u32p:
+ CHECK(uint32_t);
+ break;
+ case OIL_TYPE_s64p:
+ CHECK(int64_t);
+ break;
+ case OIL_TYPE_u64p:
+ CHECK(uint64_t);
+ break;
+ case OIL_TYPE_f32p:
+ CHECK(float);
+ break;
+ case OIL_TYPE_f64p:
+ CHECK(double);
+ break;
+ default:
+ OIL_ERROR ("should not be reached (type == %d)", type);
+ return 1e9;
+ break;
+ }
+ return x;
+}
+
+static int
+check_holes (void *data, OilType type, int pre_n, int stride, int post_n,
+ int guard)
+{
+ int i;
+ int chunk_size;
+ int hole_size;
+
+ chunk_size = pre_n * oil_type_sizeof (type);
+ hole_size = stride - chunk_size;
+ if (hole_size == 0) {
+ return 1;
+ }
+
+ for(i=0;i<post_n;i++){
+ if (!check_guard (OIL_OFFSET(data, stride * i + chunk_size),
+ hole_size, guard)) {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+#ifdef __SYMBIAN32__
+ EXPORT_C
+#endif
+void *
+oil_test_get_source_data (OilTest *test, OilArgType arg_type)
+{
+ uint8_t *ptr;
+
+ ptr = test->params[arg_type].src_data;
+ ptr += test->params[arg_type].test_header;
+
+ return ptr;
+}
+
+#ifdef __SYMBIAN32__
+ EXPORT_C
+#endif
+int
+oil_test_get_arg_pre_n (OilTest *test, OilArgType arg_type)
+{
+ return test->params[arg_type].pre_n;
+}
+
+#ifdef __SYMBIAN32__
+ EXPORT_C
+#endif
+int
+oil_test_get_arg_post_n (OilTest *test, OilArgType arg_type)
+{
+ return test->params[arg_type].post_n;
+}
+
+#ifdef __SYMBIAN32__
+ EXPORT_C
+#endif
+int
+oil_test_get_arg_stride (OilTest *test, OilArgType arg_type)
+{
+ return test->params[arg_type].stride;
+}
+
+#ifdef __SYMBIAN32__
+ EXPORT_C
+#endif
+int
+oil_test_get_value (OilTest *test, OilArgType arg_type)
+{
+ return test->params[arg_type].value;
+}