kernel-tuner 0.1.2__tar.gz → 0.1.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {kernel_tuner-0.1.2 → kernel_tuner-0.1.4}/PKG-INFO +50 -81
- {kernel_tuner-0.1.2 → kernel_tuner-0.1.4}/README.rst +49 -80
- {kernel_tuner-0.1.2 → kernel_tuner-0.1.4}/kernel_tuner/c.py +90 -45
- kernel_tuner-0.1.4/kernel_tuner/core.py +198 -0
- {kernel_tuner-0.1.2 → kernel_tuner-0.1.4}/kernel_tuner/cuda.py +22 -9
- {kernel_tuner-0.1.2 → kernel_tuner-0.1.4}/kernel_tuner/interface.py +61 -51
- {kernel_tuner-0.1.2 → kernel_tuner-0.1.4}/kernel_tuner/opencl.py +20 -3
- {kernel_tuner-0.1.2 → kernel_tuner-0.1.4}/kernel_tuner/runners/random_sample.py +12 -17
- {kernel_tuner-0.1.2 → kernel_tuner-0.1.4}/kernel_tuner/runners/sequential_brute_force.py +11 -17
- {kernel_tuner-0.1.2 → kernel_tuner-0.1.4}/kernel_tuner/util.py +47 -44
- {kernel_tuner-0.1.2 → kernel_tuner-0.1.4}/kernel_tuner.egg-info/PKG-INFO +50 -81
- {kernel_tuner-0.1.2 → kernel_tuner-0.1.4}/kernel_tuner.egg-info/SOURCES.txt +1 -0
- kernel_tuner-0.1.4/kernel_tuner.egg-info/requires.txt +1 -0
- kernel_tuner-0.1.4/requirements.txt +1 -0
- {kernel_tuner-0.1.2 → kernel_tuner-0.1.4}/setup.py +6 -1
- {kernel_tuner-0.1.2 → kernel_tuner-0.1.4}/test/test_c_functions.py +13 -10
- {kernel_tuner-0.1.2 → kernel_tuner-0.1.4}/test/test_cuda_mocked.py +3 -3
- {kernel_tuner-0.1.2 → kernel_tuner-0.1.4}/test/test_interface.py +13 -8
- {kernel_tuner-0.1.2 → kernel_tuner-0.1.4}/test/test_kernel_tuner.py +12 -16
- {kernel_tuner-0.1.2 → kernel_tuner-0.1.4}/test/test_runners.py +1 -1
- kernel_tuner-0.1.2/kernel_tuner/core.py +0 -158
- kernel_tuner-0.1.2/requirements.txt +0 -7
- {kernel_tuner-0.1.2 → kernel_tuner-0.1.4}/LICENSE +0 -0
- {kernel_tuner-0.1.2 → kernel_tuner-0.1.4}/MANIFEST.in +0 -0
- {kernel_tuner-0.1.2 → kernel_tuner-0.1.4}/kernel_tuner/__init__.py +0 -0
- {kernel_tuner-0.1.2 → kernel_tuner-0.1.4}/kernel_tuner/runners/__init__.py +0 -0
- {kernel_tuner-0.1.2 → kernel_tuner-0.1.4}/kernel_tuner.egg-info/dependency_links.txt +0 -0
- {kernel_tuner-0.1.2 → kernel_tuner-0.1.4}/kernel_tuner.egg-info/top_level.txt +0 -0
- {kernel_tuner-0.1.2 → kernel_tuner-0.1.4}/setup.cfg +0 -0
- {kernel_tuner-0.1.2 → kernel_tuner-0.1.4}/test/test_cuda_functions.py +0 -0
- {kernel_tuner-0.1.2 → kernel_tuner-0.1.4}/test/test_opencl_functions.py +0 -0
|
@@ -1,20 +1,19 @@
|
|
|
1
1
|
Metadata-Version: 1.1
|
|
2
2
|
Name: kernel_tuner
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.4
|
|
4
4
|
Summary: A simple CUDA/OpenCL kernel tuner in Python
|
|
5
5
|
Home-page: http://benvanwerkhoven.github.io/kernel_tuner/
|
|
6
6
|
Author: Ben van Werkhoven
|
|
7
7
|
Author-email: b.vanwerkhoven@esciencecenter.nl
|
|
8
8
|
License: Apache 2.0
|
|
9
|
-
Description: A simple CUDA/OpenCL kernel tuner in Python
|
|
10
|
-
|
|
9
|
+
Description: Kernel Tuner: A simple CUDA/OpenCL kernel tuner in Python
|
|
10
|
+
=========================================================
|
|
11
11
|
|
|
12
12
|
|Build Status| |Codacy Badge| |Codacy Badge2|
|
|
13
13
|
|
|
14
|
-
The
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
kernel code.
|
|
14
|
+
The Kernel Tuner is a - as simple as possible - tool for testing and auto-tuning
|
|
15
|
+
CUDA and OpenCL kernels. This means that any CUDA or OpenCL kernel can be tuned
|
|
16
|
+
without requiring extensive changes to the original kernel code.
|
|
18
17
|
|
|
19
18
|
A very common problem in GPU programming is that some combination of
|
|
20
19
|
thread block dimensions and other kernel parameters, like tiling or
|
|
@@ -22,18 +21,16 @@ Description: A simple CUDA/OpenCL kernel tuner in Python
|
|
|
22
21
|
kernel configurations. The goal of auto-tuning is to automate the
|
|
23
22
|
process of finding the best performing configuration for a given device.
|
|
24
23
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
24
|
+
The Kernel Tuner offers two main functions which are called run\_kernel and
|
|
25
|
+
tune\_kernel. With run\_kernel it's very easy to write unit tests for your GPU
|
|
26
|
+
kernels in Python. With tune\_kernel you can auto-tune your kernels using only a
|
|
27
|
+
simple Python script. These functions are very flexible and come with a lot of
|
|
28
|
+
optional parameters, for a complete list see the `documentation website
|
|
29
|
+
<http://benvanwerkhoven.github.io/kernel_tuner/user-api.html>`__.
|
|
29
30
|
|
|
30
|
-
The
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
function arguments, and a dictionary of tunable parameters. There are
|
|
34
|
-
also a lot of optional parameters, for a complete list see the full
|
|
35
|
-
documentation of
|
|
36
|
-
`tune\_kernel <http://benvanwerkhoven.github.io/kernel_tuner/details.html>`__.
|
|
31
|
+
The Kernel Tuner does not introduce any new dependencies in your kernels. The
|
|
32
|
+
tuned kernels can afterwards be used independently of the programming environment,
|
|
33
|
+
whether that is using C/C++/Java/Fortran or Python doesn't matter.
|
|
37
34
|
|
|
38
35
|
Documentation
|
|
39
36
|
-------------
|
|
@@ -44,41 +41,35 @@ Description: A simple CUDA/OpenCL kernel tuner in Python
|
|
|
44
41
|
Installation
|
|
45
42
|
------------
|
|
46
43
|
|
|
47
|
-
|
|
44
|
+
The easiest way to install the Kernel Tuner is using pip:
|
|
48
45
|
|
|
49
|
-
-
|
|
46
|
+
.. code-block:: bash
|
|
50
47
|
|
|
51
|
-
|
|
48
|
+
pip install kernel_tuner
|
|
52
49
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
- With a GitHub account: ``git clone git@github.com:benvanwerkhoven/kernel_tuner.git``
|
|
56
|
-
- Without GitHub account: ``git clone https://github.com/benvanwerkhoven/kernel_tuner.git``
|
|
57
|
-
|
|
58
|
-
- change into the top-level directory
|
|
50
|
+
But you can also install from the git repository. This way you also get the
|
|
51
|
+
examples and the tutorials:
|
|
59
52
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
- install using
|
|
63
|
-
|
|
64
|
-
- ``pip install .``
|
|
53
|
+
.. code-block:: bash
|
|
65
54
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
- To tune CUDA kernels
|
|
55
|
+
git clone https://github.com/benvanwerkhoven/kernel_tuner.git
|
|
56
|
+
cd kernel_tuner
|
|
57
|
+
pip install .
|
|
58
|
+
|
|
59
|
+
To tune CUDA kernels:
|
|
73
60
|
|
|
74
|
-
-
|
|
75
|
-
- You can install PyCuda using ``pip install pycuda``
|
|
61
|
+
- First, make sure you have the `CUDA Toolkit <https://developer.nvidia.com/cuda-toolkit>`_ installed
|
|
62
|
+
- You can install PyCuda using ``pip install pycuda``
|
|
76
63
|
|
|
77
|
-
|
|
64
|
+
To tune OpenCL kernels:
|
|
78
65
|
|
|
79
|
-
-
|
|
66
|
+
- First, make sure you have an OpenCL compiler for your intended OpenCL platform
|
|
80
67
|
- You can install PyOpenCL using ``pip install pyopencl``
|
|
81
68
|
|
|
69
|
+
If you need more information about how to install the Kernel Tuner and all
|
|
70
|
+
dependencies see the `installation guide
|
|
71
|
+
<http://benvanwerkhoven.github.io/kernel_tuner/install.html>`__
|
|
72
|
+
|
|
82
73
|
Example usage
|
|
83
74
|
-------------
|
|
84
75
|
|
|
@@ -104,7 +95,7 @@ Description: A simple CUDA/OpenCL kernel tuner in Python
|
|
|
104
95
|
args = [c, a, b, n]
|
|
105
96
|
|
|
106
97
|
tune_params = dict()
|
|
107
|
-
tune_params["block_size_x"] = [
|
|
98
|
+
tune_params["block_size_x"] = [32, 64, 128, 256, 512]
|
|
108
99
|
|
|
109
100
|
tune_kernel("vector_add", kernel_string, size, args, tune_params)
|
|
110
101
|
|
|
@@ -121,22 +112,23 @@ Description: A simple CUDA/OpenCL kernel tuner in Python
|
|
|
121
112
|
}
|
|
122
113
|
"""
|
|
123
114
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
115
|
+
The Kernel Tuner will detect the kernel language and select the right compiler and
|
|
116
|
+
runtime. For every kernel in the parameter space, the Kernel Tuner will insert C
|
|
117
|
+
preprocessor defines for the tunable parameters, compile, and benchmark the kernel. The
|
|
118
|
+
timing results will be printed to the console, but are also returned by tune_kernel to
|
|
119
|
+
allow further analysis. Note that this is just the default behavior, what and how
|
|
120
|
+
tune_kernel does exactly is controlled through its many `optional arguments
|
|
121
|
+
<http://benvanwerkhoven.github.io/kernel_tuner/user-api.html#kernel_tuner.tune_kernel>`__.
|
|
130
122
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
123
|
+
You can find many - more extensive - example codes, in the
|
|
124
|
+
`examples directory <https://github.com/benvanwerkhoven/kernel_tuner/blob/master/examples/>`__
|
|
125
|
+
and in the `Kernel Tuner
|
|
126
|
+
documentation pages <http://benvanwerkhoven.github.io/kernel_tuner/index.html>`__.
|
|
135
127
|
|
|
136
128
|
Tuning host and kernel code
|
|
137
129
|
---------------------------
|
|
138
130
|
|
|
139
|
-
It is
|
|
131
|
+
It is possible to tune for combinations of tunable parameters in
|
|
140
132
|
both host and kernel code. This allows for a number of powerfull things,
|
|
141
133
|
such as tuning the number of streams for a kernel that uses CUDA Streams
|
|
142
134
|
or OpenCL Command Queues to overlap transfers between host and device
|
|
@@ -160,33 +152,10 @@ Description: A simple CUDA/OpenCL kernel tuner in Python
|
|
|
160
152
|
answer = [a+b, None, None] # the order matches the arguments (in args) to the kernel
|
|
161
153
|
tune_kernel("vector_add", kernel_string, size, args, tune_params, answer=answer)
|
|
162
154
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
The kernel tuner follows the Google Python style guide, with Sphinxdoc
|
|
167
|
-
docstrings for module public functions. If you want to contribute to the
|
|
168
|
-
project please fork it, create a branch including your addition, and
|
|
169
|
-
create a pull request.
|
|
170
|
-
|
|
171
|
-
The tests use relative imports and can be run directly after making
|
|
172
|
-
changes to the code. To run all tests use ``nosetests`` in the main
|
|
173
|
-
directory. To run the examples after code changes, you need to run
|
|
174
|
-
``pip install --upgrade .`` in the main directory. Documentation is
|
|
175
|
-
generated by typing ``make html`` in the doc directory, the contents of
|
|
176
|
-
``doc/build/html/`` should then be copied to ``sphinxdoc`` directory of
|
|
177
|
-
the ``gh-pages`` branch.
|
|
178
|
-
|
|
179
|
-
Before creating a pull request please ensure the following:
|
|
180
|
-
|
|
181
|
-
* You have written unit tests to test your additions and all unit tests pass
|
|
182
|
-
* The examples still work and produce the same (or better) results
|
|
183
|
-
* The code is compatible with both Python 2.7 and Python 3.5
|
|
184
|
-
* An entry about the change or addition is created in CHANGELOG.md
|
|
185
|
-
|
|
186
|
-
Contributing authors so far:
|
|
155
|
+
Contributing
|
|
156
|
+
------------
|
|
187
157
|
|
|
188
|
-
|
|
189
|
-
* Berend Weel
|
|
158
|
+
Please see the `Contributions Guide <http://benvanwerkhoven.github.io/kernel_tuner/contributing.html>`__.
|
|
190
159
|
|
|
191
160
|
Citation
|
|
192
161
|
--------
|
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
A simple CUDA/OpenCL kernel tuner in Python
|
|
2
|
-
|
|
1
|
+
Kernel Tuner: A simple CUDA/OpenCL kernel tuner in Python
|
|
2
|
+
=========================================================
|
|
3
3
|
|
|
4
4
|
|Build Status| |Codacy Badge| |Codacy Badge2|
|
|
5
5
|
|
|
6
|
-
The
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
kernel code.
|
|
6
|
+
The Kernel Tuner is a - as simple as possible - tool for testing and auto-tuning
|
|
7
|
+
CUDA and OpenCL kernels. This means that any CUDA or OpenCL kernel can be tuned
|
|
8
|
+
without requiring extensive changes to the original kernel code.
|
|
10
9
|
|
|
11
10
|
A very common problem in GPU programming is that some combination of
|
|
12
11
|
thread block dimensions and other kernel parameters, like tiling or
|
|
@@ -14,18 +13,16 @@ unrolling factors, results in dramatically better performance than other
|
|
|
14
13
|
kernel configurations. The goal of auto-tuning is to automate the
|
|
15
14
|
process of finding the best performing configuration for a given device.
|
|
16
15
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
16
|
+
The Kernel Tuner offers two main functions which are called run\_kernel and
|
|
17
|
+
tune\_kernel. With run\_kernel it's very easy to write unit tests for your GPU
|
|
18
|
+
kernels in Python. With tune\_kernel you can auto-tune your kernels using only a
|
|
19
|
+
simple Python script. These functions are very flexible and come with a lot of
|
|
20
|
+
optional parameters, for a complete list see the `documentation website
|
|
21
|
+
<http://benvanwerkhoven.github.io/kernel_tuner/user-api.html>`__.
|
|
21
22
|
|
|
22
|
-
The
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
function arguments, and a dictionary of tunable parameters. There are
|
|
26
|
-
also a lot of optional parameters, for a complete list see the full
|
|
27
|
-
documentation of
|
|
28
|
-
`tune\_kernel <http://benvanwerkhoven.github.io/kernel_tuner/details.html>`__.
|
|
23
|
+
The Kernel Tuner does not introduce any new dependencies in your kernels. The
|
|
24
|
+
tuned kernels can afterwards be used independently of the programming environment,
|
|
25
|
+
whether that is using C/C++/Java/Fortran or Python doesn't matter.
|
|
29
26
|
|
|
30
27
|
Documentation
|
|
31
28
|
-------------
|
|
@@ -36,41 +33,35 @@ The full documentation is available
|
|
|
36
33
|
Installation
|
|
37
34
|
------------
|
|
38
35
|
|
|
39
|
-
|
|
36
|
+
The easiest way to install the Kernel Tuner is using pip:
|
|
40
37
|
|
|
41
|
-
-
|
|
38
|
+
.. code-block:: bash
|
|
42
39
|
|
|
43
|
-
|
|
40
|
+
pip install kernel_tuner
|
|
44
41
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
- With a GitHub account: ``git clone git@github.com:benvanwerkhoven/kernel_tuner.git``
|
|
48
|
-
- Without GitHub account: ``git clone https://github.com/benvanwerkhoven/kernel_tuner.git``
|
|
49
|
-
|
|
50
|
-
- change into the top-level directory
|
|
42
|
+
But you can also install from the git repository. This way you also get the
|
|
43
|
+
examples and the tutorials:
|
|
51
44
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
- install using
|
|
55
|
-
|
|
56
|
-
- ``pip install .``
|
|
45
|
+
.. code-block:: bash
|
|
57
46
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
- To tune CUDA kernels
|
|
47
|
+
git clone https://github.com/benvanwerkhoven/kernel_tuner.git
|
|
48
|
+
cd kernel_tuner
|
|
49
|
+
pip install .
|
|
50
|
+
|
|
51
|
+
To tune CUDA kernels:
|
|
65
52
|
|
|
66
|
-
-
|
|
67
|
-
- You can install PyCuda using ``pip install pycuda``
|
|
53
|
+
- First, make sure you have the `CUDA Toolkit <https://developer.nvidia.com/cuda-toolkit>`_ installed
|
|
54
|
+
- You can install PyCuda using ``pip install pycuda``
|
|
68
55
|
|
|
69
|
-
|
|
56
|
+
To tune OpenCL kernels:
|
|
70
57
|
|
|
71
|
-
-
|
|
58
|
+
- First, make sure you have an OpenCL compiler for your intended OpenCL platform
|
|
72
59
|
- You can install PyOpenCL using ``pip install pyopencl``
|
|
73
60
|
|
|
61
|
+
If you need more information about how to install the Kernel Tuner and all
|
|
62
|
+
dependencies see the `installation guide
|
|
63
|
+
<http://benvanwerkhoven.github.io/kernel_tuner/install.html>`__
|
|
64
|
+
|
|
74
65
|
Example usage
|
|
75
66
|
-------------
|
|
76
67
|
|
|
@@ -96,7 +87,7 @@ The following shows a simple example for tuning a CUDA kernel:
|
|
|
96
87
|
args = [c, a, b, n]
|
|
97
88
|
|
|
98
89
|
tune_params = dict()
|
|
99
|
-
tune_params["block_size_x"] = [
|
|
90
|
+
tune_params["block_size_x"] = [32, 64, 128, 256, 512]
|
|
100
91
|
|
|
101
92
|
tune_kernel("vector_add", kernel_string, size, args, tune_params)
|
|
102
93
|
|
|
@@ -113,22 +104,23 @@ The exact same Python code can be used to tune an OpenCL kernel:
|
|
|
113
104
|
}
|
|
114
105
|
"""
|
|
115
106
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
107
|
+
The Kernel Tuner will detect the kernel language and select the right compiler and
|
|
108
|
+
runtime. For every kernel in the parameter space, the Kernel Tuner will insert C
|
|
109
|
+
preprocessor defines for the tunable parameters, compile, and benchmark the kernel. The
|
|
110
|
+
timing results will be printed to the console, but are also returned by tune_kernel to
|
|
111
|
+
allow further analysis. Note that this is just the default behavior, what and how
|
|
112
|
+
tune_kernel does exactly is controlled through its many `optional arguments
|
|
113
|
+
<http://benvanwerkhoven.github.io/kernel_tuner/user-api.html#kernel_tuner.tune_kernel>`__.
|
|
122
114
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
115
|
+
You can find many - more extensive - example codes, in the
|
|
116
|
+
`examples directory <https://github.com/benvanwerkhoven/kernel_tuner/blob/master/examples/>`__
|
|
117
|
+
and in the `Kernel Tuner
|
|
118
|
+
documentation pages <http://benvanwerkhoven.github.io/kernel_tuner/index.html>`__.
|
|
127
119
|
|
|
128
120
|
Tuning host and kernel code
|
|
129
121
|
---------------------------
|
|
130
122
|
|
|
131
|
-
It is
|
|
123
|
+
It is possible to tune for combinations of tunable parameters in
|
|
132
124
|
both host and kernel code. This allows for a number of powerfull things,
|
|
133
125
|
such as tuning the number of streams for a kernel that uses CUDA Streams
|
|
134
126
|
or OpenCL Command Queues to overlap transfers between host and device
|
|
@@ -152,33 +144,10 @@ expected output of the kernel. Input arguments are replaced with None.
|
|
|
152
144
|
answer = [a+b, None, None] # the order matches the arguments (in args) to the kernel
|
|
153
145
|
tune_kernel("vector_add", kernel_string, size, args, tune_params, answer=answer)
|
|
154
146
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
The kernel tuner follows the Google Python style guide, with Sphinxdoc
|
|
159
|
-
docstrings for module public functions. If you want to contribute to the
|
|
160
|
-
project please fork it, create a branch including your addition, and
|
|
161
|
-
create a pull request.
|
|
162
|
-
|
|
163
|
-
The tests use relative imports and can be run directly after making
|
|
164
|
-
changes to the code. To run all tests use ``nosetests`` in the main
|
|
165
|
-
directory. To run the examples after code changes, you need to run
|
|
166
|
-
``pip install --upgrade .`` in the main directory. Documentation is
|
|
167
|
-
generated by typing ``make html`` in the doc directory, the contents of
|
|
168
|
-
``doc/build/html/`` should then be copied to ``sphinxdoc`` directory of
|
|
169
|
-
the ``gh-pages`` branch.
|
|
170
|
-
|
|
171
|
-
Before creating a pull request please ensure the following:
|
|
172
|
-
|
|
173
|
-
* You have written unit tests to test your additions and all unit tests pass
|
|
174
|
-
* The examples still work and produce the same (or better) results
|
|
175
|
-
* The code is compatible with both Python 2.7 and Python 3.5
|
|
176
|
-
* An entry about the change or addition is created in CHANGELOG.md
|
|
177
|
-
|
|
178
|
-
Contributing authors so far:
|
|
147
|
+
Contributing
|
|
148
|
+
------------
|
|
179
149
|
|
|
180
|
-
|
|
181
|
-
* Berend Weel
|
|
150
|
+
Please see the `Contributions Guide <http://benvanwerkhoven.github.io/kernel_tuner/contributing.html>`__.
|
|
182
151
|
|
|
183
152
|
Citation
|
|
184
153
|
--------
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
""" This module contains the functionality for running and compiling C functions """
|
|
2
2
|
|
|
3
|
-
import numpy
|
|
4
|
-
import ctypes as C
|
|
5
|
-
import _ctypes
|
|
6
3
|
import subprocess
|
|
7
|
-
import
|
|
4
|
+
import platform
|
|
8
5
|
import errno
|
|
6
|
+
import logging
|
|
7
|
+
import ctypes as C
|
|
8
|
+
import _ctypes
|
|
9
9
|
|
|
10
|
+
import numpy
|
|
10
11
|
import numpy.ctypeslib
|
|
11
|
-
from kernel_tuner.util import get_temp_filename, delete_temp_file
|
|
12
12
|
|
|
13
|
-
import
|
|
13
|
+
from kernel_tuner.util import get_temp_filename, delete_temp_file, write_file
|
|
14
|
+
|
|
14
15
|
|
|
15
16
|
class CFunctions(object):
|
|
16
17
|
"""Class that groups the code for running and compiling C functions"""
|
|
@@ -21,20 +22,46 @@ class CFunctions(object):
|
|
|
21
22
|
:param iterations: Number of iterations used while benchmarking a kernel, 7 by default.
|
|
22
23
|
:type iterations: int
|
|
23
24
|
"""
|
|
24
|
-
self.
|
|
25
|
+
self.iterations = iterations
|
|
25
26
|
self.max_threads = 1024
|
|
26
27
|
self.compiler_options = compiler_options
|
|
27
28
|
self.lib = None
|
|
29
|
+
self.using_openmp = False
|
|
30
|
+
self.arg_mapping = dict()
|
|
28
31
|
|
|
29
|
-
#
|
|
30
|
-
self.compiler = "
|
|
32
|
+
#use gcc by default
|
|
33
|
+
self.compiler = "g++"
|
|
31
34
|
try:
|
|
32
|
-
subprocess.
|
|
35
|
+
gcc_version = str(subprocess.check_output([self.compiler, "--version"]))
|
|
36
|
+
gcc_version = gcc_version.splitlines()[0].split(" ")[-1]
|
|
37
|
+
except OSError as e:
|
|
38
|
+
raise e
|
|
39
|
+
|
|
40
|
+
#check if nvcc is available
|
|
41
|
+
self.nvcc_available = False
|
|
42
|
+
try:
|
|
43
|
+
nvcc_version = str(subprocess.check_output(["nvcc", "--version"]))
|
|
44
|
+
nvcc_version = nvcc_version.splitlines()[-1].split(" ")[-1]
|
|
45
|
+
self.nvcc_available = True
|
|
33
46
|
except OSError as e:
|
|
34
|
-
self.compiler = "gcc"
|
|
35
47
|
if e.errno != errno.ENOENT:
|
|
36
48
|
raise e
|
|
37
49
|
|
|
50
|
+
#environment info
|
|
51
|
+
env = dict()
|
|
52
|
+
env["GCC Version"] = gcc_version
|
|
53
|
+
if self.nvcc_available:
|
|
54
|
+
env["NVCC Version"] = nvcc_version
|
|
55
|
+
env["iterations"] = self.iterations
|
|
56
|
+
env["compiler_options"] = compiler_options
|
|
57
|
+
self.env = env
|
|
58
|
+
self.name = platform.processor()
|
|
59
|
+
|
|
60
|
+
def get_environment(self):
|
|
61
|
+
"""Return dictionary with information about the environment"""
|
|
62
|
+
return self.env
|
|
63
|
+
|
|
64
|
+
|
|
38
65
|
def ready_argument_list(self, arguments):
|
|
39
66
|
"""ready argument list to be passed to the C function
|
|
40
67
|
|
|
@@ -46,31 +73,30 @@ class CFunctions(object):
|
|
|
46
73
|
:returns: A list of arguments that can be passed to the C function.
|
|
47
74
|
:rtype: list()
|
|
48
75
|
"""
|
|
49
|
-
self.arg_mapping = dict()
|
|
50
76
|
ctype_args = []
|
|
77
|
+
|
|
78
|
+
dtype_map = {"int32": C.c_int32,
|
|
79
|
+
"int64": C.c_int64,
|
|
80
|
+
"float32": C.c_float,
|
|
81
|
+
"float64": C.c_double}
|
|
82
|
+
np_to_c_type_map = {numpy.int32: C.c_int32,
|
|
83
|
+
numpy.int64: C.c_int64,
|
|
84
|
+
numpy.float32: C.c_float,
|
|
85
|
+
numpy.float64: C.c_double}
|
|
86
|
+
|
|
51
87
|
for arg in arguments:
|
|
52
88
|
if isinstance(arg, numpy.ndarray):
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
ctype_args.append(arg.ctypes.data_as(C.POINTER(C.c_double)))
|
|
57
|
-
elif arg.dtype == 'int32':
|
|
58
|
-
ctype_args.append(arg.ctypes.data_as(C.POINTER(C.c_int)))
|
|
89
|
+
dtype_str = str(arg.dtype)
|
|
90
|
+
if dtype_str in dtype_map.keys():
|
|
91
|
+
ctype_args.append(arg.ctypes.data_as(C.POINTER(dtype_map[dtype_str])))
|
|
59
92
|
else:
|
|
60
93
|
raise TypeError("unknown dtype for ndarray")
|
|
61
94
|
self.arg_mapping[str(ctype_args[-1])] = arg.shape
|
|
62
|
-
elif
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
ctype_args.append(int(arg))
|
|
66
|
-
elif str(arg.dtype).startswith('float'):
|
|
67
|
-
ctype_args.append(float(arg))
|
|
68
|
-
else:
|
|
69
|
-
raise TypeError("Argument is scalar with a dtype, but does not start with int or float")
|
|
70
|
-
else:
|
|
71
|
-
ctype_args.append(arg)
|
|
95
|
+
elif isinstance(arg, tuple(np_to_c_type_map.keys())):
|
|
96
|
+
ctype_args.append(np_to_c_type_map[type(arg)](arg))
|
|
97
|
+
self.arg_mapping[str(ctype_args[-1])] = ()
|
|
72
98
|
else:
|
|
73
|
-
raise TypeError("Argument is not
|
|
99
|
+
raise TypeError("Argument is not numpy ndarray or numpy scalar %s" % type(arg))
|
|
74
100
|
|
|
75
101
|
return ctype_args
|
|
76
102
|
|
|
@@ -95,12 +121,20 @@ class CFunctions(object):
|
|
|
95
121
|
|
|
96
122
|
filename = get_temp_filename()
|
|
97
123
|
source_file = filename+".cc"
|
|
98
|
-
|
|
124
|
+
|
|
125
|
+
if not "extern \"C\"" in kernel_string:
|
|
126
|
+
kernel_string = "extern \"C\" {\n" + kernel_string + "\n}"
|
|
99
127
|
|
|
100
128
|
compiler_options = ["-fPIC"]
|
|
101
129
|
if "#include <omp.h>" in kernel_string:
|
|
130
|
+
logging.debug('set using_openmp to true')
|
|
131
|
+
self.using_openmp = True
|
|
102
132
|
compiler_options.append("-fopenmp")
|
|
103
133
|
|
|
134
|
+
if ("#include <cuda" in kernel_string) or ("__global__" in kernel_string):
|
|
135
|
+
if self.nvcc_available:
|
|
136
|
+
self.compiler = "nvcc"
|
|
137
|
+
|
|
104
138
|
if self.compiler == "nvcc":
|
|
105
139
|
source_file = source_file[:-1] + "u"
|
|
106
140
|
compiler_options = ["-Xcompiler=" + c for c in compiler_options]
|
|
@@ -112,12 +146,15 @@ class CFunctions(object):
|
|
|
112
146
|
if "CL/cl.h" in kernel_string:
|
|
113
147
|
lib_args = ["-lOpenCL"]
|
|
114
148
|
|
|
149
|
+
logging.debug('using compiler ' + self.compiler)
|
|
150
|
+
logging.debug('compiler_options ' + " ".join(compiler_options))
|
|
151
|
+
logging.debug('lib_args ' + " ".join(lib_args))
|
|
152
|
+
|
|
115
153
|
try:
|
|
116
|
-
|
|
117
|
-
f.write(kernel_string)
|
|
154
|
+
write_file(source_file, kernel_string)
|
|
118
155
|
|
|
119
156
|
subprocess.check_call([self.compiler, "-c", source_file] + compiler_options + ["-o", filename+".o"])
|
|
120
|
-
subprocess.check_call([self.compiler, filename+".o"] + compiler_options + [
|
|
157
|
+
subprocess.check_call([self.compiler, filename+".o"] + compiler_options + ["-shared", "-o", filename+".so"] + lib_args)
|
|
121
158
|
|
|
122
159
|
self.lib = numpy.ctypeslib.load_library(filename, '.')
|
|
123
160
|
|
|
@@ -167,8 +204,19 @@ class CFunctions(object):
|
|
|
167
204
|
:rtype: float
|
|
168
205
|
"""
|
|
169
206
|
results = []
|
|
170
|
-
for _ in range(self.
|
|
207
|
+
for _ in range(self.iterations):
|
|
171
208
|
value = self.run_kernel(func, c_args, threads, grid)
|
|
209
|
+
|
|
210
|
+
#I would like to replace the following with actually capturing
|
|
211
|
+
#stderr and detecting the error directly in Python, it proved
|
|
212
|
+
#however that capturing stderr for non-Python functions from Python
|
|
213
|
+
#is a rather difficult thing to do
|
|
214
|
+
#
|
|
215
|
+
#The current, less than ideal, scheme uses the convention that a
|
|
216
|
+
#negative time indicates a 'too many resources requested for launch'
|
|
217
|
+
if value < 0.0:
|
|
218
|
+
raise Exception("too many resources requested for launch")
|
|
219
|
+
|
|
172
220
|
results.append(value)
|
|
173
221
|
results = sorted(results)
|
|
174
222
|
return numpy.mean(results[1:-1])
|
|
@@ -196,17 +244,10 @@ class CFunctions(object):
|
|
|
196
244
|
:returns: A robust average of values returned by the C function.
|
|
197
245
|
:rtype: float
|
|
198
246
|
"""
|
|
199
|
-
|
|
247
|
+
logging.debug("run_kernel")
|
|
248
|
+
logging.debug("arguments=" + str([str(arg) for arg in c_args]))
|
|
200
249
|
|
|
201
|
-
|
|
202
|
-
#stderr and detecting the error directly in Python, it proved
|
|
203
|
-
#however that capturing stderr for non-Python functions from Python
|
|
204
|
-
#is a rather difficult thing to do
|
|
205
|
-
#
|
|
206
|
-
#The current, less than ideal, scheme uses the convention that a
|
|
207
|
-
#negative time indicates a 'too many resources requested for launch'
|
|
208
|
-
if time < 0.0:
|
|
209
|
-
raise Exception("too many resources requested for launch")
|
|
250
|
+
time = func(*c_args)
|
|
210
251
|
|
|
211
252
|
return time
|
|
212
253
|
|
|
@@ -240,4 +281,8 @@ class CFunctions(object):
|
|
|
240
281
|
|
|
241
282
|
def cleanup_lib(self):
|
|
242
283
|
""" unload the previously loaded shared library """
|
|
243
|
-
|
|
284
|
+
if not self.using_openmp:
|
|
285
|
+
#this if statement is necessary because shared libraries that use
|
|
286
|
+
#OpenMP will core dump when unloaded, this is a well-known issue with OpenMP
|
|
287
|
+
logging.debug('unloading shared library')
|
|
288
|
+
_ctypes.dlclose(self.lib._handle)
|