I (DavidCournapeau) will put here some findings/ideas about a system for runtime optimizations in numpy/scipy.
- http://lalists.stanford.edu/lad/2008/04/0023.html
- liboil: has an implementation of what we need, but it is maybe over-complicated.
- Requirements:
- Provide interface to pure C functions (that is, the user of the functions available in plugins should not even be aware they are from plugins, except an eventual initialization call)
- Portable
- Simple (no COM, etc...)
- scalable to hundred of functions: Should be mostly automatic from the list of function declaration (in C; what about Fortran ? Can we use f2py for fortran ?) and for each function the list of implementation
- Problems:
- we should wrap the names of all used functions, to avoid name clash (foo in a .so, we always call wrapped_foo). I don't think any other way is possible without losing portability (namespace of symbols in shared code).
- For a set of functions (say the fft, or blas set), should all implementations have all functions ?
- What about sets which depend on optional dependencies ?
- loading a plugin in multi-threaded code: putting a lock around the whole plugin loading is possible ? If yes, easy.
- The logic to get a plugin location from a set of parameters is not so trivial: for example, blas/lapack have many different possible names depending on the platforms. We could generate the mapping at build time, though, with possible customization for advanced usage ?
Prototype:
- I have a really preliminary prototype working. It aims at adressing the following issues:
- generale usage from plugin user
- automatic code generation from a list of protoypes (C function declarations).
See here: https://code.launchpad.net/~david-ar/+junk/numplug
Assuming we have the list of functions in a text file, say five functions foo1, ... foo5:
The build system would then takes care of wrapping those functions, generating a header (plugapi.h) which will be used by the consumer (main.c), and a c file which load the functions (plugapi.c):
1 /*
2 * main.c
3 */
4 #include <stdlib.h>
5 #include <stdio.h>
6
7 #include "plugapi.h"
8
9 int main()
10 {
11 double *a = NULL, *b = NULL;
12 int n = 0;
13
14 int st;
15
16 /* Change argument to 0 or 1 */
17 st = init_foo(1);
18 if (st != 0) {
19 fprintf(stderr, "Error loading plug, status is %d\n", st);
20 fprintf(stderr, "Exciting...\n");
21 exit(EXIT_FAILURE);
22 }
23
24 npyw_foo1();
25 npyw_foo2();
26 npyw_foo3(n);
27 npyw_foo4(a, b);
28 npyw_foo5(a, b, n);
29
30 return 0;
31 }
The templates for the plugapi.h and plugapi.c are:
1 #include "plugapi.h"
2
3 /*
4 * At some point, this should be platform independant starting from here
5 */
6 int init_foo(int imp)
7 {
8 void* hdl;
9 int st = 0;
10
11 hdl = load_foo(imp);
12 if (hdl == NULL) {
13 return NPYW_FAIL_LOAD_PLUG;
14 }
15
16 /*
17 * XXX: it would be good to set all function pointers to dummy
18 * functions, to make debugging easier ?
19 */
20 FILL_WRAPPERS
21
22 return st;
23
24 fail_load_func:
25 unload_foo(hdl);
26 return NPYW_FAIL_LOAD_FUNC;
27 }