kernel-tuner 0.1.0b0__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.
Files changed (29) hide show
  1. kernel_tuner-0.1.0b0/LICENSE +14 -0
  2. kernel_tuner-0.1.0b0/MANIFEST.in +4 -0
  3. kernel_tuner-0.1.0b0/PKG-INFO +136 -0
  4. kernel_tuner-0.1.0b0/README.md +134 -0
  5. kernel_tuner-0.1.0b0/kernel_tuner/__init__.py +3 -0
  6. kernel_tuner-0.1.0b0/kernel_tuner/c.py +217 -0
  7. kernel_tuner-0.1.0b0/kernel_tuner/core.py +131 -0
  8. kernel_tuner-0.1.0b0/kernel_tuner/cuda.py +200 -0
  9. kernel_tuner-0.1.0b0/kernel_tuner/interface.py +381 -0
  10. kernel_tuner-0.1.0b0/kernel_tuner/opencl.py +165 -0
  11. kernel_tuner-0.1.0b0/kernel_tuner/runners/__init__.py +0 -0
  12. kernel_tuner-0.1.0b0/kernel_tuner/runners/random_sample.py +104 -0
  13. kernel_tuner-0.1.0b0/kernel_tuner/runners/sequential_brute_force.py +93 -0
  14. kernel_tuner-0.1.0b0/kernel_tuner/util.py +198 -0
  15. kernel_tuner-0.1.0b0/kernel_tuner.egg-info/PKG-INFO +136 -0
  16. kernel_tuner-0.1.0b0/kernel_tuner.egg-info/SOURCES.txt +28 -0
  17. kernel_tuner-0.1.0b0/kernel_tuner.egg-info/dependency_links.txt +1 -0
  18. kernel_tuner-0.1.0b0/kernel_tuner.egg-info/requires.txt +5 -0
  19. kernel_tuner-0.1.0b0/kernel_tuner.egg-info/top_level.txt +1 -0
  20. kernel_tuner-0.1.0b0/requirements.txt +6 -0
  21. kernel_tuner-0.1.0b0/setup.cfg +8 -0
  22. kernel_tuner-0.1.0b0/setup.py +39 -0
  23. kernel_tuner-0.1.0b0/test/test_c_functions.py +127 -0
  24. kernel_tuner-0.1.0b0/test/test_cuda_functions.py +82 -0
  25. kernel_tuner-0.1.0b0/test/test_cuda_mocked.py +98 -0
  26. kernel_tuner-0.1.0b0/test/test_interface.py +135 -0
  27. kernel_tuner-0.1.0b0/test/test_kernel_tuner.py +260 -0
  28. kernel_tuner-0.1.0b0/test/test_opencl_functions.py +74 -0
  29. kernel_tuner-0.1.0b0/test/test_runners.py +28 -0
@@ -0,0 +1,14 @@
1
+ * Copyright 2016 Netherlands eScience Center
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
14
+
@@ -0,0 +1,4 @@
1
+ include setup.py
2
+ include LICENSE
3
+ include README.md
4
+ include requirements.txt
@@ -0,0 +1,136 @@
1
+ Metadata-Version: 1.1
2
+ Name: kernel_tuner
3
+ Version: 0.1.0b0
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:
10
+ A simple CUDA/OpenCL kernel tuner in Python
11
+ ===========================================
12
+
13
+ The goal of this project is to provide a - as simple as possible - tool
14
+ for tuning CUDA and OpenCL kernels. This implies that any CUDA or OpenCL
15
+ kernel can be tuned without requiring extensive changes to the original
16
+ kernel code.
17
+
18
+ A very common problem in GPU programming is that some combination of
19
+ thread block dimensions and other kernel parameters, like tiling or
20
+ unrolling factors, results in dramatically better performance than other
21
+ kernel configurations. The goal of auto-tuning is to automate the
22
+ process of finding the best performing configuration for a given device.
23
+
24
+ This kernel tuner aims that you can directly use the tuned kernel
25
+ without introducing any new dependencies. The tuned kernels can
26
+ afterwards be used independently of the programming environment, whether
27
+ that is using C/C++/Java/Fortran or Python doesn't matter.
28
+
29
+ The kernel_tuner module currently only contains main one function which
30
+ is called tune_kernel to which you pass at least the kernel name, a string
31
+ containing the kernel code, the problem size, a list of kernel function
32
+ arguments, and a dictionary of tunable parameters. There are also a lot
33
+ of optional parameters, for a complete list see the full documentation of
34
+ tune_kernel.
35
+
36
+ Installation
37
+ ------------
38
+ | clone the repository
39
+ | ``git clone git@github.com:benvanwerkhoven/kernel_tuner.git``
40
+ | change into the top-level directory
41
+ | ``cd kernel_tuner``
42
+ | install using
43
+ | ``pip install -r requirements.txt``
44
+ | ``pip install .``
45
+
46
+ Dependencies
47
+ ------------
48
+ * Python 2.7 or Python 3.5
49
+ * PyCuda and/or PyOpenCL (https://mathema.tician.de/software/)
50
+
51
+ Example usage
52
+ -------------
53
+ The following shows a simple example for tuning a CUDA kernel:
54
+
55
+ ::
56
+
57
+ kernel_string = """
58
+ __global__ void vector_add(float *c, float *a, float *b, int n) {
59
+ int i = blockIdx.x * block_size_x + threadIdx.x;
60
+ if (i<n) {
61
+ c[i] = a[i] + b[i];
62
+ }
63
+ }
64
+ """
65
+
66
+ size = 10000000
67
+ problem_size = (size, 1)
68
+
69
+ a = numpy.random.randn(size).astype(numpy.float32)
70
+ b = numpy.random.randn(size).astype(numpy.float32)
71
+ c = numpy.zeros_like(b)
72
+ n = numpy.int32(size)
73
+ args = [c, a, b, n]
74
+
75
+ tune_params = dict()
76
+ tune_params["block_size_x"] = [128+64*i for i in range(15)]
77
+
78
+ tune_kernel("vector_add", kernel_string, problem_size, args, tune_params)
79
+
80
+ The exact same Python code can be used to tune an OpenCL kernel:
81
+
82
+ ::
83
+
84
+ kernel_string = """
85
+ __kernel void vector_add(__global float *c, __global float *a, __global float *b, int n) {
86
+ int i = get_global_id(0);
87
+ if (i<n) {
88
+ c[i] = a[i] + b[i];
89
+ }
90
+ }
91
+ """
92
+
93
+
94
+ Or even just a C function, see the example `here <https://github.com/benvanwerkhoven/kernel_tuner/blob/master/examples/c/vector_add.py>`_.
95
+
96
+ You can find these and many - more extensive - example codes, in the
97
+ `examples <https://github.com/benvanwerkhoven/kernel_tuner/blob/master/examples/>`_
98
+ directory. See the `full documentation <http://benvanwerkhoven.github.io/kernel_tuner/sphinxdoc/html/index.html>`_
99
+ for several highly detailed tutorial-style explanations of example
100
+ kernels and the scripts to tune them.
101
+
102
+ Author
103
+ ------
104
+ Ben van Werkhoven <b.vanwerkhoven@esciencenter.nl>
105
+
106
+ Copyright and License
107
+ ---------------------
108
+ * Copyright 2016 Netherlands eScience Center
109
+
110
+ Licensed under the Apache License, Version 2.0 (the "License");
111
+ you may not use this file except in compliance with the License.
112
+ You may obtain a copy of the License at
113
+
114
+ http://www.apache.org/licenses/LICENSE-2.0
115
+
116
+ Unless required by applicable law or agreed to in writing, software
117
+ distributed under the License is distributed on an "AS IS" BASIS,
118
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
119
+ See the License for the specific language governing permissions and
120
+ limitations under the License.
121
+
122
+ Keywords: auto-tuning gpu computing pycuda cuda pyopencl opencl
123
+ Platform: UNKNOWN
124
+ Classifier: Environment :: Console
125
+ Classifier: Intended Audience :: Developers
126
+ Classifier: Intended Audience :: Science/Research
127
+ Classifier: Intended Audience :: Education
128
+ Classifier: License :: OSI Approved :: Apache Software License
129
+ Classifier: Natural Language :: English
130
+ Classifier: Operating System :: POSIX :: Linux
131
+ Classifier: Programming Language :: Python :: 2.7
132
+ Classifier: Programming Language :: Python :: 3.5
133
+ Classifier: Topic :: Scientific/Engineering
134
+ Classifier: Topic :: Software Development
135
+ Classifier: Topic :: System :: Distributed Computing
136
+ Classifier: Development Status :: 4 - Beta
@@ -0,0 +1,134 @@
1
+
2
+ A simple CUDA/OpenCL kernel tuner in Python
3
+ ====================================
4
+ [![Build Status](https://api.travis-ci.org/benvanwerkhoven/kernel_tuner.svg?branch=master)](https://travis-ci.org/benvanwerkhoven/kernel_tuner)
5
+ [![Codacy Badge](https://api.codacy.com/project/badge/grade/016dc85044ab4d57b777449d93275608)](https://www.codacy.com/app/b-vanwerkhoven/kernel_tuner)
6
+ [![Codacy Badge](https://api.codacy.com/project/badge/coverage/016dc85044ab4d57b777449d93275608)](https://www.codacy.com/app/b-vanwerkhoven/kernel_tuner)
7
+
8
+ The goal of this project is to provide a - as simple as possible - tool
9
+ for tuning CUDA and OpenCL kernels. This implies that any CUDA or OpenCL
10
+ kernel can be tuned without requiring extensive changes to the original
11
+ kernel code.
12
+
13
+ A very common problem in GPU programming is that some combination of
14
+ thread block dimensions and other kernel parameters, like tiling or
15
+ unrolling factors, results in dramatically better performance than other
16
+ kernel configurations. The goal of auto-tuning is to automate the
17
+ process of finding the best performing configuration for a given device.
18
+
19
+ This kernel tuner aims that you can directly use the tuned kernel
20
+ without introducing any new dependencies. The tuned kernels can
21
+ afterwards be used independently of the programming environment, whether
22
+ that is using C/C++/Java/Fortran or Python doesn't matter.
23
+
24
+ The kernel_tuner module currently only contains main one function which
25
+ is called tune_kernel to which you pass at least the kernel name, a string
26
+ containing the kernel code, the problem size, a list of kernel function
27
+ arguments, and a dictionary of tunable parameters. There are also a lot
28
+ of optional parameters, for a complete list see the full documentation of
29
+ [tune_kernel](http://benvanwerkhoven.github.io/kernel_tuner/sphinxdoc/html/details.html).
30
+
31
+ Documentation
32
+ -------------
33
+ The full documentation is available [here](http://benvanwerkhoven.github.io/kernel_tuner/sphinxdoc/html/index.html).
34
+
35
+ Installation
36
+ ------------
37
+ clone the repository
38
+ `git clone git@github.com:benvanwerkhoven/kernel_tuner.git`
39
+ change into the top-level directory
40
+ `cd kernel_tuner`
41
+ install using
42
+ `pip install -r requirements.txt`
43
+ `pip install .`
44
+
45
+ Dependencies
46
+ ------------
47
+ * Python 2.7 or Python 3.5
48
+ * PyCuda and/or PyOpenCL (https://mathema.tician.de/software/)
49
+
50
+ Example usage
51
+ -------------
52
+ The following shows a simple example for tuning a CUDA kernel:
53
+
54
+ ```python
55
+ kernel_string = """
56
+ __global__ void vector_add(float *c, float *a, float *b, int n) {
57
+ int i = blockIdx.x * block_size_x + threadIdx.x;
58
+ if (i<n) {
59
+ c[i] = a[i] + b[i];
60
+ }
61
+ }
62
+ """
63
+
64
+ size = 10000000
65
+ problem_size = (size, 1)
66
+
67
+ a = numpy.random.randn(size).astype(numpy.float32)
68
+ b = numpy.random.randn(size).astype(numpy.float32)
69
+ c = numpy.zeros_like(b)
70
+ n = numpy.int32(size)
71
+ args = [c, a, b, n]
72
+
73
+ tune_params = dict()
74
+ tune_params["block_size_x"] = [128+64*i for i in range(15)]
75
+
76
+ tune_kernel("vector_add", kernel_string, problem_size, args, tune_params)
77
+ ```
78
+ The exact same Python code can be used to tune an OpenCL kernel:
79
+ ```python
80
+ kernel_string = """
81
+ __kernel void vector_add(__global float *c, __global float *a, __global float *b, int n) {
82
+ int i = get_global_id(0);
83
+ if (i<n) {
84
+ c[i] = a[i] + b[i];
85
+ }
86
+ }
87
+ """
88
+ ```
89
+ Or even just a C function, see the example [here](https://github.com/benvanwerkhoven/kernel_tuner/blob/master/examples/c/vector_add.py).
90
+
91
+ You can find these and many - more extensive - example codes, in the [examples](https://github.com/benvanwerkhoven/kernel_tuner/blob/master/examples/) directory.
92
+ See the [full documentation](http://benvanwerkhoven.github.io/kernel_tuner/sphinxdoc/html/index.html) for several highly detailed tutorial-style explanations of example kernels and the scripts to tune them.
93
+
94
+ Tuning host and kernel code
95
+ ---------------------------
96
+ It is also possible to tune for combinations of tunable parameters in both host and kernel code. This allows for a number of powerfull things, such as tuning the number of streams for a kernel that uses CUDA Streams or OpenCL Command Queues to overlap transfers between host and device with kernel execution. This can be done in combination with tuning the parameters inside the kernel code. See the [convolution_streams example code](https://github.com/benvanwerkhoven/kernel_tuner/blob/master/examples/) and the [documentation](http://benvanwerkhoven.github.io/kernel_tuner/sphinxdoc/html/hostcode.html) for a detailed explanation of the kernel tuner Python script.
97
+
98
+ Correctness verification
99
+ ------------------------
100
+ Optionally, you can let the kernel tuner verify the output of every kernel it compiles and benchmarks,
101
+ by passing an `answer` list. This list matches the list of arguments to the kernel, but contains the expected output of the kernel. Input arguments are replaced with None.
102
+ ```python
103
+ answer = [a+b, None, None] # the order matches the arguments (in args) to the kernel
104
+ tune_kernel("vector_add", kernel_string, problem_size, args, tune_params, answer=answer)
105
+ ```
106
+
107
+ Contribution guide
108
+ ------------------
109
+ The kernel tuner follows the Google Python style guide, with Sphinxdoc docstrings for module public functions. If you want to
110
+ contribute to the project please fork it, create a branch including your addition, and create a pull request.
111
+
112
+ The tests use relative imports and can be run directly after making
113
+ changes to the code. To run all tests use `nosetests` in the main directory.
114
+ To run the examples after code changes, you need to run `pip install --upgrade .` in the main directory.
115
+ Documentation is generated by typing `make html` in the doc directory, the contents
116
+ of `doc/build/html/` should then be copied to `sphinxdoc` directory of the `gh-pages` branch.
117
+
118
+ Before creating a pull request please ensure the following:
119
+ * You have written unit tests to test your additions
120
+ * All unit tests pass
121
+ * The examples still work and produce the same (or better) results
122
+ * The code is compatible with both Python 2.7 and Python 3.5
123
+ * An entry about the change or addition is created in CHANGELOG.md
124
+
125
+ Contributing authors so far:
126
+ * Ben van Werkhoven
127
+ * Berend Weel
128
+
129
+ Related work
130
+ ------------
131
+ You may also like [CLTune](https://github.com/CNugteren/CLTune) by Cedric
132
+ Nugteren. CLTune is a C++ library for kernel tuning and supports various
133
+ advanced features like machine learning to optimize the time spent on tuning
134
+ kernels.
@@ -0,0 +1,3 @@
1
+
2
+
3
+ from kernel_tuner.interface import tune_kernel, run_kernel
@@ -0,0 +1,217 @@
1
+ """ This module contains the functionality for running and compiling C functions """
2
+
3
+ import numpy
4
+ import ctypes as C
5
+ import subprocess
6
+ import os
7
+ import errno
8
+
9
+ import numpy.ctypeslib
10
+
11
+ from kernel_tuner.util import get_temp_filename, delete_temp_file
12
+
13
+ class CFunctions(object):
14
+ """Class that groups the code for running and compiling C functions"""
15
+
16
+ def __init__(self, iterations=7):
17
+ """instantiate CFunctions object used for interacting with C code
18
+
19
+ :param iterations: Number of iterations used while benchmarking a kernel, 7 by default.
20
+ :type iterations: int
21
+ """
22
+ self.ITERATIONS = iterations
23
+ self.max_threads = 1024
24
+
25
+ #test if nvcc is available, otherwise use gcc
26
+ self.compiler = "nvcc"
27
+ try:
28
+ subprocess.check_call([self.compiler, "--version"], stdout=open(os.devnull, 'w'))
29
+ except OSError as e:
30
+ self.compiler = "gcc"
31
+ if e.errno != errno.ENOENT:
32
+ raise e
33
+
34
+ def ready_argument_list(self, arguments):
35
+ """ready argument list to be passed to the C function
36
+
37
+ :param arguments: List of arguments to be passed to the C function.
38
+ The order should match the argument list on the C function.
39
+ Allowed values are numpy.ndarray, and/or numpy.int32, numpy.float32, and so on.
40
+ :type arguments: list(numpy objects)
41
+
42
+ :returns: A list of arguments that can be passed to the C function.
43
+ :rtype: list()
44
+ """
45
+ self.arg_mapping = dict()
46
+ ctype_args = []
47
+ for arg in arguments:
48
+ if isinstance(arg, numpy.ndarray):
49
+ if arg.dtype == 'float32':
50
+ ctype_args.append(arg.ctypes.data_as(C.POINTER(C.c_float)))
51
+ elif arg.dtype == 'float64':
52
+ ctype_args.append(arg.ctypes.data_as(C.POINTER(C.c_double)))
53
+ elif arg.dtype == 'int32':
54
+ ctype_args.append(arg.ctypes.data_as(C.POINTER(C.c_int)))
55
+ else:
56
+ raise TypeError("unknown dtype for ndarray")
57
+ self.arg_mapping[str(ctype_args[-1])] = arg.shape
58
+ elif numpy.isscalar(arg):
59
+ if hasattr(arg, 'dtype'):
60
+ if str(arg.dtype).startswith('int'):
61
+ ctype_args.append(int(arg))
62
+ elif str(arg.dtype).startswith('float'):
63
+ ctype_args.append(float(arg))
64
+ else:
65
+ raise TypeError("Argument is scalar with a dtype, but does not start with int or float")
66
+ else:
67
+ ctype_args.append(arg)
68
+ else:
69
+ raise TypeError("Argument is not a numpy.ndarray and is not a scalar %s" % type(arg))
70
+
71
+ return ctype_args
72
+
73
+
74
+ def compile(self, kernel_name, kernel_string):
75
+ """call the C compiler to compile the kernel, return the function
76
+
77
+ :param kernel_name: The name of the kernel to be compiled, used to lookup the
78
+ function after compilation.
79
+ :type kernel_name: string
80
+
81
+ :param kernel_string: The C code that contains the function `kernel_name`
82
+ :type kernel_string: string
83
+
84
+ :returns: An ctypes function that can be called directly.
85
+ :rtype: ctypes._FuncPtr
86
+ """
87
+ filename = get_temp_filename()
88
+ source_file = filename+".cc"
89
+ kernel_string = "extern \"C\" {\n" + kernel_string + "\n}"
90
+
91
+ compiler_options = ["-fPIC"]
92
+ if "#include <omp.h>" in kernel_string:
93
+ compiler_options.append("-fopenmp")
94
+
95
+ if self.compiler == "nvcc":
96
+ source_file = source_file[:-1] + "u"
97
+ compiler_options = ["-Xcompiler=" + c for c in compiler_options]
98
+ #might be better to have an optional argument to pass the desired compute capability
99
+ compiler_options += ["-arch=compute_52"]
100
+
101
+ lib_args = []
102
+ if "CL/cl.h" in kernel_string:
103
+ lib_args = ["-lOpenCL"]
104
+
105
+ try:
106
+ with open(source_file, 'w') as f:
107
+ f.write(kernel_string)
108
+
109
+ subprocess.check_call([self.compiler, "-c", source_file] + compiler_options + ["-o", filename+".o"])
110
+ subprocess.check_call([self.compiler, filename+".o"] + compiler_options + [ "-shared", "-o", filename+".so"] + lib_args)
111
+
112
+ self.lib = numpy.ctypeslib.load_library(filename, '.')
113
+
114
+ finally:
115
+ delete_temp_file(source_file)
116
+ delete_temp_file(filename+".o")
117
+ delete_temp_file(filename+".so")
118
+
119
+ func = getattr(self.lib, kernel_name)
120
+ func.restype = C.c_float
121
+
122
+ return func
123
+
124
+ def benchmark(self, func, c_args, threads, grid):
125
+ """runs the kernel repeatedly, returns averaged returned value
126
+
127
+ The C function tuning is a little bit more flexible than direct CUDA
128
+ or OpenCL kernel tuning. The C function needs to measure time, or some
129
+ other quality metric you wish to tune on, on its own and should
130
+ therefore return a single floating-point value.
131
+
132
+ Benchmark runs the C function repeatedly and returns the average of the
133
+ values returned by the C function. The number of iterations is set
134
+ during the creation of the CFunctions object. For all measurements the
135
+ lowest and highest values are discarded and the rest is included in the
136
+ average. The reason for this is to be robust against initialization
137
+ artifacts and other exceptional cases.
138
+
139
+ :param func: A C function compiled for this specific configuration
140
+ :type func: ctypes._FuncPtr
141
+
142
+ :param c_args: A list of arguments to the function, order should match the
143
+ order in the code. The list should be prepared using
144
+ ready_argument_list().
145
+ :type c_args: list()
146
+
147
+ :param threads: Ignored, but left as argument for now to have the same
148
+ interface as CudaFunctions and OpenCLFunctions.
149
+ :type threads: any
150
+
151
+ :param grid: Ignored, but left as argument for now to have the same
152
+ interface as CudaFunctions and OpenCLFunctions.
153
+ :type grid: any
154
+
155
+ :returns: A robust average of values returned by the C function.
156
+ :rtype: float
157
+ """
158
+ results = []
159
+ for _ in range(self.ITERATIONS):
160
+ value = self.run_kernel(func, c_args, threads, grid)
161
+ results.append(value)
162
+ results = sorted(results)
163
+ return numpy.mean(results[1:-1])
164
+
165
+
166
+ def run_kernel(self, func, c_args, threads, grid):
167
+ """runs the kernel once, returns whatever the kernel returns
168
+
169
+ :param func: A C function compiled for this specific configuration
170
+ :type func: ctypes._FuncPtr
171
+
172
+ :param c_args: A list of arguments to the function, order should match the
173
+ order in the code. The list should be prepared using
174
+ ready_argument_list().
175
+ :type c_args: list()
176
+
177
+ :param threads: Ignored, but left as argument for now to have the same
178
+ interface as CudaFunctions and OpenCLFunctions.
179
+ :type threads: any
180
+
181
+ :param grid: Ignored, but left as argument for now to have the same
182
+ interface as CudaFunctions and OpenCLFunctions.
183
+ :type grid: any
184
+
185
+ :returns: A robust average of values returned by the C function.
186
+ :rtype: float
187
+ """
188
+ return func(*c_args)
189
+
190
+
191
+ def memset(self, allocation, value, size):
192
+ """set the memory in allocation to the value in value
193
+
194
+ :param allocation: A memory allocation unit
195
+ :type allocation: pycuda.driver.DeviceAllocation
196
+
197
+ :param value: The value to set the memory to
198
+ :type value: a single 32-bit float or int
199
+
200
+ :param size: The size of to the allocation unit in bytes
201
+ :type size: int
202
+ """
203
+ C.memset(allocation, value, size)
204
+
205
+
206
+ def memcpy_dtoh(self, dest, src):
207
+ """a simple memcpy expects a ctypes pointer, returns a numpy array
208
+
209
+ :param dest: A numpy array to store the data
210
+ :type dest: numpy.ndarray
211
+
212
+ :param src: A ctypes pointer to some memory allocation
213
+ :type src: ctypes.pointer
214
+ """
215
+ dest[:] = numpy.ctypeslib.as_array(src, shape=self.arg_mapping[str(src)])
216
+
217
+
@@ -0,0 +1,131 @@
1
+ """ Module for grouping the core functionality needed by most runners """
2
+ from __future__ import print_function
3
+
4
+ from kernel_tuner.cuda import CudaFunctions
5
+ from kernel_tuner.opencl import OpenCLFunctions
6
+ from kernel_tuner.c import CFunctions
7
+ from kernel_tuner.util import *
8
+
9
+ def get_device_interface(lang, device, platform):
10
+ if lang == "CUDA":
11
+ dev = CudaFunctions(device)
12
+ elif lang == "OpenCL":
13
+ dev = OpenCLFunctions(device, platform)
14
+ elif lang == "C":
15
+ dev = CFunctions()
16
+ else:
17
+ raise UnImplementedException("Sorry, support for languages other than CUDA, OpenCL, or C is not implemented yet")
18
+ return dev
19
+
20
+ def check_kernel_correctness(dev, func, gpu_args, threads, grid, answer, params, verbose, atol=1e-6):
21
+ """runs the kernel once and checks the result against answer"""
22
+ for result, expected in zip(gpu_args, answer):
23
+ if expected is not None:
24
+ dev.memset(result, 0, expected.nbytes)
25
+ try:
26
+ dev.run_kernel(func, gpu_args, threads, grid)
27
+ except Exception as e:
28
+ if "too many resources requested for launch" in str(e) or "OUT_OF_RESOURCES" in str(e):
29
+ #ignore this error for now, it will show up when benchmarking the kernel
30
+ return True
31
+ else:
32
+ raise e
33
+ correct = True
34
+ for result,expected in zip(gpu_args,answer):
35
+ if expected is not None:
36
+ result_host = numpy.zeros_like(expected)
37
+ dev.memcpy_dtoh(result_host, result)
38
+ output_test = numpy.allclose(result_host.ravel(), expected.ravel(), atol=atol)
39
+ if not output_test and verbose:
40
+ print("Error: " + get_config_string(params) + " detected during correctness check")
41
+ print("Printing kernel output and expected result, set verbose=False to suppress this debug print")
42
+ numpy.set_printoptions(edgeitems=500)
43
+ print("Kernel output:")
44
+ print(result_host)
45
+ print("Expected:")
46
+ print(expected)
47
+ correct = correct and output_test
48
+ if not correct:
49
+ raise Exception("Error: " + get_config_string(params) + " failed correctness check")
50
+ return correct
51
+
52
+ def compile_kernel(dev, kernel_name, kernel_string, params, grid, instance_string, verbose):
53
+ """compile the kernel for this specific instance"""
54
+
55
+ #prepare kernel_string for compilation
56
+ name, kernel_string = setup_kernel_strings(kernel_name, kernel_string, params, grid, instance_string)
57
+
58
+ #compile kernel_string into device func
59
+ func = None
60
+ try:
61
+ func = dev.compile(name, kernel_string)
62
+ except Exception as e:
63
+ #compiles may fail because certain kernel configurations use too
64
+ #much shared memory for example, the desired behavior is to simply
65
+ #skip over this configuration and try the next one
66
+ if "uses too much shared data" in str(e):
67
+ if verbose:
68
+ print("skipping config", instance_string, "reason: too much shared memory used")
69
+ else:
70
+ raise e
71
+ return func
72
+
73
+ def benchmark(dev, func, gpu_args, threads, grid, instance_string, verbose):
74
+ """benchmark the kernel instance"""
75
+ time = None
76
+ try:
77
+ time = dev.benchmark(func, gpu_args, threads, grid)
78
+ except Exception as e:
79
+ #some launches may fail because too many registers are required
80
+ #to run the kernel given the current thread block size
81
+ #the desired behavior is to simply skip over this configuration
82
+ #and proceed to try the next one
83
+ if "too many resources requested for launch" in str(e) or "OUT_OF_RESOURCES" in str(e):
84
+ if verbose:
85
+ print("skipping config", instance_string, "reason: too many resources requested for launch")
86
+ else:
87
+ print("Error while benchmarking:", instance_string)
88
+ raise e
89
+ return time
90
+
91
+ def compile_and_benchmark(dev, gpu_args, kernel_name, original_kernel, params,
92
+ problem_size, grid_div_y, grid_div_x, cmem_args, answer, atol, instance_string, verbose):
93
+
94
+ #setup thread block and grid dimensions
95
+ threads, grid = setup_block_and_grid(dev, problem_size, grid_div_y, grid_div_x, params, instance_string, verbose)
96
+ if threads is None:
97
+ return None
98
+
99
+ temp_files = dict()
100
+
101
+ try:
102
+ #obtain the kernel_string and prepare additional files, if any
103
+ if isinstance(original_kernel, list):
104
+ kernel_string, temp_files = prepare_list_of_files(original_kernel, params, grid)
105
+ else:
106
+ kernel_string = get_kernel_string(original_kernel)
107
+
108
+ #compile the kernel
109
+ func = compile_kernel(dev, kernel_name, kernel_string, params, grid, instance_string, verbose)
110
+ if func is None:
111
+ return None
112
+
113
+ #add constant memory arguments to compiled module
114
+ if cmem_args is not None:
115
+ dev.copy_constant_memory_args(cmem_args)
116
+
117
+ #test kernel for correctness and benchmark
118
+ if answer is not None:
119
+ check_kernel_correctness(dev, func, gpu_args, threads, grid, answer, params, verbose, atol)
120
+
121
+ #benchmark
122
+ time = benchmark(dev, func, gpu_args, threads, grid, instance_string, verbose)
123
+
124
+ #clean up any temporary files
125
+ finally:
126
+ for v in temp_files.values():
127
+ delete_temp_file(v)
128
+
129
+ return time
130
+
131
+