kernel-tuner 1.1.2__tar.gz → 1.2.0__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 (102) hide show
  1. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/PKG-INFO +22 -20
  2. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/README.md +1 -1
  3. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/kernel_tuner/__init__.py +1 -1
  4. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/kernel_tuner/backends/backend.py +21 -5
  5. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/kernel_tuner/backends/compiler.py +25 -42
  6. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/kernel_tuner/backends/hip.py +18 -13
  7. kernel_tuner-1.2.0/kernel_tuner/backends/hypertuner.py +131 -0
  8. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/kernel_tuner/backends/pycuda.py +4 -1
  9. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/kernel_tuner/core.py +91 -131
  10. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/kernel_tuner/file_utils.py +73 -23
  11. kernel_tuner-1.2.0/kernel_tuner/hyper.py +98 -0
  12. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/kernel_tuner/integration.py +3 -0
  13. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/kernel_tuner/interface.py +158 -11
  14. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/kernel_tuner/runners/sequential.py +1 -1
  15. kernel_tuner-1.2.0/kernel_tuner/schema/T1/1.0.0/input-schema.json +412 -0
  16. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/kernel_tuner/searchspace.py +131 -46
  17. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/kernel_tuner/strategies/bayes_opt.py +85 -42
  18. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/kernel_tuner/strategies/brute_force.py +3 -0
  19. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/kernel_tuner/strategies/common.py +29 -15
  20. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/kernel_tuner/strategies/diff_evo.py +2 -3
  21. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/kernel_tuner/strategies/firefly_algorithm.py +6 -6
  22. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/kernel_tuner/strategies/genetic_algorithm.py +2 -0
  23. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/kernel_tuner/strategies/greedy_ils.py +1 -1
  24. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/kernel_tuner/strategies/greedy_mls.py +4 -2
  25. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/kernel_tuner/strategies/hillclimbers.py +4 -2
  26. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/kernel_tuner/strategies/pso.py +4 -2
  27. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/kernel_tuner/strategies/random_sample.py +2 -2
  28. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/kernel_tuner/strategies/simulated_annealing.py +19 -12
  29. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/kernel_tuner/util.py +236 -227
  30. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/kernel_tuner/utils/directives.py +142 -17
  31. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/pyproject.toml +54 -54
  32. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/test/context.py +7 -0
  33. kernel_tuner-1.2.0/test/convolution.cu +166 -0
  34. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/test/strategies/test_bayesian_optimization.py +1 -1
  35. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/test/strategies/test_common.py +8 -3
  36. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/test/strategies/test_strategies.py +20 -1
  37. kernel_tuner-1.2.0/test/test_T1_input.json +133 -0
  38. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/test/test_compiler_functions.py +35 -131
  39. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/test/test_core.py +2 -1
  40. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/test/test_file_utils.py +8 -1
  41. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/test/test_runners.py +11 -0
  42. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/test/test_searchspace.py +28 -0
  43. kernel_tuner-1.2.0/test/test_time_budgets.py +79 -0
  44. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/test/test_util_functions.py +81 -32
  45. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/test/utils/test_directives.py +48 -2
  46. kernel_tuner-1.1.2/kernel_tuner/hyper.py +0 -89
  47. kernel_tuner-1.1.2/test/test_hyper.py +0 -18
  48. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/LICENSE +0 -0
  49. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/kernel_tuner/accuracy.py +0 -0
  50. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/kernel_tuner/backends/__init__.py +0 -0
  51. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/kernel_tuner/backends/cupy.py +0 -0
  52. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/kernel_tuner/backends/nvcuda.py +0 -0
  53. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/kernel_tuner/backends/opencl.py +0 -0
  54. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/kernel_tuner/energy/__init__.py +0 -0
  55. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/kernel_tuner/energy/energy.py +0 -0
  56. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/kernel_tuner/kernelbuilder.py +0 -0
  57. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/kernel_tuner/observers/__init__.py +0 -0
  58. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/kernel_tuner/observers/compiler.py +0 -0
  59. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/kernel_tuner/observers/cupy.py +0 -0
  60. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/kernel_tuner/observers/hip.py +0 -0
  61. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/kernel_tuner/observers/ncu.py +0 -0
  62. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/kernel_tuner/observers/nvcuda.py +0 -0
  63. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/kernel_tuner/observers/nvml.py +0 -0
  64. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/kernel_tuner/observers/observer.py +0 -0
  65. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/kernel_tuner/observers/opencl.py +0 -0
  66. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/kernel_tuner/observers/pmt.py +0 -0
  67. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/kernel_tuner/observers/powersensor.py +0 -0
  68. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/kernel_tuner/observers/pycuda.py +0 -0
  69. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/kernel_tuner/observers/register.py +0 -0
  70. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/kernel_tuner/observers/tegra.py +0 -0
  71. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/kernel_tuner/runners/__init__.py +0 -0
  72. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/kernel_tuner/runners/runner.py +0 -0
  73. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/kernel_tuner/runners/simulation.py +0 -0
  74. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/kernel_tuner/schema/T4/1.0.0/metadata-schema.json +0 -0
  75. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/kernel_tuner/schema/T4/1.0.0/results-schema.json +0 -0
  76. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/kernel_tuner/strategies/__init__.py +0 -0
  77. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/kernel_tuner/strategies/basinhopping.py +0 -0
  78. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/kernel_tuner/strategies/dual_annealing.py +0 -0
  79. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/kernel_tuner/strategies/minimize.py +0 -0
  80. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/kernel_tuner/strategies/mls.py +0 -0
  81. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/kernel_tuner/strategies/ordered_greedy_mls.py +0 -0
  82. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/kernel_tuner/utils/__init__.py +0 -0
  83. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/test/__init__.py +0 -0
  84. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/test/strategies/test_genetic_algorithm.py +0 -0
  85. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/test/synthetic_fp32_cache_NVIDIA_RTX_A4000.json +0 -0
  86. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/test/test_accuracy.py +0 -0
  87. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/test/test_backend.py +0 -0
  88. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/test/test_cache_file.json +0 -0
  89. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/test/test_common.py +0 -0
  90. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/test/test_cuda_functions.py +0 -0
  91. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/test/test_cupy_functions.py +0 -0
  92. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/test/test_energy.py +0 -0
  93. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/test/test_hip_functions.py +0 -0
  94. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/test/test_integration.py +0 -0
  95. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/test/test_kernelbuilder.py +0 -0
  96. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/test/test_nvml_mocked.py +0 -0
  97. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/test/test_observers.py +0 -0
  98. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/test/test_opencl_functions.py +0 -0
  99. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/test/test_pycuda_functions.py +0 -0
  100. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/test/test_pycuda_mocked.py +0 -0
  101. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/test/test_toml_file.py +0 -0
  102. {kernel_tuner-1.1.2 → kernel_tuner-1.2.0}/test/utils/__init__.py +0 -0
@@ -1,15 +1,15 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: kernel_tuner
3
- Version: 1.1.2
3
+ Version: 1.2.0
4
4
  Summary: An easy to use CUDA/OpenCL kernel tuner in Python
5
5
  License: Apache-2.0
6
6
  Keywords: auto-tuning,gpu,computing,pycuda,cuda,pyopencl,opencl
7
7
  Author: Ben van Werkhoven
8
8
  Author-email: b.vanwerkhoven@esciencecenter.nl
9
- Requires-Python: >=3.9,<4
10
- Classifier: Development Status :: 5 - Production/Stable
9
+ Requires-Python: >=3.10,<4
11
10
  Classifier: Environment :: Console
12
11
  Classifier: Environment :: GPU
12
+ Classifier: Development Status :: 5 - Production/Stable
13
13
  Classifier: Intended Audience :: Developers
14
14
  Classifier: Intended Audience :: Education
15
15
  Classifier: Intended Audience :: Science/Research
@@ -17,39 +17,41 @@ Classifier: License :: OSI Approved :: Apache Software License
17
17
  Classifier: Natural Language :: English
18
18
  Classifier: Operating System :: MacOS :: MacOS X
19
19
  Classifier: Operating System :: POSIX :: Linux
20
- Classifier: Programming Language :: Python :: 3
21
- Classifier: Programming Language :: Python :: 3.9
20
+ Classifier: Topic :: Scientific/Engineering
21
+ Classifier: Topic :: Software Development
22
+ Classifier: Topic :: System :: Distributed Computing
22
23
  Classifier: Programming Language :: Python :: 3.10
23
24
  Classifier: Programming Language :: Python :: 3.11
24
25
  Classifier: Programming Language :: Python :: 3.12
25
26
  Classifier: Programming Language :: Python :: 3.13
26
- Classifier: Topic :: Scientific/Engineering
27
- Classifier: Topic :: Software Development
28
- Classifier: Topic :: System :: Distributed Computing
29
27
  Provides-Extra: cuda
30
28
  Provides-Extra: cuda-opencl
31
29
  Provides-Extra: hip
32
30
  Provides-Extra: opencl
33
31
  Provides-Extra: tutorial
34
- Requires-Dist: hip-python (>=6.3.3.540.31,<7.0.0.0.0) ; extra == "hip"
32
+ Requires-Dist: hip-python ; extra == "hip"
35
33
  Requires-Dist: jsonschema
36
- Requires-Dist: jupyter (>=1.0.0,<2.0.0) ; extra == "tutorial"
37
- Requires-Dist: matplotlib (>=3.5.0,<4.0.0) ; extra == "tutorial"
38
- Requires-Dist: numpy (>=2.0.0,<3.0.0)
39
- Requires-Dist: nvidia-ml-py (>=12.535.108,<13.0.0) ; extra == "cuda" or extra == "tutorial"
34
+ Requires-Dist: jupyter (>=1.0.0) ; extra == "tutorial"
35
+ Requires-Dist: matplotlib (>=3.5.0) ; extra == "tutorial"
36
+ Requires-Dist: numpy (>=2.0.0)
37
+ Requires-Dist: nvidia-ml-py (>=12.535.108) ; extra == "cuda"
38
+ Requires-Dist: nvidia-ml-py (>=12.535.108) ; extra == "tutorial"
40
39
  Requires-Dist: packaging
41
40
  Requires-Dist: pandas (>=2.0.0)
42
- Requires-Dist: pycuda (>=2024.1,<2025.0) ; extra == "cuda" or extra == "cuda-opencl"
43
- Requires-Dist: pynvml (>=11.4.1,<12.0.0) ; extra == "cuda"
44
- Requires-Dist: pyopencl ; extra == "opencl" or extra == "cuda-opencl"
45
- Requires-Dist: python-constraint2 (>=2.1.0,<3.0.0)
41
+ Requires-Dist: pycuda (>=2024.1) ; extra == "cuda-opencl"
42
+ Requires-Dist: pycuda (>=2025.1) ; extra == "cuda"
43
+ Requires-Dist: pynvml (>=11.4.1) ; extra == "cuda"
44
+ Requires-Dist: pyopencl ; extra == "cuda-opencl"
45
+ Requires-Dist: pyopencl ; extra == "opencl"
46
+ Requires-Dist: python-constraint2 (>=2.3.1)
46
47
  Requires-Dist: scikit-learn (>=1.0.2)
47
- Requires-Dist: scipy (>=1.11.0)
48
+ Requires-Dist: scipy (>=1.14.1)
48
49
  Requires-Dist: xmltodict
49
50
  Project-URL: Documentation, https://KernelTuner.github.io/kernel_tuner/
50
51
  Project-URL: Homepage, https://KernelTuner.github.io/kernel_tuner/
51
52
  Project-URL: Repository, https://github.com/KernelTuner/kernel_tuner
52
- Project-URL: Tracker, https://github.com/KernelTuner/kernel_tuner/issues
53
+ Project-URL: changelog, https://github.com/KernelTuner/kernel_tuner/blob/master/CHANGELOG.md
54
+ Project-URL: issues, https://github.com/KernelTuner/kernel_tuner/issues
53
55
  Description-Content-Type: text/markdown
54
56
 
55
57
 
@@ -70,7 +72,7 @@ Description-Content-Type: text/markdown
70
72
 
71
73
 
72
74
  Create optimized GPU applications in any mainstream GPU
73
- programming language (CUDA, HIP, OpenCL, OpenACC).
75
+ programming language (CUDA, HIP, OpenCL, OpenACC, OpenMP).
74
76
 
75
77
  What Kernel Tuner does:
76
78
 
@@ -16,7 +16,7 @@
16
16
 
17
17
 
18
18
  Create optimized GPU applications in any mainstream GPU
19
- programming language (CUDA, HIP, OpenCL, OpenACC).
19
+ programming language (CUDA, HIP, OpenCL, OpenACC, OpenMP).
20
20
 
21
21
  What Kernel Tuner does:
22
22
 
@@ -1,5 +1,5 @@
1
1
  from kernel_tuner.integration import store_results, create_device_targets
2
- from kernel_tuner.interface import tune_kernel, run_kernel
2
+ from kernel_tuner.interface import tune_kernel, tune_kernel_T1, run_kernel
3
3
 
4
4
  from importlib.metadata import version
5
5
 
@@ -1,16 +1,16 @@
1
- """This module contains the interface of all kernel_tuner backends"""
1
+ """This module contains the interface of all kernel_tuner backends."""
2
2
  from __future__ import print_function
3
3
 
4
4
  from abc import ABC, abstractmethod
5
5
 
6
6
 
7
7
  class Backend(ABC):
8
- """Base class for kernel_tuner backends"""
8
+ """Base class for kernel_tuner backends."""
9
9
 
10
10
  @abstractmethod
11
11
  def ready_argument_list(self, arguments):
12
12
  """This method must implement the allocation of the arguments on device memory."""
13
- pass
13
+ return arguments
14
14
 
15
15
  @abstractmethod
16
16
  def compile(self, kernel_instance):
@@ -57,9 +57,14 @@ class Backend(ABC):
57
57
  """This method must implement a host to device copy."""
58
58
  pass
59
59
 
60
+ @abstractmethod
61
+ def refresh_memory(self, device_memory, host_arguments, should_sync):
62
+ """This method must implement refreshing the device memory with a clean copy."""
63
+ pass
64
+
60
65
 
61
66
  class GPUBackend(Backend):
62
- """Base class for GPU backends"""
67
+ """Base class for GPU backends."""
63
68
 
64
69
  @abstractmethod
65
70
  def __init__(self, device, iterations, compiler_options, observers):
@@ -80,10 +85,21 @@ class GPUBackend(Backend):
80
85
  """This method must implement the allocation and copy of texture memory to the GPU."""
81
86
  pass
82
87
 
88
+ def refresh_memory(self, gpu_memory, host_arguments, should_sync):
89
+ """Refresh the GPU memory with the untouched host arguments."""
90
+ for i, arg in enumerate(host_arguments):
91
+ if should_sync[i]:
92
+ self.memcpy_htod(gpu_memory[i], arg)
93
+
83
94
 
84
95
  class CompilerBackend(Backend):
85
- """Base class for compiler backends"""
96
+ """Base class for compiler backends."""
86
97
 
87
98
  @abstractmethod
88
99
  def __init__(self, iterations, compiler_options, compiler):
89
100
  pass
101
+
102
+ @abstractmethod
103
+ def cleanup_lib(self):
104
+ """Unload the previously loaded shared library"""
105
+ pass
@@ -34,7 +34,7 @@ except ImportError:
34
34
  try:
35
35
  from hip._util.types import DeviceArray
36
36
  except ImportError:
37
- Pointer = Exception # using Exception here as a type that will never be among kernel arguments
37
+ Pointer = Exception # using Exception here as a type that will never be among kernel arguments
38
38
  DeviceArray = Exception
39
39
 
40
40
 
@@ -93,8 +93,12 @@ class CompilerFunctions(CompilerBackend):
93
93
  :param iterations: Number of iterations used while benchmarking a kernel, 7 by default.
94
94
  :type iterations: int
95
95
  """
96
+ # allocations contains a clean copy of the memory
97
+ self.allocations = []
96
98
  self.observers = observers or []
97
99
  self.observers.append(CompilerRuntimeObserver(self))
100
+ for obs in self.observers:
101
+ obs.register_device(self)
98
102
 
99
103
  self.iterations = iterations
100
104
  self.max_threads = 1024
@@ -104,7 +108,6 @@ class CompilerFunctions(CompilerBackend):
104
108
  self.lib = None
105
109
  self.using_openmp = False
106
110
  self.using_openacc = False
107
- self.observers = [CompilerRuntimeObserver(self)]
108
111
  self.last_result = None
109
112
 
110
113
  if self.compiler == "g++":
@@ -157,30 +160,24 @@ class CompilerFunctions(CompilerBackend):
157
160
 
158
161
  for i, arg in enumerate(arguments):
159
162
  if not (isinstance(arg, (np.ndarray, np.number, DeviceArray)) or is_cupy_array(arg)):
160
- raise TypeError(f"Argument is not numpy or cupy ndarray or numpy scalar or HIP Python DeviceArray but a {type(arg)}")
163
+ raise TypeError(
164
+ f"Argument is not numpy or cupy ndarray or numpy scalar or HIP Python DeviceArray but a {type(arg)}"
165
+ )
161
166
  dtype_str = arg.typestr if isinstance(arg, DeviceArray) else str(arg.dtype)
162
167
  if isinstance(arg, np.ndarray):
163
168
  if dtype_str in dtype_map.keys():
164
- # In numpy <= 1.15, ndarray.ctypes.data_as does not itself keep a reference
165
- # to its underlying array, so we need to store a reference to arg.copy()
166
- # in the Argument object manually to avoid it being deleted.
167
- # (This changed in numpy > 1.15.)
168
- # data_ctypes = data.ctypes.data_as(C.POINTER(dtype_map[dtype_str]))
169
169
  data_ctypes = arg.ctypes.data_as(C.POINTER(dtype_map[dtype_str]))
170
- numpy_arg = arg
171
170
  else:
172
171
  raise TypeError("unknown dtype for ndarray")
173
172
  elif isinstance(arg, np.generic):
174
173
  data_ctypes = dtype_map[dtype_str](arg)
175
- numpy_arg = arg
176
174
  elif is_cupy_array(arg):
177
175
  data_ctypes = C.c_void_p(arg.data.ptr)
178
- numpy_arg = arg
179
176
  elif isinstance(arg, DeviceArray):
180
177
  data_ctypes = arg.as_c_void_p()
181
- numpy_arg = None
182
178
 
183
- ctype_args[i] = Argument(numpy=numpy_arg, ctypes=data_ctypes)
179
+ ctype_args[i] = Argument(numpy=arg, ctypes=data_ctypes)
180
+ self.allocations.append(Argument(numpy=arg.copy(), ctypes=data_ctypes))
184
181
  return ctype_args
185
182
 
186
183
  def compile(self, kernel_instance):
@@ -204,16 +201,13 @@ class CompilerFunctions(CompilerBackend):
204
201
  compiler_options = ["-fPIC"]
205
202
 
206
203
  # detect openmp
207
- if "#include <omp.h>" in kernel_string or "use omp_lib" in kernel_string:
204
+ if "#pragma omp" in kernel_string or "!$omp" in kernel_string:
208
205
  logging.debug("set using_openmp to true")
209
206
  self.using_openmp = True
210
- if self.compiler in ["nvc", "nvc++", "nvfortran"]:
211
- compiler_options.append("-mp")
212
- else:
213
- compiler_options.append("-fopenmp")
214
207
 
215
208
  # detect openacc
216
209
  if "#pragma acc" in kernel_string or "!$acc" in kernel_string:
210
+ logging.debug("set using_openacc to true")
217
211
  self.using_openacc = True
218
212
 
219
213
  # if filename is known, use that one
@@ -288,7 +282,7 @@ class CompilerFunctions(CompilerBackend):
288
282
  stdout=subprocess.PIPE,
289
283
  stderr=subprocess.PIPE,
290
284
  text=True,
291
- check=True
285
+ check=True,
292
286
  )
293
287
 
294
288
  subprocess.run(
@@ -299,7 +293,7 @@ class CompilerFunctions(CompilerBackend):
299
293
  stdout=subprocess.PIPE,
300
294
  stderr=subprocess.PIPE,
301
295
  text=True,
302
- check=True
296
+ check=True,
303
297
  )
304
298
 
305
299
  self.lib = np.ctypeslib.load_library(filename, ".")
@@ -390,7 +384,8 @@ class CompilerFunctions(CompilerBackend):
390
384
  C.memset(allocation.ctypes, value, size)
391
385
 
392
386
  def memcpy_dtoh(self, dest, src):
393
- """a simple memcpy copying from an Argument to a numpy array
387
+ """This method implements the semantic of a device to host copy for the Compiler backend.
388
+ There is no actual copy from device to host happening, but host to host.
394
389
 
395
390
  :param dest: A numpy or cupy array to store the data
396
391
  :type dest: np.ndarray or cupy.ndarray
@@ -404,6 +399,7 @@ class CompilerFunctions(CompilerBackend):
404
399
  # This is because DeviceArray manages its own memory and donesn't need
405
400
  # explicit copies like numpy arrays do
406
401
  return
402
+ # there is no real copy from device to host, but host to host
407
403
  if isinstance(dest, np.ndarray) and is_cupy_array(src.numpy):
408
404
  # Implicit conversion to a NumPy array is not allowed.
409
405
  value = src.numpy.get()
@@ -413,33 +409,20 @@ class CompilerFunctions(CompilerBackend):
413
409
  dest[:] = xp.asarray(value)
414
410
 
415
411
  def memcpy_htod(self, dest, src):
416
- """a simple memcpy copying from a numpy array to an Argument
417
-
418
- :param dest: An Argument for some memory allocation
419
- :type dest: Argument
412
+ """There is no memcpy_htod implemented for the compiler backend."""
413
+ pass
420
414
 
421
- :param src: A numpy or cupy array containing the source data
422
- :type src: np.ndarray or cupy.ndarray
423
- """
424
- # If src.numpy is None, it means we're dealing with a HIP Python DeviceArray
425
- if dest.numpy is None:
426
- # Skip memory copies for HIP Python DeviceArray
427
- # This is because DeviceArray manages its own memory and donesn't need
428
- # explicit copies like numpy arrays do
429
- return
430
- if isinstance(dest.numpy, np.ndarray) and is_cupy_array(src):
431
- # Implicit conversion to a NumPy array is not allowed.
432
- value = src.get()
433
- else:
434
- value = src
435
- xp = get_array_module(dest.numpy)
436
- dest.numpy[:] = xp.asarray(value)
415
+ def refresh_memory(self, _, arguments, should_sync):
416
+ """Copy the preserved content of the output memory to used arrays."""
417
+ for i, arg in enumerate(arguments):
418
+ if should_sync[i]:
419
+ self.memcpy_dtoh(arg, self.allocations[i])
437
420
 
438
421
  def cleanup_lib(self):
439
422
  """unload the previously loaded shared library"""
440
423
  if self.lib is None:
441
424
  return
442
-
425
+
443
426
  if not self.using_openmp and not self.using_openacc:
444
427
  # this if statement is necessary because shared libraries that use
445
428
  # OpenMP will core dump when unloaded, this is a well-known issue with OpenMP
@@ -19,7 +19,6 @@ dtype_map = {
19
19
  "bool": ctypes.c_bool,
20
20
  "int8": ctypes.c_int8,
21
21
  "int16": ctypes.c_int16,
22
- "float16": ctypes.c_int16,
23
22
  "int32": ctypes.c_int32,
24
23
  "int64": ctypes.c_int64,
25
24
  "uint8": ctypes.c_uint8,
@@ -40,7 +39,9 @@ def hip_check(call_result):
40
39
  if len(result) == 1:
41
40
  result = result[0]
42
41
  if isinstance(err, hip.hipError_t) and err != hip.hipError_t.hipSuccess:
43
- raise RuntimeError(str(err))
42
+ _, error_name = hip.hipGetErrorName(err)
43
+ _, error_str = hip.hipGetErrorString(err)
44
+ raise RuntimeError(f"{error_name}: {error_str}")
44
45
  return result
45
46
 
46
47
 
@@ -120,25 +121,29 @@ class HipFunctions(GPUBackend):
120
121
 
121
122
  # Handle numpy arrays
122
123
  if isinstance(arg, np.ndarray):
123
- if dtype_str in dtype_map.keys():
124
- # Allocate device memory
125
- device_ptr = hip_check(hip.hipMalloc(arg.nbytes))
124
+ # Allocate device memory
125
+ device_ptr = hip_check(hip.hipMalloc(arg.nbytes))
126
126
 
127
- # Copy data to device using hipMemcpy
128
- hip_check(hip.hipMemcpy(device_ptr, arg, arg.nbytes, hip.hipMemcpyKind.hipMemcpyHostToDevice))
127
+ # Copy data to device using hipMemcpy
128
+ hip_check(hip.hipMemcpy(device_ptr, arg, arg.nbytes, hip.hipMemcpyKind.hipMemcpyHostToDevice))
129
129
 
130
- prepared_args.append(device_ptr)
131
- else:
132
- raise TypeError(f"Unknown dtype {dtype_str} for ndarray")
130
+ prepared_args.append(device_ptr)
133
131
 
134
132
  # Handle numpy scalar types
135
133
  elif isinstance(arg, np.generic):
136
134
  # Convert numpy scalar to corresponding ctypes
137
- ctype_arg = dtype_map[dtype_str](arg)
138
- prepared_args.append(ctype_arg)
135
+ if dtype_str in dtype_map:
136
+ ctype_arg = dtype_map[dtype_str](arg)
137
+ prepared_args.append(ctype_arg)
138
+ # 16-bit float is not supported, view it as uint16
139
+ elif dtype_str in ("float16", "bfloat16"):
140
+ ctype_arg = ctypes.c_uint16(arg.view(np.uint16))
141
+ prepared_args.append(ctype_arg)
142
+ else:
143
+ raise ValueError(f"Invalid argument type {dtype_str}: {arg}")
139
144
 
140
145
  else:
141
- raise ValueError(f"Invalid argument type {type(arg)}, {arg}")
146
+ raise ValueError(f"Invalid argument type {type(arg)}: {arg}")
142
147
 
143
148
  return prepared_args
144
149
 
@@ -0,0 +1,131 @@
1
+ """This module contains a 'device' for hyperparameter tuning using the autotuning methodology."""
2
+
3
+ import platform
4
+ from pathlib import Path
5
+
6
+ from numpy import mean
7
+
8
+ from kernel_tuner.backends.backend import Backend
9
+ from kernel_tuner.observers.observer import BenchmarkObserver
10
+
11
+ try:
12
+ methodology_available = True
13
+ from autotuning_methodology.experiments import generate_experiment_file
14
+ from autotuning_methodology.report_experiments import get_strategy_scores
15
+ except ImportError:
16
+ methodology_available = False
17
+
18
+
19
+ class ScoreObserver(BenchmarkObserver):
20
+ def __init__(self, dev):
21
+ self.dev = dev
22
+ self.scores = []
23
+
24
+ def after_finish(self):
25
+ self.scores.append(self.dev.last_score)
26
+
27
+ def get_results(self):
28
+ results = {'score': mean(self.scores), 'scores': self.scores.copy()}
29
+ self.scores = []
30
+ return results
31
+
32
+ class HypertunerFunctions(Backend):
33
+ """Class for executing hyperparameter tuning."""
34
+ units = {}
35
+
36
+ def __init__(self, iterations):
37
+ self.iterations = iterations
38
+ self.observers = [ScoreObserver(self)]
39
+ self.name = platform.processor()
40
+ self.max_threads = 1024
41
+ self.last_score = None
42
+
43
+ # set the environment options
44
+ env = dict()
45
+ env["iterations"] = self.iterations
46
+ self.env = env
47
+
48
+ # check for the methodology package
49
+ if methodology_available is not True:
50
+ raise ImportError("Unable to import the autotuning methodology, run `pip install autotuning_methodology`.")
51
+
52
+ def ready_argument_list(self, arguments):
53
+ arglist = super().ready_argument_list(arguments)
54
+ if arglist is None:
55
+ arglist = []
56
+ return arglist
57
+
58
+ def compile(self, kernel_instance):
59
+ super().compile(kernel_instance)
60
+ path = Path(__file__).parent.parent.parent / "hyperparamtuning"
61
+ path.mkdir(exist_ok=True)
62
+
63
+ # TODO get applications & GPUs args from benchmark
64
+ gpus = ["RTX_3090", "RTX_2080_Ti"]
65
+ applications = None
66
+ # applications = [
67
+ # {
68
+ # "name": "convolution",
69
+ # "folder": "./cached_data_used/kernels",
70
+ # "input_file": "convolution.json"
71
+ # },
72
+ # {
73
+ # "name": "pnpoly",
74
+ # "folder": "./cached_data_used/kernels",
75
+ # "input_file": "pnpoly.json"
76
+ # }
77
+ # ]
78
+
79
+ # strategy settings
80
+ strategy: str = kernel_instance.arguments[0]
81
+ hyperparams = [{'name': k, 'value': v} for k, v in kernel_instance.params.items()]
82
+ hyperparams_string = "_".join(f"{k}={str(v)}" for k, v in kernel_instance.params.items())
83
+ searchspace_strategies = [{
84
+ "autotuner": "KernelTuner",
85
+ "name": f"{strategy.lower()}_{hyperparams_string}",
86
+ "display_name": strategy.replace('_', ' ').capitalize(),
87
+ "search_method": strategy.lower(),
88
+ 'search_method_hyperparameters': hyperparams
89
+ }]
90
+
91
+ # any additional settings
92
+ override = {
93
+ "experimental_groups_defaults": {
94
+ "samples": self.iterations
95
+ }
96
+ }
97
+
98
+ name = kernel_instance.name if len(kernel_instance.name) > 0 else kernel_instance.kernel_source.kernel_name
99
+ experiments_filepath = generate_experiment_file(name, path, searchspace_strategies, applications, gpus,
100
+ override=override, overwrite_existing_file=True)
101
+ return str(experiments_filepath)
102
+
103
+ def start_event(self):
104
+ return super().start_event()
105
+
106
+ def stop_event(self):
107
+ return super().stop_event()
108
+
109
+ def kernel_finished(self):
110
+ super().kernel_finished()
111
+ return True
112
+
113
+ def synchronize(self):
114
+ return super().synchronize()
115
+
116
+ def run_kernel(self, func, gpu_args=None, threads=None, grid=None, stream=None):
117
+ # generate the experiments file
118
+ experiments_filepath = Path(func)
119
+
120
+ # run the methodology to get a fitness score for this configuration
121
+ scores = get_strategy_scores(str(experiments_filepath))
122
+ self.last_score = scores[list(scores.keys())[0]]['score']
123
+
124
+ def memset(self, allocation, value, size):
125
+ return super().memset(allocation, value, size)
126
+
127
+ def memcpy_dtoh(self, dest, src):
128
+ return super().memcpy_dtoh(dest, src)
129
+
130
+ def memcpy_htod(self, dest, src):
131
+ return super().memcpy_htod(dest, src)
@@ -106,7 +106,7 @@ class PyCudaFunctions(GPUBackend):
106
106
  )
107
107
  if cc == "00":
108
108
  cc = self.context.get_device().compute_capability()
109
- self.cc = str(cc[0]) + str(cc[1])
109
+ self.cc = str(cc)
110
110
  self.iterations = iterations
111
111
  self.current_module = None
112
112
  self.func = None
@@ -180,6 +180,9 @@ class PyCudaFunctions(GPUBackend):
180
180
  # pycuda does not support bool, convert to uint8 instead
181
181
  elif isinstance(arg, np.bool_):
182
182
  gpu_args.append(arg.astype(np.uint8))
183
+ # pycuda does not support 16-bit formats, view them as uint16
184
+ elif isinstance(arg, np.generic) and str(arg.dtype) in ("float16", "bfloat16"):
185
+ gpu_args.append(arg.view(np.uint16))
183
186
  # if not an array, just pass argument along
184
187
  else:
185
188
  gpu_args.append(arg)