genericopenlibs/liboil/src/liboiltest.c
changeset 18 47c74d1534e1
--- /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;
+}