kernel-tuner 0.1.1__tar.gz → 0.1.2__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.1 → kernel_tuner-0.1.2}/MANIFEST.in +1 -1
- kernel_tuner-0.1.2/PKG-INFO +232 -0
- kernel_tuner-0.1.2/README.rst +208 -0
- {kernel_tuner-0.1.1 → kernel_tuner-0.1.2}/kernel_tuner/c.py +28 -6
- {kernel_tuner-0.1.1 → kernel_tuner-0.1.2}/kernel_tuner/core.py +23 -2
- {kernel_tuner-0.1.1 → kernel_tuner-0.1.2}/kernel_tuner/cuda.py +10 -1
- {kernel_tuner-0.1.1 → kernel_tuner-0.1.2}/kernel_tuner/interface.py +83 -123
- {kernel_tuner-0.1.1 → kernel_tuner-0.1.2}/kernel_tuner/runners/random_sample.py +3 -3
- {kernel_tuner-0.1.1 → kernel_tuner-0.1.2}/kernel_tuner/runners/sequential_brute_force.py +10 -3
- {kernel_tuner-0.1.1 → kernel_tuner-0.1.2}/kernel_tuner/util.py +34 -21
- kernel_tuner-0.1.2/kernel_tuner.egg-info/PKG-INFO +232 -0
- {kernel_tuner-0.1.1 → kernel_tuner-0.1.2}/kernel_tuner.egg-info/SOURCES.txt +1 -1
- {kernel_tuner-0.1.1 → kernel_tuner-0.1.2}/requirements.txt +2 -1
- {kernel_tuner-0.1.1 → kernel_tuner-0.1.2}/setup.cfg +1 -1
- {kernel_tuner-0.1.1 → kernel_tuner-0.1.2}/setup.py +6 -2
- {kernel_tuner-0.1.1 → kernel_tuner-0.1.2}/test/test_c_functions.py +0 -1
- {kernel_tuner-0.1.1 → kernel_tuner-0.1.2}/test/test_cuda_functions.py +1 -1
- {kernel_tuner-0.1.1 → kernel_tuner-0.1.2}/test/test_cuda_mocked.py +0 -1
- {kernel_tuner-0.1.1 → kernel_tuner-0.1.2}/test/test_interface.py +4 -5
- {kernel_tuner-0.1.1 → kernel_tuner-0.1.2}/test/test_kernel_tuner.py +28 -31
- {kernel_tuner-0.1.1 → kernel_tuner-0.1.2}/test/test_opencl_functions.py +1 -3
- {kernel_tuner-0.1.1 → kernel_tuner-0.1.2}/test/test_runners.py +1 -4
- kernel_tuner-0.1.1/PKG-INFO +0 -136
- kernel_tuner-0.1.1/README.md +0 -142
- kernel_tuner-0.1.1/kernel_tuner.egg-info/PKG-INFO +0 -136
- {kernel_tuner-0.1.1 → kernel_tuner-0.1.2}/LICENSE +0 -0
- {kernel_tuner-0.1.1 → kernel_tuner-0.1.2}/kernel_tuner/__init__.py +0 -0
- {kernel_tuner-0.1.1 → kernel_tuner-0.1.2}/kernel_tuner/opencl.py +0 -0
- {kernel_tuner-0.1.1 → kernel_tuner-0.1.2}/kernel_tuner/runners/__init__.py +0 -0
- {kernel_tuner-0.1.1 → kernel_tuner-0.1.2}/kernel_tuner.egg-info/dependency_links.txt +0 -0
- {kernel_tuner-0.1.1 → kernel_tuner-0.1.2}/kernel_tuner.egg-info/top_level.txt +0 -0
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
Metadata-Version: 1.1
|
|
2
|
+
Name: kernel_tuner
|
|
3
|
+
Version: 0.1.2
|
|
4
|
+
Summary: A simple CUDA/OpenCL kernel tuner in Python
|
|
5
|
+
Home-page: http://benvanwerkhoven.github.io/kernel_tuner/
|
|
6
|
+
Author: Ben van Werkhoven
|
|
7
|
+
Author-email: b.vanwerkhoven@esciencecenter.nl
|
|
8
|
+
License: Apache 2.0
|
|
9
|
+
Description: A simple CUDA/OpenCL kernel tuner in Python
|
|
10
|
+
===========================================
|
|
11
|
+
|
|
12
|
+
|Build Status| |Codacy Badge| |Codacy Badge2|
|
|
13
|
+
|
|
14
|
+
The goal of this project is to provide a - as simple as possible - tool
|
|
15
|
+
for tuning CUDA and OpenCL kernels. This implies that any CUDA or OpenCL
|
|
16
|
+
kernel can be tuned without requiring extensive changes to the original
|
|
17
|
+
kernel code.
|
|
18
|
+
|
|
19
|
+
A very common problem in GPU programming is that some combination of
|
|
20
|
+
thread block dimensions and other kernel parameters, like tiling or
|
|
21
|
+
unrolling factors, results in dramatically better performance than other
|
|
22
|
+
kernel configurations. The goal of auto-tuning is to automate the
|
|
23
|
+
process of finding the best performing configuration for a given device.
|
|
24
|
+
|
|
25
|
+
This kernel tuner aims that you can directly use the tuned kernel
|
|
26
|
+
without introducing any new dependencies. The tuned kernels can
|
|
27
|
+
afterwards be used independently of the programming environment, whether
|
|
28
|
+
that is using C/C++/Java/Fortran or Python doesn't matter.
|
|
29
|
+
|
|
30
|
+
The kernel\_tuner module currently only contains main one function which
|
|
31
|
+
is called tune\_kernel to which you pass at least the kernel name, a
|
|
32
|
+
string containing the kernel code, the problem size, a list of kernel
|
|
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>`__.
|
|
37
|
+
|
|
38
|
+
Documentation
|
|
39
|
+
-------------
|
|
40
|
+
|
|
41
|
+
The full documentation is available
|
|
42
|
+
`here <http://benvanwerkhoven.github.io/kernel_tuner/index.html>`__.
|
|
43
|
+
|
|
44
|
+
Installation
|
|
45
|
+
------------
|
|
46
|
+
|
|
47
|
+
To install from PyPi:
|
|
48
|
+
|
|
49
|
+
- ``pip install kernel_tuner``
|
|
50
|
+
|
|
51
|
+
To install from the source (and get the tutorial and examples):
|
|
52
|
+
|
|
53
|
+
- clone the repository
|
|
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
|
|
59
|
+
|
|
60
|
+
- ``cd kernel_tuner``
|
|
61
|
+
|
|
62
|
+
- install using
|
|
63
|
+
|
|
64
|
+
- ``pip install .``
|
|
65
|
+
|
|
66
|
+
Dependencies
|
|
67
|
+
------------
|
|
68
|
+
Python 2.7 or Python 3.5
|
|
69
|
+
|
|
70
|
+
PyCuda and/or PyOpenCL (https://mathema.tician.de/software/)
|
|
71
|
+
|
|
72
|
+
- To tune CUDA kernels
|
|
73
|
+
|
|
74
|
+
- Make sure you have the `CUDA Toolkit <https://developer.nvidia.com/cuda-toolkit>`_ installed
|
|
75
|
+
- You can install PyCuda using ``pip install pycuda``
|
|
76
|
+
|
|
77
|
+
- To tune OpenCL kernels
|
|
78
|
+
|
|
79
|
+
- Make sure you have an OpenCL compiler for your intended OpenCL platform
|
|
80
|
+
- You can install PyOpenCL using ``pip install pyopencl``
|
|
81
|
+
|
|
82
|
+
Example usage
|
|
83
|
+
-------------
|
|
84
|
+
|
|
85
|
+
The following shows a simple example for tuning a CUDA kernel:
|
|
86
|
+
|
|
87
|
+
.. code:: python
|
|
88
|
+
|
|
89
|
+
kernel_string = """
|
|
90
|
+
__global__ void vector_add(float *c, float *a, float *b, int n) {
|
|
91
|
+
int i = blockIdx.x * block_size_x + threadIdx.x;
|
|
92
|
+
if (i<n) {
|
|
93
|
+
c[i] = a[i] + b[i];
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
"""
|
|
97
|
+
|
|
98
|
+
size = 10000000
|
|
99
|
+
|
|
100
|
+
a = numpy.random.randn(size).astype(numpy.float32)
|
|
101
|
+
b = numpy.random.randn(size).astype(numpy.float32)
|
|
102
|
+
c = numpy.zeros_like(b)
|
|
103
|
+
n = numpy.int32(size)
|
|
104
|
+
args = [c, a, b, n]
|
|
105
|
+
|
|
106
|
+
tune_params = dict()
|
|
107
|
+
tune_params["block_size_x"] = [128+64*i for i in range(15)]
|
|
108
|
+
|
|
109
|
+
tune_kernel("vector_add", kernel_string, size, args, tune_params)
|
|
110
|
+
|
|
111
|
+
The exact same Python code can be used to tune an OpenCL kernel:
|
|
112
|
+
|
|
113
|
+
.. code:: python
|
|
114
|
+
|
|
115
|
+
kernel_string = """
|
|
116
|
+
__kernel void vector_add(__global float *c, __global float *a, __global float *b, int n) {
|
|
117
|
+
int i = get_global_id(0);
|
|
118
|
+
if (i<n) {
|
|
119
|
+
c[i] = a[i] + b[i];
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
"""
|
|
123
|
+
|
|
124
|
+
Or even just a C function, see the example
|
|
125
|
+
`here <https://github.com/benvanwerkhoven/kernel_tuner/blob/master/examples/c/vector_add.py>`__.
|
|
126
|
+
|
|
127
|
+
You can find these and many - more extensive - example codes, in the
|
|
128
|
+
`examples <https://github.com/benvanwerkhoven/kernel_tuner/blob/master/examples/>`__
|
|
129
|
+
directory.
|
|
130
|
+
|
|
131
|
+
See the `full
|
|
132
|
+
documentation <http://benvanwerkhoven.github.io/kernel_tuner/index.html>`__
|
|
133
|
+
for several highly detailed tutorial-style explanations of example
|
|
134
|
+
kernels and the scripts to tune them.
|
|
135
|
+
|
|
136
|
+
Tuning host and kernel code
|
|
137
|
+
---------------------------
|
|
138
|
+
|
|
139
|
+
It is also possible to tune for combinations of tunable parameters in
|
|
140
|
+
both host and kernel code. This allows for a number of powerfull things,
|
|
141
|
+
such as tuning the number of streams for a kernel that uses CUDA Streams
|
|
142
|
+
or OpenCL Command Queues to overlap transfers between host and device
|
|
143
|
+
with kernel execution. This can be done in combination with tuning the
|
|
144
|
+
parameters inside the kernel code. See the `convolution\_streams example
|
|
145
|
+
code <https://github.com/benvanwerkhoven/kernel_tuner/blob/master/examples/>`__
|
|
146
|
+
and the
|
|
147
|
+
`documentation <http://benvanwerkhoven.github.io/kernel_tuner/hostcode.html>`__
|
|
148
|
+
for a detailed explanation of the kernel tuner Python script.
|
|
149
|
+
|
|
150
|
+
Correctness verification
|
|
151
|
+
------------------------
|
|
152
|
+
|
|
153
|
+
Optionally, you can let the kernel tuner verify the output of every
|
|
154
|
+
kernel it compiles and benchmarks, by passing an ``answer`` list. This
|
|
155
|
+
list matches the list of arguments to the kernel, but contains the
|
|
156
|
+
expected output of the kernel. Input arguments are replaced with None.
|
|
157
|
+
|
|
158
|
+
.. code:: python
|
|
159
|
+
|
|
160
|
+
answer = [a+b, None, None] # the order matches the arguments (in args) to the kernel
|
|
161
|
+
tune_kernel("vector_add", kernel_string, size, args, tune_params, answer=answer)
|
|
162
|
+
|
|
163
|
+
Contribution guide
|
|
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:
|
|
187
|
+
|
|
188
|
+
* Ben van Werkhoven
|
|
189
|
+
* Berend Weel
|
|
190
|
+
|
|
191
|
+
Citation
|
|
192
|
+
--------
|
|
193
|
+
A scientific paper about the Kernel Tuner is in preparation, in the meantime please cite the Kernel Tuner as follows:
|
|
194
|
+
|
|
195
|
+
.. code:: latex
|
|
196
|
+
|
|
197
|
+
@misc{
|
|
198
|
+
author = {Ben van Werkhoven},
|
|
199
|
+
title = {Kernel Tuner: A simple CUDA/OpenCL Kernel Tuner in Python},
|
|
200
|
+
year = {2017}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
Related work
|
|
204
|
+
------------
|
|
205
|
+
|
|
206
|
+
You may also like `CLTune <https://github.com/CNugteren/CLTune>`__ by
|
|
207
|
+
Cedric Nugteren. CLTune is a C++ library for kernel tuning and supports
|
|
208
|
+
various advanced features like machine learning to optimize the time
|
|
209
|
+
spent on tuning kernels.
|
|
210
|
+
|
|
211
|
+
.. |Build Status| image:: https://api.travis-ci.org/benvanwerkhoven/kernel_tuner.svg?branch=master
|
|
212
|
+
:target: https://travis-ci.org/benvanwerkhoven/kernel_tuner
|
|
213
|
+
.. |Codacy Badge| image:: https://api.codacy.com/project/badge/grade/016dc85044ab4d57b777449d93275608
|
|
214
|
+
:target: https://www.codacy.com/app/b-vanwerkhoven/kernel_tuner
|
|
215
|
+
.. |Codacy Badge2| image:: https://api.codacy.com/project/badge/coverage/016dc85044ab4d57b777449d93275608
|
|
216
|
+
:target: https://www.codacy.com/app/b-vanwerkhoven/kernel_tuner
|
|
217
|
+
|
|
218
|
+
Keywords: auto-tuning gpu computing pycuda cuda pyopencl opencl
|
|
219
|
+
Platform: UNKNOWN
|
|
220
|
+
Classifier: Environment :: Console
|
|
221
|
+
Classifier: Intended Audience :: Developers
|
|
222
|
+
Classifier: Intended Audience :: Science/Research
|
|
223
|
+
Classifier: Intended Audience :: Education
|
|
224
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
225
|
+
Classifier: Natural Language :: English
|
|
226
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
227
|
+
Classifier: Programming Language :: Python :: 2.7
|
|
228
|
+
Classifier: Programming Language :: Python :: 3.5
|
|
229
|
+
Classifier: Topic :: Scientific/Engineering
|
|
230
|
+
Classifier: Topic :: Software Development
|
|
231
|
+
Classifier: Topic :: System :: Distributed Computing
|
|
232
|
+
Classifier: Development Status :: 4 - Beta
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
A simple CUDA/OpenCL kernel tuner in Python
|
|
2
|
+
===========================================
|
|
3
|
+
|
|
4
|
+
|Build Status| |Codacy Badge| |Codacy Badge2|
|
|
5
|
+
|
|
6
|
+
The goal of this project is to provide a - as simple as possible - tool
|
|
7
|
+
for tuning CUDA and OpenCL kernels. This implies that any CUDA or OpenCL
|
|
8
|
+
kernel can be tuned without requiring extensive changes to the original
|
|
9
|
+
kernel code.
|
|
10
|
+
|
|
11
|
+
A very common problem in GPU programming is that some combination of
|
|
12
|
+
thread block dimensions and other kernel parameters, like tiling or
|
|
13
|
+
unrolling factors, results in dramatically better performance than other
|
|
14
|
+
kernel configurations. The goal of auto-tuning is to automate the
|
|
15
|
+
process of finding the best performing configuration for a given device.
|
|
16
|
+
|
|
17
|
+
This kernel tuner aims that you can directly use the tuned kernel
|
|
18
|
+
without introducing any new dependencies. The tuned kernels can
|
|
19
|
+
afterwards be used independently of the programming environment, whether
|
|
20
|
+
that is using C/C++/Java/Fortran or Python doesn't matter.
|
|
21
|
+
|
|
22
|
+
The kernel\_tuner module currently only contains main one function which
|
|
23
|
+
is called tune\_kernel to which you pass at least the kernel name, a
|
|
24
|
+
string containing the kernel code, the problem size, a list of kernel
|
|
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>`__.
|
|
29
|
+
|
|
30
|
+
Documentation
|
|
31
|
+
-------------
|
|
32
|
+
|
|
33
|
+
The full documentation is available
|
|
34
|
+
`here <http://benvanwerkhoven.github.io/kernel_tuner/index.html>`__.
|
|
35
|
+
|
|
36
|
+
Installation
|
|
37
|
+
------------
|
|
38
|
+
|
|
39
|
+
To install from PyPi:
|
|
40
|
+
|
|
41
|
+
- ``pip install kernel_tuner``
|
|
42
|
+
|
|
43
|
+
To install from the source (and get the tutorial and examples):
|
|
44
|
+
|
|
45
|
+
- clone the repository
|
|
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
|
|
51
|
+
|
|
52
|
+
- ``cd kernel_tuner``
|
|
53
|
+
|
|
54
|
+
- install using
|
|
55
|
+
|
|
56
|
+
- ``pip install .``
|
|
57
|
+
|
|
58
|
+
Dependencies
|
|
59
|
+
------------
|
|
60
|
+
Python 2.7 or Python 3.5
|
|
61
|
+
|
|
62
|
+
PyCuda and/or PyOpenCL (https://mathema.tician.de/software/)
|
|
63
|
+
|
|
64
|
+
- To tune CUDA kernels
|
|
65
|
+
|
|
66
|
+
- Make sure you have the `CUDA Toolkit <https://developer.nvidia.com/cuda-toolkit>`_ installed
|
|
67
|
+
- You can install PyCuda using ``pip install pycuda``
|
|
68
|
+
|
|
69
|
+
- To tune OpenCL kernels
|
|
70
|
+
|
|
71
|
+
- Make sure you have an OpenCL compiler for your intended OpenCL platform
|
|
72
|
+
- You can install PyOpenCL using ``pip install pyopencl``
|
|
73
|
+
|
|
74
|
+
Example usage
|
|
75
|
+
-------------
|
|
76
|
+
|
|
77
|
+
The following shows a simple example for tuning a CUDA kernel:
|
|
78
|
+
|
|
79
|
+
.. code:: python
|
|
80
|
+
|
|
81
|
+
kernel_string = """
|
|
82
|
+
__global__ void vector_add(float *c, float *a, float *b, int n) {
|
|
83
|
+
int i = blockIdx.x * block_size_x + threadIdx.x;
|
|
84
|
+
if (i<n) {
|
|
85
|
+
c[i] = a[i] + b[i];
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
"""
|
|
89
|
+
|
|
90
|
+
size = 10000000
|
|
91
|
+
|
|
92
|
+
a = numpy.random.randn(size).astype(numpy.float32)
|
|
93
|
+
b = numpy.random.randn(size).astype(numpy.float32)
|
|
94
|
+
c = numpy.zeros_like(b)
|
|
95
|
+
n = numpy.int32(size)
|
|
96
|
+
args = [c, a, b, n]
|
|
97
|
+
|
|
98
|
+
tune_params = dict()
|
|
99
|
+
tune_params["block_size_x"] = [128+64*i for i in range(15)]
|
|
100
|
+
|
|
101
|
+
tune_kernel("vector_add", kernel_string, size, args, tune_params)
|
|
102
|
+
|
|
103
|
+
The exact same Python code can be used to tune an OpenCL kernel:
|
|
104
|
+
|
|
105
|
+
.. code:: python
|
|
106
|
+
|
|
107
|
+
kernel_string = """
|
|
108
|
+
__kernel void vector_add(__global float *c, __global float *a, __global float *b, int n) {
|
|
109
|
+
int i = get_global_id(0);
|
|
110
|
+
if (i<n) {
|
|
111
|
+
c[i] = a[i] + b[i];
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
"""
|
|
115
|
+
|
|
116
|
+
Or even just a C function, see the example
|
|
117
|
+
`here <https://github.com/benvanwerkhoven/kernel_tuner/blob/master/examples/c/vector_add.py>`__.
|
|
118
|
+
|
|
119
|
+
You can find these and many - more extensive - example codes, in the
|
|
120
|
+
`examples <https://github.com/benvanwerkhoven/kernel_tuner/blob/master/examples/>`__
|
|
121
|
+
directory.
|
|
122
|
+
|
|
123
|
+
See the `full
|
|
124
|
+
documentation <http://benvanwerkhoven.github.io/kernel_tuner/index.html>`__
|
|
125
|
+
for several highly detailed tutorial-style explanations of example
|
|
126
|
+
kernels and the scripts to tune them.
|
|
127
|
+
|
|
128
|
+
Tuning host and kernel code
|
|
129
|
+
---------------------------
|
|
130
|
+
|
|
131
|
+
It is also possible to tune for combinations of tunable parameters in
|
|
132
|
+
both host and kernel code. This allows for a number of powerfull things,
|
|
133
|
+
such as tuning the number of streams for a kernel that uses CUDA Streams
|
|
134
|
+
or OpenCL Command Queues to overlap transfers between host and device
|
|
135
|
+
with kernel execution. This can be done in combination with tuning the
|
|
136
|
+
parameters inside the kernel code. See the `convolution\_streams example
|
|
137
|
+
code <https://github.com/benvanwerkhoven/kernel_tuner/blob/master/examples/>`__
|
|
138
|
+
and the
|
|
139
|
+
`documentation <http://benvanwerkhoven.github.io/kernel_tuner/hostcode.html>`__
|
|
140
|
+
for a detailed explanation of the kernel tuner Python script.
|
|
141
|
+
|
|
142
|
+
Correctness verification
|
|
143
|
+
------------------------
|
|
144
|
+
|
|
145
|
+
Optionally, you can let the kernel tuner verify the output of every
|
|
146
|
+
kernel it compiles and benchmarks, by passing an ``answer`` list. This
|
|
147
|
+
list matches the list of arguments to the kernel, but contains the
|
|
148
|
+
expected output of the kernel. Input arguments are replaced with None.
|
|
149
|
+
|
|
150
|
+
.. code:: python
|
|
151
|
+
|
|
152
|
+
answer = [a+b, None, None] # the order matches the arguments (in args) to the kernel
|
|
153
|
+
tune_kernel("vector_add", kernel_string, size, args, tune_params, answer=answer)
|
|
154
|
+
|
|
155
|
+
Contribution guide
|
|
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:
|
|
179
|
+
|
|
180
|
+
* Ben van Werkhoven
|
|
181
|
+
* Berend Weel
|
|
182
|
+
|
|
183
|
+
Citation
|
|
184
|
+
--------
|
|
185
|
+
A scientific paper about the Kernel Tuner is in preparation, in the meantime please cite the Kernel Tuner as follows:
|
|
186
|
+
|
|
187
|
+
.. code:: latex
|
|
188
|
+
|
|
189
|
+
@misc{
|
|
190
|
+
author = {Ben van Werkhoven},
|
|
191
|
+
title = {Kernel Tuner: A simple CUDA/OpenCL Kernel Tuner in Python},
|
|
192
|
+
year = {2017}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
Related work
|
|
196
|
+
------------
|
|
197
|
+
|
|
198
|
+
You may also like `CLTune <https://github.com/CNugteren/CLTune>`__ by
|
|
199
|
+
Cedric Nugteren. CLTune is a C++ library for kernel tuning and supports
|
|
200
|
+
various advanced features like machine learning to optimize the time
|
|
201
|
+
spent on tuning kernels.
|
|
202
|
+
|
|
203
|
+
.. |Build Status| image:: https://api.travis-ci.org/benvanwerkhoven/kernel_tuner.svg?branch=master
|
|
204
|
+
:target: https://travis-ci.org/benvanwerkhoven/kernel_tuner
|
|
205
|
+
.. |Codacy Badge| image:: https://api.codacy.com/project/badge/grade/016dc85044ab4d57b777449d93275608
|
|
206
|
+
:target: https://www.codacy.com/app/b-vanwerkhoven/kernel_tuner
|
|
207
|
+
.. |Codacy Badge2| image:: https://api.codacy.com/project/badge/coverage/016dc85044ab4d57b777449d93275608
|
|
208
|
+
:target: https://www.codacy.com/app/b-vanwerkhoven/kernel_tuner
|
|
@@ -2,14 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
import numpy
|
|
4
4
|
import ctypes as C
|
|
5
|
+
import _ctypes
|
|
5
6
|
import subprocess
|
|
6
7
|
import os
|
|
7
8
|
import errno
|
|
8
9
|
|
|
9
10
|
import numpy.ctypeslib
|
|
10
|
-
|
|
11
11
|
from kernel_tuner.util import get_temp_filename, delete_temp_file
|
|
12
12
|
|
|
13
|
+
import logging
|
|
14
|
+
|
|
13
15
|
class CFunctions(object):
|
|
14
16
|
"""Class that groups the code for running and compiling C functions"""
|
|
15
17
|
|
|
@@ -22,6 +24,7 @@ class CFunctions(object):
|
|
|
22
24
|
self.ITERATIONS = iterations
|
|
23
25
|
self.max_threads = 1024
|
|
24
26
|
self.compiler_options = compiler_options
|
|
27
|
+
self.lib = None
|
|
25
28
|
|
|
26
29
|
#test if nvcc is available, otherwise use gcc
|
|
27
30
|
self.compiler = "nvcc"
|
|
@@ -85,6 +88,11 @@ class CFunctions(object):
|
|
|
85
88
|
:returns: An ctypes function that can be called directly.
|
|
86
89
|
:rtype: ctypes._FuncPtr
|
|
87
90
|
"""
|
|
91
|
+
logging.debug('compiling ' + kernel_name)
|
|
92
|
+
|
|
93
|
+
if self.lib != None:
|
|
94
|
+
self.cleanup_lib()
|
|
95
|
+
|
|
88
96
|
filename = get_temp_filename()
|
|
89
97
|
source_file = filename+".cc"
|
|
90
98
|
kernel_string = "extern \"C\" {\n" + kernel_string + "\n}"
|
|
@@ -96,8 +104,6 @@ class CFunctions(object):
|
|
|
96
104
|
if self.compiler == "nvcc":
|
|
97
105
|
source_file = source_file[:-1] + "u"
|
|
98
106
|
compiler_options = ["-Xcompiler=" + c for c in compiler_options]
|
|
99
|
-
#might be better to have an optional argument to pass the desired compute capability
|
|
100
|
-
compiler_options += ["-arch=compute_52"]
|
|
101
107
|
|
|
102
108
|
if self.compiler_options:
|
|
103
109
|
compiler_options += self.compiler_options
|
|
@@ -115,13 +121,14 @@ class CFunctions(object):
|
|
|
115
121
|
|
|
116
122
|
self.lib = numpy.ctypeslib.load_library(filename, '.')
|
|
117
123
|
|
|
124
|
+
func = getattr(self.lib, kernel_name)
|
|
125
|
+
func.restype = C.c_float
|
|
126
|
+
|
|
118
127
|
finally:
|
|
119
128
|
delete_temp_file(source_file)
|
|
120
129
|
delete_temp_file(filename+".o")
|
|
121
130
|
delete_temp_file(filename+".so")
|
|
122
131
|
|
|
123
|
-
func = getattr(self.lib, kernel_name)
|
|
124
|
-
func.restype = C.c_float
|
|
125
132
|
|
|
126
133
|
return func
|
|
127
134
|
|
|
@@ -189,7 +196,19 @@ class CFunctions(object):
|
|
|
189
196
|
:returns: A robust average of values returned by the C function.
|
|
190
197
|
:rtype: float
|
|
191
198
|
"""
|
|
192
|
-
|
|
199
|
+
time = func(*c_args)
|
|
200
|
+
|
|
201
|
+
#I would like to replace the following with actually capturing
|
|
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")
|
|
210
|
+
|
|
211
|
+
return time
|
|
193
212
|
|
|
194
213
|
|
|
195
214
|
def memset(self, allocation, value, size):
|
|
@@ -219,3 +238,6 @@ class CFunctions(object):
|
|
|
219
238
|
dest[:] = numpy.ctypeslib.as_array(src, shape=self.arg_mapping[str(src)])
|
|
220
239
|
|
|
221
240
|
|
|
241
|
+
def cleanup_lib(self):
|
|
242
|
+
""" unload the previously loaded shared library """
|
|
243
|
+
_ctypes.dlclose(self.lib._handle)
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
""" Module for grouping the core functionality needed by most runners """
|
|
2
2
|
from __future__ import print_function
|
|
3
3
|
|
|
4
|
+
import resource
|
|
5
|
+
import logging
|
|
6
|
+
|
|
4
7
|
from kernel_tuner.cuda import CudaFunctions
|
|
5
8
|
from kernel_tuner.opencl import OpenCLFunctions
|
|
6
9
|
from kernel_tuner.c import CFunctions
|
|
@@ -19,6 +22,8 @@ def get_device_interface(lang, device, platform, compiler_options=None):
|
|
|
19
22
|
|
|
20
23
|
def check_kernel_correctness(dev, func, gpu_args, threads, grid, answer, params, verbose, atol=1e-6):
|
|
21
24
|
"""runs the kernel once and checks the result against answer"""
|
|
25
|
+
logging.debug('check_kernel_correctness')
|
|
26
|
+
|
|
22
27
|
for result, expected in zip(gpu_args, answer):
|
|
23
28
|
if expected is not None:
|
|
24
29
|
dev.memset(result, 0, expected.nbytes)
|
|
@@ -27,8 +32,10 @@ def check_kernel_correctness(dev, func, gpu_args, threads, grid, answer, params,
|
|
|
27
32
|
except Exception as e:
|
|
28
33
|
if "too many resources requested for launch" in str(e) or "OUT_OF_RESOURCES" in str(e):
|
|
29
34
|
#ignore this error for now, it will show up when benchmarking the kernel
|
|
35
|
+
logging.debug('correctness check ignores runtime failure due to too many resources required')
|
|
30
36
|
return True
|
|
31
37
|
else:
|
|
38
|
+
logging.debug('correctness check encountered runtime failure: ' + str(e))
|
|
32
39
|
raise e
|
|
33
40
|
correct = True
|
|
34
41
|
for result,expected in zip(gpu_args,answer):
|
|
@@ -45,12 +52,15 @@ def check_kernel_correctness(dev, func, gpu_args, threads, grid, answer, params,
|
|
|
45
52
|
print("Expected:")
|
|
46
53
|
print(expected)
|
|
47
54
|
correct = correct and output_test
|
|
55
|
+
del result_host
|
|
48
56
|
if not correct:
|
|
57
|
+
logging.debug('correctness check has found a correctness issue')
|
|
49
58
|
raise Exception("Error: " + get_config_string(params) + " failed correctness check")
|
|
50
59
|
return correct
|
|
51
60
|
|
|
52
61
|
def compile_kernel(dev, kernel_name, kernel_string, params, grid, instance_string, verbose):
|
|
53
62
|
"""compile the kernel for this specific instance"""
|
|
63
|
+
logging.debug('compile_kernel ' + instance_string)
|
|
54
64
|
|
|
55
65
|
#prepare kernel_string for compilation
|
|
56
66
|
name, kernel_string = setup_kernel_strings(kernel_name, kernel_string, params, grid, instance_string)
|
|
@@ -64,15 +74,21 @@ def compile_kernel(dev, kernel_name, kernel_string, params, grid, instance_strin
|
|
|
64
74
|
#much shared memory for example, the desired behavior is to simply
|
|
65
75
|
#skip over this configuration and try the next one
|
|
66
76
|
if "uses too much shared data" in str(e):
|
|
77
|
+
logging.debug('compile_kernel failed due to kernel using too much shared memory')
|
|
67
78
|
if verbose:
|
|
68
79
|
print("skipping config", instance_string, "reason: too much shared memory used")
|
|
69
80
|
else:
|
|
81
|
+
logging.debug('compile_kernel failed due to error: ' + str(e))
|
|
70
82
|
print("Error while compiling:", instance_string)
|
|
71
83
|
raise e
|
|
72
84
|
return func
|
|
73
85
|
|
|
74
86
|
def benchmark(dev, func, gpu_args, threads, grid, instance_string, verbose):
|
|
75
87
|
"""benchmark the kernel instance"""
|
|
88
|
+
logging.debug('benchmark ' + instance_string)
|
|
89
|
+
logging.debug('thread block dimensions x,y,z=%d,%d,%d', *threads)
|
|
90
|
+
logging.debug('grid dimensions x,y,z=%d,%d,%d', *grid)
|
|
91
|
+
|
|
76
92
|
time = None
|
|
77
93
|
try:
|
|
78
94
|
time = dev.benchmark(func, gpu_args, threads, grid)
|
|
@@ -82,18 +98,23 @@ def benchmark(dev, func, gpu_args, threads, grid, instance_string, verbose):
|
|
|
82
98
|
#the desired behavior is to simply skip over this configuration
|
|
83
99
|
#and proceed to try the next one
|
|
84
100
|
if "too many resources requested for launch" in str(e) or "OUT_OF_RESOURCES" in str(e):
|
|
101
|
+
logging.debug('benchmark fails due to runtime failure too many resources required')
|
|
85
102
|
if verbose:
|
|
86
103
|
print("skipping config", instance_string, "reason: too many resources requested for launch")
|
|
87
104
|
else:
|
|
105
|
+
logging.debug('benchmark encountered runtime failure: ' + str(e))
|
|
88
106
|
print("Error while benchmarking:", instance_string)
|
|
89
107
|
raise e
|
|
90
108
|
return time
|
|
91
109
|
|
|
92
110
|
def compile_and_benchmark(dev, gpu_args, kernel_name, original_kernel, params,
|
|
93
|
-
problem_size, grid_div_y, grid_div_x, cmem_args, answer, atol, instance_string, verbose):
|
|
111
|
+
problem_size, grid_div_z, grid_div_y, grid_div_x, cmem_args, answer, atol, instance_string, verbose):
|
|
112
|
+
|
|
113
|
+
logging.debug('compile_and_benchmark ' + instance_string)
|
|
114
|
+
logging.debug('Memory usage : %2.2f MB', round(resource.getrusage(resource.RUSAGE_SELF).ru_maxrss/1024.0,1) )
|
|
94
115
|
|
|
95
116
|
#setup thread block and grid dimensions
|
|
96
|
-
threads, grid = setup_block_and_grid(dev, problem_size, grid_div_y, grid_div_x, params, instance_string, verbose)
|
|
117
|
+
threads, grid = setup_block_and_grid(dev, problem_size, grid_div_z, grid_div_y, grid_div_x, params, instance_string, verbose)
|
|
97
118
|
if threads is None:
|
|
98
119
|
return None
|
|
99
120
|
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
"""This module contains all CUDA specific kernel_tuner functions"""
|
|
2
|
+
from __future__ import print_function
|
|
2
3
|
import numpy
|
|
4
|
+
import logging
|
|
3
5
|
|
|
4
6
|
#embedded in try block to be able to generate documentation
|
|
5
7
|
#and run tests without pycuda installed
|
|
@@ -41,7 +43,7 @@ class CudaFunctions(object):
|
|
|
41
43
|
self.ITERATIONS = iterations
|
|
42
44
|
self.current_module = None
|
|
43
45
|
self.compiler_options = compiler_options or []
|
|
44
|
-
|
|
46
|
+
print("Using: " + str(self.context.get_device().name()))
|
|
45
47
|
|
|
46
48
|
def __del__(self):
|
|
47
49
|
if hasattr(self, 'context'):
|
|
@@ -154,8 +156,15 @@ class CudaFunctions(object):
|
|
|
154
156
|
to be numpy objects, such as numpy.ndarray or numpy.int32, and so on.
|
|
155
157
|
:type cmem_args: dict( string: numpy.ndarray, ... )
|
|
156
158
|
"""
|
|
159
|
+
logging.debug('copy_constant_memory_args called')
|
|
160
|
+
logging.debug('current module: ' + str(self.current_module))
|
|
157
161
|
for k,v in cmem_args.items():
|
|
158
162
|
symbol = self.current_module.get_global(k)[0]
|
|
163
|
+
logging.debug('copying to symbol: ' + str(symbol))
|
|
164
|
+
logging.debug('array to be copied: ')
|
|
165
|
+
logging.debug(v.nbytes)
|
|
166
|
+
logging.debug(v.dtype)
|
|
167
|
+
logging.debug(v.flags)
|
|
159
168
|
drv.memcpy_htod(symbol, v)
|
|
160
169
|
|
|
161
170
|
def run_kernel(self, func, gpu_args, threads, grid):
|