|
1 /* |
|
2 * LIBOIL - Library of Optimized Inner Loops |
|
3 * Copyright (c) 2003,2004 David A. Schleef <ds@schleef.org> |
|
4 * All rights reserved. |
|
5 * |
|
6 * Redistribution and use in source and binary forms, with or without |
|
7 * modification, are permitted provided that the following conditions |
|
8 * are met: |
|
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. |
|
14 * |
|
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. |
|
26 */ |
|
27 //Portions Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. |
|
28 |
|
29 #ifdef HAVE_CONFIG_H |
|
30 #include "config.h" |
|
31 #endif |
|
32 #include <liboil/liboildebug.h> |
|
33 #include <liboil/liboilcpu.h> |
|
34 #include <liboil/liboilfault.h> |
|
35 #include <liboil/liboiltest.h> |
|
36 |
|
37 #include <stdio.h> |
|
38 #include <string.h> |
|
39 #include <stdlib.h> |
|
40 #include <time.h> |
|
41 |
|
42 /** |
|
43 * SECTION:liboilclass-unstable |
|
44 * @title:OilFunctionClass |
|
45 * @short_description: Functions for manipulating function classes |
|
46 * |
|
47 * <para> |
|
48 * Functions operate on arrays of data. The arrays can be either source |
|
49 * arrays (input only), destination arrays (output only), or in-place |
|
50 * arrays (both input and output). |
|
51 * </para> |
|
52 * |
|
53 * <para> |
|
54 * The interpretation of a parameter can usually be determined from its |
|
55 * name. Parameters for arrays are of the form d1_1xn, where the first |
|
56 * character represents the direction (source, destination, or in-place), |
|
57 * the second represents the index for that particular direction, and |
|
58 * the characters after the underscore indicate the size of the array. |
|
59 * In this case, "1xn" represents an array that is 1 by N. Note that |
|
60 * the index and the size can both be omitted, giving a default of 1 |
|
61 * for the index and 1xn for the size. |
|
62 * </para> |
|
63 * |
|
64 * <para> |
|
65 * Parameters that represent strides are of the form "d1s". The |
|
66 * interpretation is similar to above, except that the s indicates |
|
67 * a stride parameter. |
|
68 * </para> |
|
69 * |
|
70 * <para> |
|
71 * The exceptions to the above rule are "dest", "src", "dstr", "sstr", etc. |
|
72 * These are aliases for "d1", "s1", "d1s", and "s1s", respectively. This |
|
73 * form is deprecated and will be removed in the 0.4 series. |
|
74 * </para> |
|
75 * |
|
76 * <para> |
|
77 * Two special parameters are "n" and "m", which determine the size of |
|
78 * the arrays in other parameters. |
|
79 * </para> |
|
80 * |
|
81 * <para> |
|
82 * Data arrays are laid out such that rows are separated by the number |
|
83 * of bytes given by the corresponding stride. Elements in each row |
|
84 * are contiguous. If there is no stride parameter corresponding to an |
|
85 * array, the rows of the array are contiguous. |
|
86 * </para> |
|
87 */ |
|
88 |
|
89 /** |
|
90 * SECTION:liboilimpl-unstable |
|
91 * @title:OilFunctionImpl |
|
92 * @short_description: Functions for manipulating function implementations. |
|
93 */ |
|
94 |
|
95 |
|
96 #ifndef __SYMBIAN32__ |
|
97 extern OilFunctionClass *_oil_function_class_array[]; |
|
98 extern OilFunctionImpl *_oil_function_impl_array[]; |
|
99 #else |
|
100 extern OilFunctionClass** __oil_function_class_array(void); |
|
101 extern OilFunctionImpl** __oil_function_impl_array(void); |
|
102 #define _oil_function_class_array ((OilFunctionClass **)(__oil_function_class_array())) |
|
103 #define _oil_function_impl_array ((OilFunctionImpl **)(__oil_function_impl_array())) |
|
104 extern void init(void); |
|
105 extern void init_impl(void); |
|
106 #endif |
|
107 |
|
108 |
|
109 static int _oil_n_function_impls; |
|
110 static int _oil_n_function_classes; |
|
111 |
|
112 static void oil_init_pointers (void); |
|
113 static void oil_init_structs (void); |
|
114 |
|
115 static char * xstrdup (const char *s); |
|
116 |
|
117 void _oil_cpu_init (void); |
|
118 |
|
119 /** |
|
120 * SECTION:liboilinit |
|
121 * @title: Intialization |
|
122 * @short_description: Initialization functions |
|
123 */ |
|
124 /** |
|
125 * SECTION:liboilinit-unstable |
|
126 * @title: Intialization |
|
127 * @short_description: Initialization functions |
|
128 */ |
|
129 /** |
|
130 * oil_init: |
|
131 * |
|
132 * Initialize liboil. This function must be called before any |
|
133 * other liboil function is used. oil_init() may be called multiple |
|
134 * times. |
|
135 * |
|
136 * Since: 0.3.0 |
|
137 */ |
|
138 static int _oil_inited = 0; |
|
139 |
|
140 #ifdef __SYMBIAN32__ |
|
141 EXPORT_C |
|
142 #endif |
|
143 void |
|
144 oil_init (void) |
|
145 { |
|
146 |
|
147 if (_oil_inited) return; |
|
148 _oil_inited = 1; |
|
149 |
|
150 #ifdef __SYMBIAN32__ |
|
151 init(); |
|
152 init_impl(); |
|
153 #endif |
|
154 |
|
155 srand(time(NULL)); |
|
156 |
|
157 _oil_debug_init (); |
|
158 _oil_cpu_init (); |
|
159 oil_init_pointers (); |
|
160 oil_init_structs (); |
|
161 |
|
162 oil_optimize_all (); |
|
163 |
|
164 OIL_INFO ("oil_init() finished"); |
|
165 } |
|
166 |
|
167 /** |
|
168 * oil_init_no_optimize: |
|
169 * |
|
170 * Initialize liboil similar to oil_init(), but do not run the |
|
171 * profiling stage. This function is mainly useful for internal |
|
172 * programs. |
|
173 */ |
|
174 #ifdef __SYMBIAN32__ |
|
175 EXPORT_C |
|
176 #endif |
|
177 void |
|
178 oil_init_no_optimize (void) |
|
179 { |
|
180 if (_oil_inited) return; |
|
181 _oil_inited = 1; |
|
182 |
|
183 srand(time(NULL)); |
|
184 |
|
185 _oil_debug_init (); |
|
186 _oil_cpu_init (); |
|
187 oil_init_pointers (); |
|
188 oil_init_structs (); |
|
189 } |
|
190 |
|
191 /** |
|
192 * oil_optimize_all: |
|
193 * |
|
194 * Optimize all function classes. |
|
195 */ |
|
196 #ifdef __SYMBIAN32__ |
|
197 EXPORT_C |
|
198 #endif |
|
199 void |
|
200 oil_optimize_all (void) |
|
201 { |
|
202 OilFunctionClass *klass; |
|
203 int i; |
|
204 |
|
205 oil_fault_check_enable (); |
|
206 for (i = 0; i < _oil_n_function_classes; i++) { |
|
207 klass = oil_class_get_by_index (i); |
|
208 |
|
209 oil_class_optimize (klass); |
|
210 } |
|
211 OIL_INFO("%d classes, %d implementations, %d enabled", |
|
212 _oil_n_function_classes, _oil_n_function_impls, 0); |
|
213 oil_fault_check_disable (); |
|
214 } |
|
215 |
|
216 /** |
|
217 * oil_optimize: |
|
218 * @class_name: a string |
|
219 * |
|
220 * Optimize the function class that has the name specified by @class_name. |
|
221 */ |
|
222 #ifdef __SYMBIAN32__ |
|
223 EXPORT_C |
|
224 #endif |
|
225 void |
|
226 oil_optimize (const char *class_name) |
|
227 { |
|
228 OilFunctionClass *klass; |
|
229 |
|
230 klass = oil_class_get (class_name); |
|
231 if (klass == NULL) { |
|
232 OIL_ERROR ("could not find class %s", class_name); |
|
233 return; |
|
234 } |
|
235 |
|
236 oil_class_optimize (klass); |
|
237 } |
|
238 |
|
239 /** |
|
240 * oil_class_get_n_classes: |
|
241 * |
|
242 * Returns the number of function classes. |
|
243 * |
|
244 * Returns: the number of function classes |
|
245 */ |
|
246 #ifdef __SYMBIAN32__ |
|
247 EXPORT_C |
|
248 #endif |
|
249 int |
|
250 oil_class_get_n_classes (void) |
|
251 { |
|
252 return _oil_n_function_classes; |
|
253 } |
|
254 |
|
255 /** |
|
256 * oil_class_get_by_index: |
|
257 * @i: index |
|
258 * |
|
259 * Returns a pointer to the function class with index @i. |
|
260 * |
|
261 * Returns: an @OilFunctionClass |
|
262 */ |
|
263 |
|
264 #ifdef __SYMBIAN32__ |
|
265 EXPORT_C |
|
266 #endif |
|
267 OilFunctionClass * |
|
268 oil_class_get_by_index (int i) |
|
269 { |
|
270 if (i<0 || i>=_oil_n_function_classes) return NULL; |
|
271 |
|
272 return _oil_function_class_array[i]; |
|
273 } |
|
274 |
|
275 /** |
|
276 * oil_impl_is_runnable: |
|
277 * @impl: an @OilFunctionImpl |
|
278 * |
|
279 * Determines whether the function implementation given by @impl |
|
280 * can be executed by the current CPU. |
|
281 * |
|
282 * Returns: 1 if the implementation can be executed, otherwise 0 |
|
283 */ |
|
284 #ifdef __SYMBIAN32__ |
|
285 EXPORT_C |
|
286 #endif |
|
287 int |
|
288 oil_impl_is_runnable (OilFunctionImpl *impl) |
|
289 { |
|
290 unsigned int oil_cpu_flags = oil_cpu_get_flags(); |
|
291 |
|
292 if ((impl->flags & OIL_CPU_FLAG_MASK) & (~oil_cpu_flags)) |
|
293 return 0; |
|
294 return 1; |
|
295 } |
|
296 |
|
297 //#ifdef __SYMBIAN32__ |
|
298 //EXPORT_C unsigned long _oil_cpu_flags() |
|
299 //{ |
|
300 //return &oil_cpu_flags; |
|
301 //} |
|
302 //#endif |
|
303 |
|
304 /** |
|
305 * oil_impl_is_usable: |
|
306 * @impl: an @OilFunctionImpl |
|
307 * |
|
308 * Determines whether the function implementation given by @impl |
|
309 * is useful, that is, it can be executed on the current CPU and |
|
310 * passes tests. |
|
311 * |
|
312 * Returns: 1 if the implementation can be used, otherwise 0 |
|
313 */ |
|
314 #ifdef __SYMBIAN32__ |
|
315 EXPORT_C |
|
316 #endif |
|
317 int |
|
318 oil_impl_is_usable (OilFunctionImpl *impl) |
|
319 { |
|
320 unsigned int oil_cpu_flags = oil_cpu_get_flags(); |
|
321 |
|
322 if ((impl->flags & OIL_CPU_FLAG_MASK) & (~oil_cpu_flags)) |
|
323 return 0; |
|
324 if (impl->flags & OIL_IMPL_FLAG_DISABLED) |
|
325 return 0; |
|
326 return 1; |
|
327 } |
|
328 |
|
329 /** |
|
330 * oil_impl_get_by_index: |
|
331 * @i: index |
|
332 * |
|
333 * Returns a pointer to the function implementation with index @i. |
|
334 * |
|
335 * Returns: a pointer to a function implementation structure |
|
336 */ |
|
337 #ifdef __SYMBIAN32__ |
|
338 EXPORT_C |
|
339 #endif |
|
340 OilFunctionImpl * |
|
341 oil_impl_get_by_index (int i) |
|
342 { |
|
343 if (i<0 || i>=_oil_n_function_impls) return NULL; |
|
344 |
|
345 return _oil_function_impl_array[i]; |
|
346 } |
|
347 |
|
348 /** |
|
349 * oil_class_get: |
|
350 * @class_name: the name of the function class |
|
351 * |
|
352 * Returns a pointer to the function class that has the given class |
|
353 * name. If no such class is found, NULL is returned. |
|
354 * |
|
355 * Returns: a pointer to a function class |
|
356 */ |
|
357 #ifdef __SYMBIAN32__ |
|
358 EXPORT_C |
|
359 #endif |
|
360 OilFunctionClass * |
|
361 oil_class_get (const char *class_name) |
|
362 { |
|
363 OilFunctionClass *klass; |
|
364 int i; |
|
365 |
|
366 for (i = 0; i < _oil_n_function_classes; i++) { |
|
367 klass = oil_class_get_by_index (i); |
|
368 |
|
369 if (strcmp (klass->name, class_name) == 0) |
|
370 return klass; |
|
371 } |
|
372 return NULL; |
|
373 } |
|
374 |
|
375 /** |
|
376 * oil_class_choose_by_name: |
|
377 * @klass: a function class |
|
378 * @name: the name of an implementation |
|
379 * |
|
380 * Sets the chosen implementation for the given function class to |
|
381 * the implementation with the given name. If no implementation |
|
382 * having the given name is found, the chosen implementation is |
|
383 * not changed. |
|
384 */ |
|
385 #ifdef __SYMBIAN32__ |
|
386 EXPORT_C |
|
387 #endif |
|
388 void |
|
389 oil_class_choose_by_name (OilFunctionClass * klass, const char *name) |
|
390 { |
|
391 OilFunctionImpl *impl; |
|
392 |
|
393 for(impl = klass->first_impl; impl; impl = impl->next) { |
|
394 if (impl->name && strcmp (impl->name, name) == 0) { |
|
395 klass->chosen_impl = impl; |
|
396 klass->func = impl->func; |
|
397 return; |
|
398 } |
|
399 } |
|
400 } |
|
401 |
|
402 /** |
|
403 * oil_class_optimize: |
|
404 * @klass: a function class |
|
405 * |
|
406 * Tests and profiles each implementation for the given function |
|
407 * class. Testing compares the output of running each implementation |
|
408 * on random input against the reference implementation for the |
|
409 * same input. |
|
410 */ |
|
411 #ifdef __SYMBIAN32__ |
|
412 EXPORT_C |
|
413 #endif |
|
414 void |
|
415 oil_class_optimize (OilFunctionClass * klass) |
|
416 { |
|
417 OilFunctionImpl *impl; |
|
418 OilFunctionImpl *min_impl; |
|
419 OilTest *test; |
|
420 int ret; |
|
421 |
|
422 OIL_DEBUG ("optimizing class %s", klass->name); |
|
423 |
|
424 if (klass->reference_impl == NULL) { |
|
425 OIL_ERROR ("class %s has no reference implmentation", klass->name); |
|
426 return; |
|
427 } |
|
428 if (klass->first_impl == NULL) { |
|
429 OIL_ERROR ("class %s has no implmentations", klass->name); |
|
430 return; |
|
431 } |
|
432 |
|
433 test = oil_test_new (klass); |
|
434 if (test == NULL) { |
|
435 OIL_ERROR ("failed to test function class %s", klass->name); |
|
436 return; |
|
437 } |
|
438 |
|
439 min_impl = NULL; |
|
440 for (impl = klass->first_impl; impl; impl = impl->next) { |
|
441 OIL_LOG ("testing impl %s", impl->name); |
|
442 if (!oil_impl_is_runnable (impl)) |
|
443 continue; |
|
444 |
|
445 ret = oil_test_check_impl (test, impl); |
|
446 if (ret) { |
|
447 impl->profile_ave = test->profile_ave; |
|
448 impl->profile_std = test->profile_std; |
|
449 OIL_LOG ("impl %s ave=%g std=%g", impl->name, impl->profile_ave, |
|
450 impl->profile_std); |
|
451 if (min_impl == NULL) { |
|
452 min_impl = impl; |
|
453 } else { |
|
454 if (impl->profile_ave < min_impl->profile_ave) { |
|
455 min_impl = impl; |
|
456 } |
|
457 } |
|
458 } else { |
|
459 OIL_WARNING("disabling implementation %s", impl->name); |
|
460 impl->profile_ave = test->profile_ave; |
|
461 impl->profile_std = test->profile_std; |
|
462 impl->flags |= OIL_IMPL_FLAG_DISABLED; |
|
463 } |
|
464 } |
|
465 if (min_impl == NULL) { |
|
466 OIL_ERROR ("failed to find optimal implementation for class %s", |
|
467 klass->name); |
|
468 return; |
|
469 } |
|
470 |
|
471 OIL_DEBUG("choosing implementation %s", min_impl->name); |
|
472 klass->chosen_impl = min_impl; |
|
473 klass->func = min_impl->func; |
|
474 |
|
475 oil_test_free (test); |
|
476 } |
|
477 |
|
478 static void |
|
479 oil_init_pointers (void) |
|
480 { |
|
481 int i; |
|
482 |
|
483 for(i=0;_oil_function_class_array[i];i++) { |
|
484 _oil_n_function_classes++; |
|
485 } |
|
486 |
|
487 for(i=0;_oil_function_impl_array[i];i++) { |
|
488 _oil_n_function_impls++; |
|
489 } |
|
490 |
|
491 } |
|
492 |
|
493 static void |
|
494 oil_init_structs (void) |
|
495 { |
|
496 int i; |
|
497 OilFunctionImpl *impl; |
|
498 |
|
499 for (i = 0; i < _oil_n_function_impls; i++) { |
|
500 impl = oil_impl_get_by_index (i); |
|
501 OIL_LOG ("registering impl %p (%s)", impl, |
|
502 (impl->name != NULL) ? impl->name : "NULL"); |
|
503 if (impl->klass == NULL) { |
|
504 OIL_ERROR ("impl->klass is NULL for impl %p (%s)", impl, |
|
505 (impl->name != NULL) ? impl->name : "NULL"); |
|
506 continue; |
|
507 } |
|
508 impl->next = impl->klass->first_impl; |
|
509 impl->klass->first_impl = impl; |
|
510 if (impl->flags & OIL_IMPL_FLAG_REF) { |
|
511 impl->klass->reference_impl = impl; |
|
512 impl->klass->chosen_impl = impl; |
|
513 impl->klass->func = impl->func; |
|
514 } |
|
515 } |
|
516 } |
|
517 |
|
518 /** |
|
519 * oil_class_register_impl_by_name: |
|
520 * @klass_name: the name of the class |
|
521 * @impl: an implementation |
|
522 * |
|
523 * Adds @impl to the list of implementations associated with |
|
524 * the function class given by @klass_name. |
|
525 */ |
|
526 #ifdef __SYMBIAN32__ |
|
527 EXPORT_C |
|
528 #endif |
|
529 void |
|
530 oil_class_register_impl_by_name (const char *klass_name, OilFunctionImpl *impl) |
|
531 { |
|
532 OilFunctionClass *klass; |
|
533 |
|
534 klass = oil_class_get (klass_name); |
|
535 if (klass == NULL) return; |
|
536 |
|
537 oil_class_register_impl (klass, impl); |
|
538 } |
|
539 |
|
540 /** |
|
541 * oil_class_register_impl: |
|
542 * @klass: the class |
|
543 * @impl: an implementation |
|
544 * |
|
545 * Adds @impl to the list of implementations associated with |
|
546 * the function class given by @klass. |
|
547 */ |
|
548 #ifdef __SYMBIAN32__ |
|
549 EXPORT_C |
|
550 #endif |
|
551 void |
|
552 oil_class_register_impl (OilFunctionClass *klass, OilFunctionImpl *impl) |
|
553 { |
|
554 impl->klass = klass; |
|
555 impl->next = impl->klass->first_impl; |
|
556 klass->first_impl = impl; |
|
557 if (impl->flags & OIL_IMPL_FLAG_REF) { |
|
558 impl->klass->reference_impl = impl; |
|
559 impl->klass->chosen_impl = impl; |
|
560 impl->klass->func = impl->func; |
|
561 } |
|
562 } |
|
563 |
|
564 /** |
|
565 * oil_class_register_impl_full: |
|
566 * @klass: the class |
|
567 * @func: the function |
|
568 * @name: name of the function |
|
569 * @flags: CPU flags |
|
570 * |
|
571 * Adds @func to the list of implementations associated with |
|
572 * the function class given by @klass. |
|
573 */ |
|
574 #ifdef __SYMBIAN32__ |
|
575 EXPORT_C |
|
576 #endif |
|
577 void |
|
578 oil_class_register_impl_full (OilFunctionClass *klass, |
|
579 void (*func)(void), const char *name, unsigned int flags) |
|
580 { |
|
581 OilFunctionImpl *impl; |
|
582 |
|
583 impl = malloc(sizeof(OilFunctionImpl)); |
|
584 memset (impl, 0, sizeof(OilFunctionImpl)); |
|
585 |
|
586 impl->func = (void*)func; |
|
587 impl->flags = flags; |
|
588 impl->name = xstrdup(name); |
|
589 |
|
590 oil_class_register_impl(klass,impl); |
|
591 } |
|
592 |
|
593 static char * |
|
594 xstrdup (const char *s) |
|
595 { |
|
596 int n = strlen(s); |
|
597 char *t; |
|
598 |
|
599 n = strlen(s); |
|
600 t = malloc(n + 1); |
|
601 memcpy (t, s, n); |
|
602 t[n] = 0; |
|
603 |
|
604 return t; |
|
605 } |
|
606 |