First public contribution.
2 * LIBOIL - Library of Optimized Inner Loops
3 * Copyright (c) 2003,2004 David A. Schleef <ds@schleef.org>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
19 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
23 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
24 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 * POSSIBILITY OF SUCH DAMAGE.
27 //Portions Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved.
33 #include <liboil/liboiltest.h>
34 #include <liboil/liboildebug.h>
35 #include <liboil/liboilrandom.h>
36 #include <liboil/liboilprofile.h>
37 #include <liboil/liboilfault.h>
45 #pragma warn_unusedarg off
54 * @short_description: Test and profile function implementations.
57 static void oil_test_init_params (OilTest *test);
58 static void fill_array (void *ptr, OilType type, int pre_n, int stride,
60 static double check_array (void *data, void *ref, OilType type, int pre_n,
61 int stride, int post_n);
62 static int check_holes (void *data, OilType type, int pre_n,
63 int stride, int post_n, int guard);
67 * @klass: an OilFunctionClass
69 * Creates a new OilTest for the OilFunctionClass represented by @klass.
71 * Returns: the new OilTest
77 oil_test_new (OilFunctionClass *klass)
83 if (klass == NULL) return NULL;
85 proto = oil_prototype_from_string (klass->prototype);
86 if (proto == NULL) return NULL;
88 test = malloc (sizeof (OilTest));
89 memset (test, 0, sizeof (OilTest));
93 test->impl = klass->reference_impl;
94 test->tolerance = 0.0;
96 for (i=0;i<proto->n_params;i++){
97 if (proto->params[i].parameter_type == OIL_ARG_UNKNOWN) {
100 if (oil_type_is_floating_point(proto->params[i].type)) {
101 test->tolerance = 0.001;
103 memcpy (&test->params[proto->params[i].parameter_type], &proto->params[i],
104 sizeof(OilParameter));
106 for (i=0;i<OIL_ARG_LAST;i++){
107 test->params[i].src_data = NULL;
108 test->params[i].ref_data = NULL;
109 test->params[i].test_data = NULL;
110 test->params[i].test_header = OIL_TEST_HEADER;
111 test->params[i].test_footer = OIL_TEST_FOOTER;
114 test->iterations = 10;
125 * Frees memory associated with @test.
131 oil_test_free (OilTest *test)
136 oil_prototype_free (test->proto);
139 for(i=0;i<OIL_ARG_LAST;i++){
140 if (test->params[i].src_data) {
141 free (test->params[i].src_data);
143 if (test->params[i].ref_data) {
144 free (test->params[i].ref_data);
146 if (test->params[i].test_data) {
147 free (test->params[i].test_data);
157 * @impl: an OilFunctionImpl to set
159 * Sets the current implementation of @test to @impl.
165 oil_test_set_impl (OilTest *test, OilFunctionImpl *impl)
171 * oil_test_set_iterations:
173 * @iterations: the number of iterations
175 * Sets the number of iterations of @test to @iterations.
181 oil_test_set_iterations (OilTest *test, int iterations)
183 test->iterations = iterations;
187 * oil_test_set_test_header:
189 * @p: the OilParameter to change the header for
190 * @test_header: the number of bytes of guard header
192 * Sets the number of bytes of guard header for @p to @test_header.
198 oil_test_set_test_header (OilTest *test, OilParameter *p, int test_header)
200 p->test_header = test_header;
204 * oil_test_set_test_footer:
206 * @p: the OilParameter to change the footer for
207 * @test_footer: the number of bytes of guard footer
209 * Sets the number of bytes of guard footer for @p to @test_footer.
215 oil_test_set_test_footer (OilTest *test, OilParameter *p, int test_footer)
217 p->test_footer = test_footer;
232 oil_test_init (OilTest *test)
238 oil_test_init_params(test);
240 test->params[OIL_ARG_N].value = test->n;
244 if (test->klass->test_func) {
245 test->klass->test_func (test);
250 #pragma suppress_warnings on
253 #pragma diag_remark 188
257 oil_test_check_function (void * priv)
259 OilTest *test = priv;
262 unsigned long args[MAX_PARAMS];
263 unsigned int pointer_mask;
265 oil_test_init (test);
267 OIL_LOG("calling function %s", test->impl->name);
270 for(i=0;i<test->proto->n_params;i++){
272 j = test->proto->params[i].parameter_type;
273 p = &test->params[j];
276 OIL_LOG(" %s: 0x%08lx (%ld)", oil_arg_type_name (j), p->value, p->value);
279 if (p->direction == 's') {
280 args[i] = (unsigned long)p->src_data + p->test_header;
281 } else if (p->direction == 'i') {
282 memcpy (p->test_data, p->src_data, p->size);
283 args[i] = (unsigned long)p->test_data + p->test_header;
284 } else if (p->direction == 'd') {
285 memset (p->test_data, p->guard, p->size);
286 args[i] = (unsigned long)p->test_data + p->test_header;
288 OIL_ERROR ("not reached");
295 #pragma suppress_warnings off
298 oil_profile_init (&test->prof);
299 for(i=0;i<test->iterations;i++){
302 for(k=0;k<test->proto->n_params;k++){
304 j = test->proto->params[k].parameter_type;
305 p = &test->params[j];
306 if (p->direction == 'i') {
307 memcpy (p->test_data, p->src_data, p->size);
310 _oil_test_marshal_function (test->impl->func, args, test->proto->n_params,
311 pointer_mask, &test->prof);
314 oil_profile_get_ave_std (&test->prof, &test->profile_ave,
319 * oil_test_check_ref:
322 * Runs the test specified by @test on the reference function of the
323 * class being tested.
329 oil_test_check_ref (OilTest *test)
333 if (test->proto->n_params > MAX_PARAMS) {
334 OIL_ERROR ("function class %s has too many parameters",
338 if (test->klass->reference_impl == NULL) {
339 OIL_ERROR ("function class %s has no reference implementation",
344 test->impl = test->klass->reference_impl;
346 oil_test_check_function (test);
348 for(i=0;i<OIL_ARG_LAST;i++){
349 OilParameter *p = &test->params[i];
352 if (p->direction == 'i' || p->direction == 'd') {
353 memcpy (p->ref_data, p->test_data, p->size);
358 test->tested_ref = 1;
362 check_guard (uint8_t *data, int n, int guard)
366 if (data[i] != guard) return 0;
372 * oil_test_check_impl:
374 * @impl: an OilFunctionImpl
376 * Runs the testing procedure described by @test on the implementation
379 * Returns: 1 if @impl passes the test, 0 if it fails
385 oil_test_check_impl (OilTest *test, OilFunctionImpl *impl)
393 if (test->proto->n_params > MAX_PARAMS) {
394 OIL_ERROR ("function has too many parameters");
398 if (!test->inited || !test->tested_ref) {
399 oil_test_check_ref(test);
403 ret = oil_fault_check_try (oil_test_check_function, test);
405 OIL_ERROR ("illegal instruction in %s", test->impl->name);
406 test->profile_ave = 0;
407 test->profile_std = 0;
414 for(i=0;i<OIL_ARG_LAST;i++){
415 OilParameter *p = &test->params[i];
418 if (p->direction == 'i' || p->direction == 'd') {
419 x += check_array (p->test_data + p->test_header,
420 p->ref_data + p->test_header, p->type, p->pre_n, p->stride,
422 n += p->pre_n * p->post_n;
423 if (!check_guard (p->test_data, p->test_header, p->guard)) {
425 OIL_ERROR("function %s wrote before area for parameter %s",
426 test->impl->name, p->parameter_name);
428 if (!check_guard ((uint8_t *)p->test_data + p->size - p->test_footer,
429 p->test_footer, p->guard)) {
431 OIL_ERROR("function %s wrote after area for parameter %s",
432 test->impl->name, p->parameter_name);
434 if (!check_holes (p->test_data, p->type, p->pre_n, p->stride,
435 p->post_n, p->guard)) {
437 OIL_ERROR("function %s wrote in interstitial area for parameter %s",
438 test->impl->name, p->parameter_name);
443 OIL_DEBUG("sum of absolute differences %g for %d values", x, n);
444 test->sum_abs_diff = x;
447 if (x > test->tolerance * n || fail) {
448 OIL_ERROR ("function %s in class %s failed check (%g > %g) || (outside=%d)",
449 test->impl->name, test->klass->name, x, test->tolerance * n, fail);
468 oil_test_cleanup (OilTest *test)
470 OilParameter *params = test->params;
473 if(params[OIL_ARG_SRC1].type) {
474 if (!params[OIL_ARG_SSTR1].type) {
475 params[OIL_ARG_SSTR1].value = oil_type_sizeof (params[OIL_ARG_SRC1].type);
480 if(params[OIL_ARG_SRC2].type) {
481 if (!params[OIL_ARG_SSTR2].type) {
482 params[OIL_ARG_SSTR2].value = oil_type_sizeof (params[OIL_ARG_SRC2].type);
487 if(params[OIL_ARG_SRC3].type) {
488 if (!params[OIL_ARG_SSTR3].type) {
489 params[OIL_ARG_SSTR3].value = oil_type_sizeof (params[OIL_ARG_SRC3].type);
494 if(params[OIL_ARG_DEST1].type) {
495 if (!params[OIL_ARG_DSTR1].type) {
496 params[OIL_ARG_DSTR1].value = oil_type_sizeof (params[OIL_ARG_DEST1].type);
501 if(params[OIL_ARG_DEST2].type) {
502 if (!params[OIL_ARG_DSTR2].type) {
503 params[OIL_ARG_DSTR2].value = oil_type_sizeof (params[OIL_ARG_DEST2].type);
508 if(params[OIL_ARG_DEST3].type) {
509 if (!params[OIL_ARG_DSTR3].type) {
510 params[OIL_ARG_DSTR3].value = oil_type_sizeof (params[OIL_ARG_DEST3].type);
518 init_parameter (OilTest *test, OilParameter *p, OilParameter *ps)
520 if (!p->type) return;
522 p->pre_n = p->prestride_length;
523 if (p->prestride_var == 1) {
526 if (p->prestride_var == 2) {
531 p->stride = ps->value;
533 p->stride = oil_type_sizeof (p->type) * p->pre_n;
534 ps->value = p->stride;
537 p->post_n = p->poststride_length;
538 if (p->poststride_var == 1) {
539 p->post_n += test->n;
541 if (p->poststride_var == 2) {
542 p->post_n += test->m;
545 p->size = p->stride * p->post_n + p->test_header + p->test_footer;
546 p->guard = oil_rand_u8();
548 if (p->direction == 'i' || p->direction == 's') {
549 if (p->src_data) free (p->src_data);
551 OIL_DEBUG("allocating %d bytes for src_data for %s", p->size, p->parameter_name);
552 p->src_data = malloc (p->size);
553 memset (p->src_data, p->guard, p->size);
554 fill_array (p->src_data + p->test_header, p->type, p->pre_n, p->stride, p->post_n);
557 if (p->direction == 'i' || p->direction == 'd') {
558 if (p->ref_data) free (p->ref_data);
559 p->ref_data = malloc (p->size);
560 memset (p->ref_data, p->guard, p->size);
561 OIL_DEBUG("allocating %d bytes for ref_data and test_data for %s", p->size, p->parameter_name);
563 if (p->test_data) free (p->test_data);
564 p->test_data = malloc (p->size);
565 memset (p->test_data, p->guard, p->size);
570 oil_test_init_params (OilTest *test)
572 init_parameter (test, &test->params[OIL_ARG_DEST1],
573 &test->params[OIL_ARG_DSTR1]);
574 init_parameter (test, &test->params[OIL_ARG_DEST2],
575 &test->params[OIL_ARG_DSTR2]);
576 init_parameter (test, &test->params[OIL_ARG_DEST3],
577 &test->params[OIL_ARG_DSTR3]);
579 init_parameter (test, &test->params[OIL_ARG_SRC1],
580 &test->params[OIL_ARG_SSTR1]);
581 init_parameter (test, &test->params[OIL_ARG_SRC2],
582 &test->params[OIL_ARG_SSTR2]);
583 init_parameter (test, &test->params[OIL_ARG_SRC3],
584 &test->params[OIL_ARG_SSTR3]);
585 init_parameter (test, &test->params[OIL_ARG_SRC4],
586 &test->params[OIL_ARG_SSTR4]);
587 init_parameter (test, &test->params[OIL_ARG_SRC5],
588 &test->params[OIL_ARG_SSTR5]);
590 init_parameter (test, &test->params[OIL_ARG_INPLACE1],
591 &test->params[OIL_ARG_ISTR1]);
592 init_parameter (test, &test->params[OIL_ARG_INPLACE2],
593 &test->params[OIL_ARG_ISTR2]);
597 fill_array (void *data, OilType type, int pre_n, int stride, int post_n)
601 #define FILL(type,func) do {\
602 for(i=0;i<post_n;i++){ \
603 func (OIL_OFFSET(data, i*stride), pre_n); \
609 FILL(int8_t,oil_random_s8);
612 FILL(uint8_t,oil_random_u8);
615 FILL(int16_t,oil_random_s16);
618 FILL(uint16_t,oil_random_u16);
621 FILL(int32_t,oil_random_s32);
624 FILL(uint32_t,oil_random_u32);
627 FILL(int64_t,oil_random_s64);
630 FILL(uint64_t,oil_random_u64);
633 FILL(float,oil_random_f32);
636 FILL(double,oil_random_f64);
639 OIL_ERROR ("should not be reached (type == %d)", type);
646 check_array (void *data, void *ref, OilType type, int pre_n, int stride, int post_n)
650 int s2 = oil_type_sizeof (type);
654 OIL_ERROR ("check array pre_n=%d stride=%d post_n=%d",
655 pre_n, stride, post_n);
658 #define CHECK(type) do {\
659 for(i=0;i<post_n;i++){ \
660 for(j=0;j<pre_n;j++){ \
661 x += fabs((double)OIL_GET(data, i*stride + j*s2, type) - \
662 (double)OIL_GET(ref, i*stride + j*s2, type)); \
699 OIL_ERROR ("should not be reached (type == %d)", type);
707 check_holes (void *data, OilType type, int pre_n, int stride, int post_n,
714 chunk_size = pre_n * oil_type_sizeof (type);
715 hole_size = stride - chunk_size;
716 if (hole_size == 0) {
720 for(i=0;i<post_n;i++){
721 if (!check_guard (OIL_OFFSET(data, stride * i + chunk_size),
734 oil_test_get_source_data (OilTest *test, OilArgType arg_type)
738 ptr = test->params[arg_type].src_data;
739 ptr += test->params[arg_type].test_header;
748 oil_test_get_arg_pre_n (OilTest *test, OilArgType arg_type)
750 return test->params[arg_type].pre_n;
757 oil_test_get_arg_post_n (OilTest *test, OilArgType arg_type)
759 return test->params[arg_type].post_n;
766 oil_test_get_arg_stride (OilTest *test, OilArgType arg_type)
768 return test->params[arg_type].stride;
775 oil_test_get_value (OilTest *test, OilArgType arg_type)
777 return test->params[arg_type].value;