sl@0: /* sl@0: * LIBOIL - Library of Optimized Inner Loops sl@0: * Copyright (c) 2003,2004 David A. Schleef sl@0: * All rights reserved. sl@0: * sl@0: * Redistribution and use in source and binary forms, with or without sl@0: * modification, are permitted provided that the following conditions sl@0: * are met: sl@0: * 1. Redistributions of source code must retain the above copyright sl@0: * notice, this list of conditions and the following disclaimer. sl@0: * 2. Redistributions in binary form must reproduce the above copyright sl@0: * notice, this list of conditions and the following disclaimer in the sl@0: * documentation and/or other materials provided with the distribution. sl@0: * sl@0: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR sl@0: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED sl@0: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE sl@0: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, sl@0: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES sl@0: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR sl@0: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) sl@0: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, sl@0: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING sl@0: * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE sl@0: * POSSIBILITY OF SUCH DAMAGE. sl@0: */ sl@0: //Portions Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. sl@0: sl@0: #ifdef HAVE_CONFIG_H sl@0: #include "config.h" sl@0: #endif sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: sl@0: /** sl@0: * SECTION:liboilclass-unstable sl@0: * @title:OilFunctionClass sl@0: * @short_description: Functions for manipulating function classes sl@0: * sl@0: * sl@0: * Functions operate on arrays of data. The arrays can be either source sl@0: * arrays (input only), destination arrays (output only), or in-place sl@0: * arrays (both input and output). sl@0: * sl@0: * sl@0: * sl@0: * The interpretation of a parameter can usually be determined from its sl@0: * name. Parameters for arrays are of the form d1_1xn, where the first sl@0: * character represents the direction (source, destination, or in-place), sl@0: * the second represents the index for that particular direction, and sl@0: * the characters after the underscore indicate the size of the array. sl@0: * In this case, "1xn" represents an array that is 1 by N. Note that sl@0: * the index and the size can both be omitted, giving a default of 1 sl@0: * for the index and 1xn for the size. sl@0: * sl@0: * sl@0: * sl@0: * Parameters that represent strides are of the form "d1s". The sl@0: * interpretation is similar to above, except that the s indicates sl@0: * a stride parameter. sl@0: * sl@0: * sl@0: * sl@0: * The exceptions to the above rule are "dest", "src", "dstr", "sstr", etc. sl@0: * These are aliases for "d1", "s1", "d1s", and "s1s", respectively. This sl@0: * form is deprecated and will be removed in the 0.4 series. sl@0: * sl@0: * sl@0: * sl@0: * Two special parameters are "n" and "m", which determine the size of sl@0: * the arrays in other parameters. sl@0: * sl@0: * sl@0: * sl@0: * Data arrays are laid out such that rows are separated by the number sl@0: * of bytes given by the corresponding stride. Elements in each row sl@0: * are contiguous. If there is no stride parameter corresponding to an sl@0: * array, the rows of the array are contiguous. sl@0: * sl@0: */ sl@0: sl@0: /** sl@0: * SECTION:liboilimpl-unstable sl@0: * @title:OilFunctionImpl sl@0: * @short_description: Functions for manipulating function implementations. sl@0: */ sl@0: sl@0: sl@0: #ifndef __SYMBIAN32__ sl@0: extern OilFunctionClass *_oil_function_class_array[]; sl@0: extern OilFunctionImpl *_oil_function_impl_array[]; sl@0: #else sl@0: extern OilFunctionClass** __oil_function_class_array(void); sl@0: extern OilFunctionImpl** __oil_function_impl_array(void); sl@0: #define _oil_function_class_array ((OilFunctionClass **)(__oil_function_class_array())) sl@0: #define _oil_function_impl_array ((OilFunctionImpl **)(__oil_function_impl_array())) sl@0: extern void init(void); sl@0: extern void init_impl(void); sl@0: #endif sl@0: sl@0: sl@0: static int _oil_n_function_impls; sl@0: static int _oil_n_function_classes; sl@0: sl@0: static void oil_init_pointers (void); sl@0: static void oil_init_structs (void); sl@0: sl@0: static char * xstrdup (const char *s); sl@0: sl@0: void _oil_cpu_init (void); sl@0: sl@0: /** sl@0: * SECTION:liboilinit sl@0: * @title: Intialization sl@0: * @short_description: Initialization functions sl@0: */ sl@0: /** sl@0: * SECTION:liboilinit-unstable sl@0: * @title: Intialization sl@0: * @short_description: Initialization functions sl@0: */ sl@0: /** sl@0: * oil_init: sl@0: * sl@0: * Initialize liboil. This function must be called before any sl@0: * other liboil function is used. oil_init() may be called multiple sl@0: * times. sl@0: * sl@0: * Since: 0.3.0 sl@0: */ sl@0: static int _oil_inited = 0; sl@0: sl@0: #ifdef __SYMBIAN32__ sl@0: EXPORT_C sl@0: #endif sl@0: void sl@0: oil_init (void) sl@0: { sl@0: sl@0: if (_oil_inited) return; sl@0: _oil_inited = 1; sl@0: sl@0: #ifdef __SYMBIAN32__ sl@0: init(); sl@0: init_impl(); sl@0: #endif sl@0: sl@0: srand(time(NULL)); sl@0: sl@0: _oil_debug_init (); sl@0: _oil_cpu_init (); sl@0: oil_init_pointers (); sl@0: oil_init_structs (); sl@0: sl@0: oil_optimize_all (); sl@0: sl@0: OIL_INFO ("oil_init() finished"); sl@0: } sl@0: sl@0: /** sl@0: * oil_init_no_optimize: sl@0: * sl@0: * Initialize liboil similar to oil_init(), but do not run the sl@0: * profiling stage. This function is mainly useful for internal sl@0: * programs. sl@0: */ sl@0: #ifdef __SYMBIAN32__ sl@0: EXPORT_C sl@0: #endif sl@0: void sl@0: oil_init_no_optimize (void) sl@0: { sl@0: if (_oil_inited) return; sl@0: _oil_inited = 1; sl@0: sl@0: srand(time(NULL)); sl@0: sl@0: _oil_debug_init (); sl@0: _oil_cpu_init (); sl@0: oil_init_pointers (); sl@0: oil_init_structs (); sl@0: } sl@0: sl@0: /** sl@0: * oil_optimize_all: sl@0: * sl@0: * Optimize all function classes. sl@0: */ sl@0: #ifdef __SYMBIAN32__ sl@0: EXPORT_C sl@0: #endif sl@0: void sl@0: oil_optimize_all (void) sl@0: { sl@0: OilFunctionClass *klass; sl@0: int i; sl@0: sl@0: oil_fault_check_enable (); sl@0: for (i = 0; i < _oil_n_function_classes; i++) { sl@0: klass = oil_class_get_by_index (i); sl@0: sl@0: oil_class_optimize (klass); sl@0: } sl@0: OIL_INFO("%d classes, %d implementations, %d enabled", sl@0: _oil_n_function_classes, _oil_n_function_impls, 0); sl@0: oil_fault_check_disable (); sl@0: } sl@0: sl@0: /** sl@0: * oil_optimize: sl@0: * @class_name: a string sl@0: * sl@0: * Optimize the function class that has the name specified by @class_name. sl@0: */ sl@0: #ifdef __SYMBIAN32__ sl@0: EXPORT_C sl@0: #endif sl@0: void sl@0: oil_optimize (const char *class_name) sl@0: { sl@0: OilFunctionClass *klass; sl@0: sl@0: klass = oil_class_get (class_name); sl@0: if (klass == NULL) { sl@0: OIL_ERROR ("could not find class %s", class_name); sl@0: return; sl@0: } sl@0: sl@0: oil_class_optimize (klass); sl@0: } sl@0: sl@0: /** sl@0: * oil_class_get_n_classes: sl@0: * sl@0: * Returns the number of function classes. sl@0: * sl@0: * Returns: the number of function classes sl@0: */ sl@0: #ifdef __SYMBIAN32__ sl@0: EXPORT_C sl@0: #endif sl@0: int sl@0: oil_class_get_n_classes (void) sl@0: { sl@0: return _oil_n_function_classes; sl@0: } sl@0: sl@0: /** sl@0: * oil_class_get_by_index: sl@0: * @i: index sl@0: * sl@0: * Returns a pointer to the function class with index @i. sl@0: * sl@0: * Returns: an @OilFunctionClass sl@0: */ sl@0: sl@0: #ifdef __SYMBIAN32__ sl@0: EXPORT_C sl@0: #endif sl@0: OilFunctionClass * sl@0: oil_class_get_by_index (int i) sl@0: { sl@0: if (i<0 || i>=_oil_n_function_classes) return NULL; sl@0: sl@0: return _oil_function_class_array[i]; sl@0: } sl@0: sl@0: /** sl@0: * oil_impl_is_runnable: sl@0: * @impl: an @OilFunctionImpl sl@0: * sl@0: * Determines whether the function implementation given by @impl sl@0: * can be executed by the current CPU. sl@0: * sl@0: * Returns: 1 if the implementation can be executed, otherwise 0 sl@0: */ sl@0: #ifdef __SYMBIAN32__ sl@0: EXPORT_C sl@0: #endif sl@0: int sl@0: oil_impl_is_runnable (OilFunctionImpl *impl) sl@0: { sl@0: unsigned int oil_cpu_flags = oil_cpu_get_flags(); sl@0: sl@0: if ((impl->flags & OIL_CPU_FLAG_MASK) & (~oil_cpu_flags)) sl@0: return 0; sl@0: return 1; sl@0: } sl@0: sl@0: //#ifdef __SYMBIAN32__ sl@0: //EXPORT_C unsigned long _oil_cpu_flags() sl@0: //{ sl@0: //return &oil_cpu_flags; sl@0: //} sl@0: //#endif sl@0: sl@0: /** sl@0: * oil_impl_is_usable: sl@0: * @impl: an @OilFunctionImpl sl@0: * sl@0: * Determines whether the function implementation given by @impl sl@0: * is useful, that is, it can be executed on the current CPU and sl@0: * passes tests. sl@0: * sl@0: * Returns: 1 if the implementation can be used, otherwise 0 sl@0: */ sl@0: #ifdef __SYMBIAN32__ sl@0: EXPORT_C sl@0: #endif sl@0: int sl@0: oil_impl_is_usable (OilFunctionImpl *impl) sl@0: { sl@0: unsigned int oil_cpu_flags = oil_cpu_get_flags(); sl@0: sl@0: if ((impl->flags & OIL_CPU_FLAG_MASK) & (~oil_cpu_flags)) sl@0: return 0; sl@0: if (impl->flags & OIL_IMPL_FLAG_DISABLED) sl@0: return 0; sl@0: return 1; sl@0: } sl@0: sl@0: /** sl@0: * oil_impl_get_by_index: sl@0: * @i: index sl@0: * sl@0: * Returns a pointer to the function implementation with index @i. sl@0: * sl@0: * Returns: a pointer to a function implementation structure sl@0: */ sl@0: #ifdef __SYMBIAN32__ sl@0: EXPORT_C sl@0: #endif sl@0: OilFunctionImpl * sl@0: oil_impl_get_by_index (int i) sl@0: { sl@0: if (i<0 || i>=_oil_n_function_impls) return NULL; sl@0: sl@0: return _oil_function_impl_array[i]; sl@0: } sl@0: sl@0: /** sl@0: * oil_class_get: sl@0: * @class_name: the name of the function class sl@0: * sl@0: * Returns a pointer to the function class that has the given class sl@0: * name. If no such class is found, NULL is returned. sl@0: * sl@0: * Returns: a pointer to a function class sl@0: */ sl@0: #ifdef __SYMBIAN32__ sl@0: EXPORT_C sl@0: #endif sl@0: OilFunctionClass * sl@0: oil_class_get (const char *class_name) sl@0: { sl@0: OilFunctionClass *klass; sl@0: int i; sl@0: sl@0: for (i = 0; i < _oil_n_function_classes; i++) { sl@0: klass = oil_class_get_by_index (i); sl@0: sl@0: if (strcmp (klass->name, class_name) == 0) sl@0: return klass; sl@0: } sl@0: return NULL; sl@0: } sl@0: sl@0: /** sl@0: * oil_class_choose_by_name: sl@0: * @klass: a function class sl@0: * @name: the name of an implementation sl@0: * sl@0: * Sets the chosen implementation for the given function class to sl@0: * the implementation with the given name. If no implementation sl@0: * having the given name is found, the chosen implementation is sl@0: * not changed. sl@0: */ sl@0: #ifdef __SYMBIAN32__ sl@0: EXPORT_C sl@0: #endif sl@0: void sl@0: oil_class_choose_by_name (OilFunctionClass * klass, const char *name) sl@0: { sl@0: OilFunctionImpl *impl; sl@0: sl@0: for(impl = klass->first_impl; impl; impl = impl->next) { sl@0: if (impl->name && strcmp (impl->name, name) == 0) { sl@0: klass->chosen_impl = impl; sl@0: klass->func = impl->func; sl@0: return; sl@0: } sl@0: } sl@0: } sl@0: sl@0: /** sl@0: * oil_class_optimize: sl@0: * @klass: a function class sl@0: * sl@0: * Tests and profiles each implementation for the given function sl@0: * class. Testing compares the output of running each implementation sl@0: * on random input against the reference implementation for the sl@0: * same input. sl@0: */ sl@0: #ifdef __SYMBIAN32__ sl@0: EXPORT_C sl@0: #endif sl@0: void sl@0: oil_class_optimize (OilFunctionClass * klass) sl@0: { sl@0: OilFunctionImpl *impl; sl@0: OilFunctionImpl *min_impl; sl@0: OilTest *test; sl@0: int ret; sl@0: sl@0: OIL_DEBUG ("optimizing class %s", klass->name); sl@0: sl@0: if (klass->reference_impl == NULL) { sl@0: OIL_ERROR ("class %s has no reference implmentation", klass->name); sl@0: return; sl@0: } sl@0: if (klass->first_impl == NULL) { sl@0: OIL_ERROR ("class %s has no implmentations", klass->name); sl@0: return; sl@0: } sl@0: sl@0: test = oil_test_new (klass); sl@0: if (test == NULL) { sl@0: OIL_ERROR ("failed to test function class %s", klass->name); sl@0: return; sl@0: } sl@0: sl@0: min_impl = NULL; sl@0: for (impl = klass->first_impl; impl; impl = impl->next) { sl@0: OIL_LOG ("testing impl %s", impl->name); sl@0: if (!oil_impl_is_runnable (impl)) sl@0: continue; sl@0: sl@0: ret = oil_test_check_impl (test, impl); sl@0: if (ret) { sl@0: impl->profile_ave = test->profile_ave; sl@0: impl->profile_std = test->profile_std; sl@0: OIL_LOG ("impl %s ave=%g std=%g", impl->name, impl->profile_ave, sl@0: impl->profile_std); sl@0: if (min_impl == NULL) { sl@0: min_impl = impl; sl@0: } else { sl@0: if (impl->profile_ave < min_impl->profile_ave) { sl@0: min_impl = impl; sl@0: } sl@0: } sl@0: } else { sl@0: OIL_WARNING("disabling implementation %s", impl->name); sl@0: impl->profile_ave = test->profile_ave; sl@0: impl->profile_std = test->profile_std; sl@0: impl->flags |= OIL_IMPL_FLAG_DISABLED; sl@0: } sl@0: } sl@0: if (min_impl == NULL) { sl@0: OIL_ERROR ("failed to find optimal implementation for class %s", sl@0: klass->name); sl@0: return; sl@0: } sl@0: sl@0: OIL_DEBUG("choosing implementation %s", min_impl->name); sl@0: klass->chosen_impl = min_impl; sl@0: klass->func = min_impl->func; sl@0: sl@0: oil_test_free (test); sl@0: } sl@0: sl@0: static void sl@0: oil_init_pointers (void) sl@0: { sl@0: int i; sl@0: sl@0: for(i=0;_oil_function_class_array[i];i++) { sl@0: _oil_n_function_classes++; sl@0: } sl@0: sl@0: for(i=0;_oil_function_impl_array[i];i++) { sl@0: _oil_n_function_impls++; sl@0: } sl@0: sl@0: } sl@0: sl@0: static void sl@0: oil_init_structs (void) sl@0: { sl@0: int i; sl@0: OilFunctionImpl *impl; sl@0: sl@0: for (i = 0; i < _oil_n_function_impls; i++) { sl@0: impl = oil_impl_get_by_index (i); sl@0: OIL_LOG ("registering impl %p (%s)", impl, sl@0: (impl->name != NULL) ? impl->name : "NULL"); sl@0: if (impl->klass == NULL) { sl@0: OIL_ERROR ("impl->klass is NULL for impl %p (%s)", impl, sl@0: (impl->name != NULL) ? impl->name : "NULL"); sl@0: continue; sl@0: } sl@0: impl->next = impl->klass->first_impl; sl@0: impl->klass->first_impl = impl; sl@0: if (impl->flags & OIL_IMPL_FLAG_REF) { sl@0: impl->klass->reference_impl = impl; sl@0: impl->klass->chosen_impl = impl; sl@0: impl->klass->func = impl->func; sl@0: } sl@0: } sl@0: } sl@0: sl@0: /** sl@0: * oil_class_register_impl_by_name: sl@0: * @klass_name: the name of the class sl@0: * @impl: an implementation sl@0: * sl@0: * Adds @impl to the list of implementations associated with sl@0: * the function class given by @klass_name. sl@0: */ sl@0: #ifdef __SYMBIAN32__ sl@0: EXPORT_C sl@0: #endif sl@0: void sl@0: oil_class_register_impl_by_name (const char *klass_name, OilFunctionImpl *impl) sl@0: { sl@0: OilFunctionClass *klass; sl@0: sl@0: klass = oil_class_get (klass_name); sl@0: if (klass == NULL) return; sl@0: sl@0: oil_class_register_impl (klass, impl); sl@0: } sl@0: sl@0: /** sl@0: * oil_class_register_impl: sl@0: * @klass: the class sl@0: * @impl: an implementation sl@0: * sl@0: * Adds @impl to the list of implementations associated with sl@0: * the function class given by @klass. sl@0: */ sl@0: #ifdef __SYMBIAN32__ sl@0: EXPORT_C sl@0: #endif sl@0: void sl@0: oil_class_register_impl (OilFunctionClass *klass, OilFunctionImpl *impl) sl@0: { sl@0: impl->klass = klass; sl@0: impl->next = impl->klass->first_impl; sl@0: klass->first_impl = impl; sl@0: if (impl->flags & OIL_IMPL_FLAG_REF) { sl@0: impl->klass->reference_impl = impl; sl@0: impl->klass->chosen_impl = impl; sl@0: impl->klass->func = impl->func; sl@0: } sl@0: } sl@0: sl@0: /** sl@0: * oil_class_register_impl_full: sl@0: * @klass: the class sl@0: * @func: the function sl@0: * @name: name of the function sl@0: * @flags: CPU flags sl@0: * sl@0: * Adds @func to the list of implementations associated with sl@0: * the function class given by @klass. sl@0: */ sl@0: #ifdef __SYMBIAN32__ sl@0: EXPORT_C sl@0: #endif sl@0: void sl@0: oil_class_register_impl_full (OilFunctionClass *klass, sl@0: void (*func)(void), const char *name, unsigned int flags) sl@0: { sl@0: OilFunctionImpl *impl; sl@0: sl@0: impl = malloc(sizeof(OilFunctionImpl)); sl@0: memset (impl, 0, sizeof(OilFunctionImpl)); sl@0: sl@0: impl->func = (void*)func; sl@0: impl->flags = flags; sl@0: impl->name = xstrdup(name); sl@0: sl@0: oil_class_register_impl(klass,impl); sl@0: } sl@0: sl@0: static char * sl@0: xstrdup (const char *s) sl@0: { sl@0: int n = strlen(s); sl@0: char *t; sl@0: sl@0: n = strlen(s); sl@0: t = malloc(n + 1); sl@0: memcpy (t, s, n); sl@0: t[n] = 0; sl@0: sl@0: return t; sl@0: } sl@0: