kernel-tuner 1.3.3__tar.gz → 1.5.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 (131) hide show
  1. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/PKG-INFO +9 -4
  2. kernel_tuner-1.5.0/kernel_tuner/__init__.py +22 -0
  3. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/kernel_tuner/accuracy.py +38 -30
  4. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/kernel_tuner/backends/compiler.py +22 -19
  5. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/kernel_tuner/backends/cupy.py +13 -7
  6. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/kernel_tuner/backends/hip/hip.py +48 -5
  7. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/kernel_tuner/backends/hypertuner.py +44 -34
  8. kernel_tuner-1.5.0/kernel_tuner/backends/julia.py +521 -0
  9. kernel_tuner-1.5.0/kernel_tuner/backends/julia_helper.jl +88 -0
  10. kernel_tuner-1.5.0/kernel_tuner/backends/julia_helper.py +134 -0
  11. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/kernel_tuner/backends/nvcuda.py +164 -28
  12. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/kernel_tuner/backends/opencl.py +6 -13
  13. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/kernel_tuner/backends/pycuda.py +11 -20
  14. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/kernel_tuner/core.py +258 -139
  15. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/kernel_tuner/file_utils.py +40 -17
  16. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/kernel_tuner/integration.py +1 -29
  17. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/kernel_tuner/interface.py +263 -87
  18. kernel_tuner-1.5.0/kernel_tuner/observers/amd.py +401 -0
  19. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/kernel_tuner/observers/hip.py +4 -2
  20. kernel_tuner-1.5.0/kernel_tuner/observers/julia.py +130 -0
  21. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/kernel_tuner/observers/nvml.py +91 -24
  22. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/kernel_tuner/observers/pmt.py +10 -5
  23. kernel_tuner-1.5.0/kernel_tuner/runners/parallel.py +405 -0
  24. kernel_tuner-1.5.0/kernel_tuner/runners/runner.py +38 -0
  25. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/kernel_tuner/runners/sequential.py +70 -39
  26. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/kernel_tuner/runners/simulation.py +64 -52
  27. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/kernel_tuner/searchspace.py +21 -20
  28. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/kernel_tuner/strategies/bayes_opt.py +27 -0
  29. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/kernel_tuner/strategies/common.py +114 -68
  30. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/kernel_tuner/strategies/diff_evo.py +4 -4
  31. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/kernel_tuner/strategies/firefly_algorithm.py +7 -6
  32. kernel_tuner-1.5.0/kernel_tuner/strategies/gen_adaptive_tabu_greywolf.py +239 -0
  33. kernel_tuner-1.5.0/kernel_tuner/strategies/gen_hybrid_vndx.py +236 -0
  34. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/kernel_tuner/strategies/genetic_algorithm.py +11 -14
  35. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/kernel_tuner/strategies/greedy_ils.py +2 -3
  36. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/kernel_tuner/strategies/greedy_mls.py +2 -3
  37. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/kernel_tuner/strategies/hillclimbers.py +18 -16
  38. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/kernel_tuner/strategies/pso.py +19 -14
  39. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/kernel_tuner/strategies/pyatf_strategies.py +1 -1
  40. kernel_tuner-1.5.0/kernel_tuner/strategies/pymoo_minimize.py +256 -0
  41. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/kernel_tuner/strategies/random_sample.py +5 -8
  42. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/kernel_tuner/strategies/simulated_annealing.py +1 -1
  43. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/kernel_tuner/util.py +428 -121
  44. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/kernel_tuner/utils/directives.py +93 -93
  45. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/kernel_tuner/utils/nvcuda.py +25 -4
  46. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/pyproject.toml +14 -11
  47. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/test/conftest.py +1 -1
  48. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/test/context.py +38 -21
  49. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/test/strategies/test_bayesian_optimization.py +2 -0
  50. kernel_tuner-1.5.0/test/strategies/test_cache_time_energy.json +48 -0
  51. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/test/strategies/test_common.py +10 -10
  52. kernel_tuner-1.5.0/test/strategies/test_pymoo_strategies.py +36 -0
  53. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/test/strategies/test_strategies.py +5 -4
  54. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/test/test_backend.py +7 -1
  55. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/test/test_cache_file.json +2 -1
  56. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/test/test_cache_file_T1_input.json +2 -2
  57. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/test/test_common.py +14 -6
  58. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/test/test_core.py +38 -74
  59. kernel_tuner-1.5.0/test/test_cuda_functions.py +154 -0
  60. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/test/test_energy.py +2 -2
  61. kernel_tuner-1.5.0/test/test_julia_functions.py +73 -0
  62. kernel_tuner-1.5.0/test/test_lazy_imports.py +47 -0
  63. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/test/test_observers.py +21 -3
  64. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/test/test_runners.py +18 -11
  65. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/test/test_time_budgets.py +6 -3
  66. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/test/test_util_functions.py +169 -78
  67. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/test/utils/nvcuda.py +1 -0
  68. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/test/utils/test_directives.py +3 -8
  69. kernel_tuner-1.3.3/kernel_tuner/__init__.py +0 -6
  70. kernel_tuner-1.3.3/kernel_tuner/runners/runner.py +0 -22
  71. kernel_tuner-1.3.3/test/test_cuda_functions.py +0 -60
  72. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/LICENSE +0 -0
  73. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/README.md +0 -0
  74. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/kernel_tuner/backends/__init__.py +0 -0
  75. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/kernel_tuner/backends/backend.py +0 -0
  76. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/kernel_tuner/backends/hip/__init__.py +0 -0
  77. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/kernel_tuner/backends/hip/util.py +0 -0
  78. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/kernel_tuner/energy/__init__.py +0 -0
  79. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/kernel_tuner/energy/energy.py +0 -0
  80. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/kernel_tuner/hyper.py +0 -0
  81. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/kernel_tuner/kernelbuilder.py +0 -0
  82. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/kernel_tuner/observers/__init__.py +0 -0
  83. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/kernel_tuner/observers/compiler.py +0 -0
  84. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/kernel_tuner/observers/cupy.py +0 -0
  85. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/kernel_tuner/observers/ncu.py +0 -0
  86. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/kernel_tuner/observers/nvcuda.py +0 -0
  87. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/kernel_tuner/observers/observer.py +0 -0
  88. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/kernel_tuner/observers/opencl.py +0 -0
  89. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/kernel_tuner/observers/powersensor.py +0 -0
  90. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/kernel_tuner/observers/pycuda.py +0 -0
  91. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/kernel_tuner/observers/register.py +0 -0
  92. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/kernel_tuner/observers/tegra.py +0 -0
  93. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/kernel_tuner/runners/__init__.py +0 -0
  94. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/kernel_tuner/schema/T1/1.0.0/input-schema.json +0 -0
  95. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/kernel_tuner/schema/T4/1.0.0/metadata-schema.json +0 -0
  96. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/kernel_tuner/schema/T4/1.0.0/results-schema.json +0 -0
  97. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/kernel_tuner/strategies/__init__.py +0 -0
  98. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/kernel_tuner/strategies/basinhopping.py +0 -0
  99. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/kernel_tuner/strategies/brute_force.py +0 -0
  100. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/kernel_tuner/strategies/dual_annealing.py +0 -0
  101. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/kernel_tuner/strategies/minimize.py +0 -0
  102. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/kernel_tuner/strategies/mls.py +0 -0
  103. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/kernel_tuner/strategies/ordered_greedy_mls.py +0 -0
  104. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/kernel_tuner/strategies/skopt.py +0 -0
  105. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/kernel_tuner/strategies/wrapper.py +0 -0
  106. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/kernel_tuner/utils/__init__.py +0 -0
  107. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/test/__init__.py +0 -0
  108. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/test/convolution.cu +0 -0
  109. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/test/strategies/__init__.py +0 -0
  110. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/test/strategies/test_cache_file.json +0 -0
  111. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/test/strategies/test_diff_evo.py +0 -0
  112. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/test/strategies/test_genetic_algorithm.py +0 -0
  113. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/test/synthetic_fp32_cache_NVIDIA_RTX_A4000.json +0 -0
  114. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/test/test_T1_input.json +0 -0
  115. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/test/test_accuracy.py +0 -0
  116. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/test/test_compiler_functions.py +0 -0
  117. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/test/test_cupy_functions.py +0 -0
  118. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/test/test_custom_optimizer.py +0 -0
  119. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/test/test_file_utils.py +0 -0
  120. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/test/test_hip_functions.py +0 -0
  121. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/test/test_hyper.py +0 -0
  122. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/test/test_integration.py +0 -0
  123. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/test/test_kernelbuilder.py +0 -0
  124. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/test/test_nvml_mocked.py +0 -0
  125. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/test/test_opencl_functions.py +0 -0
  126. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/test/test_pycuda_functions.py +0 -0
  127. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/test/test_pycuda_mocked.py +0 -0
  128. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/test/test_searchspace.py +0 -0
  129. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/test/test_toml_file.py +0 -0
  130. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/test/utils/__init__.py +0 -0
  131. {kernel_tuner-1.3.3 → kernel_tuner-1.5.0}/test/vector_add.cu +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kernel_tuner
3
- Version: 1.3.3
3
+ Version: 1.5.0
4
4
  Summary: An easy to use CUDA/OpenCL kernel tuner in Python
5
5
  License-Expression: Apache-2.0
6
6
  License-File: LICENSE
@@ -25,13 +25,19 @@ Classifier: Programming Language :: Python :: 3.10
25
25
  Classifier: Programming Language :: Python :: 3.11
26
26
  Classifier: Programming Language :: Python :: 3.12
27
27
  Classifier: Programming Language :: Python :: 3.13
28
+ Classifier: Programming Language :: Python :: 3.14
28
29
  Provides-Extra: cuda
29
30
  Provides-Extra: cuda-opencl
30
31
  Provides-Extra: hip
32
+ Provides-Extra: julia
31
33
  Provides-Extra: opencl
32
34
  Provides-Extra: tutorial
35
+ Requires-Dist: cuda-python (>=12.6.0) ; extra == "cuda"
36
+ Requires-Dist: cuda-python (>=12.6.0) ; extra == "cuda-opencl"
33
37
  Requires-Dist: hip-python ; extra == "hip"
34
38
  Requires-Dist: jsonschema
39
+ Requires-Dist: juliacall (>=0.9.31) ; extra == "julia"
40
+ Requires-Dist: juliapkg (>=0.1.23) ; extra == "julia"
35
41
  Requires-Dist: jupyter (>=1.0.0) ; extra == "tutorial"
36
42
  Requires-Dist: matplotlib (>=3.5.0) ; extra == "tutorial"
37
43
  Requires-Dist: numpy (>=2.0.0)
@@ -39,12 +45,11 @@ Requires-Dist: nvidia-ml-py (>=12.535.108) ; extra == "cuda"
39
45
  Requires-Dist: nvidia-ml-py (>=12.535.108) ; extra == "tutorial"
40
46
  Requires-Dist: packaging
41
47
  Requires-Dist: pandas (>=2.0.0)
42
- Requires-Dist: pycuda (>=2024.1) ; extra == "cuda-opencl"
43
- Requires-Dist: pycuda (>=2025.1) ; extra == "cuda"
48
+ Requires-Dist: pymoo (>=0.6.1.6)
44
49
  Requires-Dist: pynvml (>=11.4.1) ; extra == "cuda"
45
50
  Requires-Dist: pyopencl ; extra == "cuda-opencl"
46
51
  Requires-Dist: pyopencl ; extra == "opencl"
47
- Requires-Dist: python-constraint2 (>=2.4.0)
52
+ Requires-Dist: python-constraint2 (>=2.5.0)
48
53
  Requires-Dist: scikit-learn (>=1.0.2)
49
54
  Requires-Dist: scipy (>=1.14.1)
50
55
  Requires-Dist: xmltodict
@@ -0,0 +1,22 @@
1
+ from importlib.metadata import version
2
+
3
+ from kernel_tuner.interface import run_kernel, tune_kernel, tune_kernel_T1, tune_cache
4
+
5
+ __version__ = version(__package__)
6
+
7
+ __all__ = [
8
+ "create_device_targets",
9
+ "run_kernel",
10
+ "store_results",
11
+ "tune_kernel",
12
+ "tune_cache",
13
+ "tune_kernel_T1",
14
+ "__version__",
15
+ ]
16
+
17
+
18
+ def __getattr__(name):
19
+ if name in ("store_results", "create_device_targets"):
20
+ from kernel_tuner import integration
21
+ return getattr(integration, name)
22
+ raise AttributeError(f"module 'kernel_tuner' has no attribute {name!r}")
@@ -1,19 +1,25 @@
1
+ """Module for accuracy measurement and tunable parameters."""
2
+
3
+ import logging
4
+ import re
1
5
  from collections import UserDict
2
6
  from typing import Dict
7
+
3
8
  import numpy as np
4
- import logging
5
- import re
6
9
 
7
10
  from kernel_tuner.observers import OutputObserver
8
11
 
9
12
 
10
13
  class Tunable(UserDict):
14
+ """``Tunable`` can be used as a parameter value dependent input argument when tuning kernels."""
15
+
11
16
  def __init__(self, param_key: str, arrays: Dict):
12
- """The ``Tunable`` object can be used as an input argument when tuning
13
- kernels. It is a container that holds several arrays internally and
17
+ """The ``Tunable`` object can be used as an input argument when tuning kernels.
18
+
19
+ It is a container that holds several arrays internally and
14
20
  selects one array during benchmarking based on the value of a tunable parameter.
15
21
 
16
- Example
22
+ Example:
17
23
  -------
18
24
  Consider this example::
19
25
 
@@ -37,6 +43,7 @@ class Tunable(UserDict):
37
43
  self.param_key = param_key
38
44
 
39
45
  def select_for_configuration(self, params):
46
+ """Select the array for the given configuration."""
40
47
  if callable(self.param_key):
41
48
  option = self.param_key(params)
42
49
  elif self.param_key in params:
@@ -45,14 +52,16 @@ class Tunable(UserDict):
45
52
  option = eval(self.param_key, params, params)
46
53
 
47
54
  if option not in self.data:
48
- list = ", ".join(map(str, self.data.keys()))
49
- raise KeyError(
50
- f"'{option}' is not a valid parameter value, should be one of: {list}"
51
- )
55
+ raise KeyError(f"'{option}' is not a valid parameter value, should be one of: {', '.join(map(str, self.data.keys()))}")
52
56
 
53
- return self.data[option]
57
+ # continue recursively until we find a non-Tunable
58
+ el = self.data[option]
59
+ if isinstance(el, Tunable):
60
+ return el.select_for_configuration(params)
61
+ else:
62
+ return el
54
63
 
55
- def __call__(self, params):
64
+ def __call__(self, params): # noqa: D102
56
65
  return self.select_for_configuration(params)
57
66
 
58
67
 
@@ -70,6 +79,7 @@ def _find_bfloat16_if_available():
70
79
  if dtype is None:
71
80
  try:
72
81
  from ml_dtypes import bfloat16
82
+
73
83
  dtype = bfloat16
74
84
  except ImportError:
75
85
  pass
@@ -78,6 +88,7 @@ def _find_bfloat16_if_available():
78
88
  if dtype is None:
79
89
  try:
80
90
  from jax.numpy import bfloat16
91
+
81
92
  dtype = bfloat16
82
93
  except ImportError:
83
94
  pass
@@ -86,6 +97,7 @@ def _find_bfloat16_if_available():
86
97
  if dtype is None:
87
98
  try:
88
99
  from tensorflow import bfloat16
100
+
89
101
  dtype = bfloat16.as_numpy_dtype
90
102
  except ImportError:
91
103
  pass
@@ -100,9 +112,9 @@ def _find_bfloat16_if_available():
100
112
 
101
113
 
102
114
  def _to_float_dtype(x: str) -> np.dtype:
103
- """Convert a string to a numpy data type (``dtype``). This function recognizes
104
- common names (such as ``f16`` or ``kfloat``), and uses ``np.dtype(x)`` as a
105
- fallback.
115
+ """Convert a string to a numpy data type (``dtype``).
116
+
117
+ This function recognizes common names (such as ``f16`` or ``kfloat``), and uses ``np.dtype(x)`` as a fallback.
106
118
  """
107
119
  if isinstance(x, str):
108
120
  x = x.lower()
@@ -123,16 +135,17 @@ def _to_float_dtype(x: str) -> np.dtype:
123
135
 
124
136
 
125
137
  class TunablePrecision(Tunable):
126
- def __init__(
127
- self, param_key: str, array: np.ndarray, dtypes: Dict[str, np.dtype] = None
128
- ):
129
- """The ``Tunable`` object can be used as an input argument when tuning
130
- kernels. It is a container that internally holds several arrays
138
+ """``TunablePrecision`` can be used as a precision-level dependent input argument when tuning kernels."""
139
+
140
+ def __init__(self, param_key: str, array: np.ndarray, dtypes: Dict[str, np.dtype] = None):
141
+ """The ``Tunable`` object can be used as an input argument when tuning kernels.
142
+
143
+ It is a container that internally holds several arrays
131
144
  containing the same data, but stored in using different levels of
132
145
  precision. During benchamrking, one array is selected based on the value
133
146
  of the tunable parameter called ``param_key``.
134
147
 
135
- Example
148
+ Example:
136
149
  -------
137
150
  Consider this example::
138
151
 
@@ -156,7 +169,6 @@ class TunablePrecision(Tunable):
156
169
  if bfloat16 is not None:
157
170
  dtypes["bfloat16"] = bfloat16
158
171
 
159
-
160
172
  # If dtype is a list, convert it to a dictionary
161
173
  if isinstance(dtypes, (list, tuple)):
162
174
  dtypes = dict((name, _to_float_dtype(name)) for name in dtypes)
@@ -197,7 +209,6 @@ def error_metric_from_name(user_key, EPS=1e-8):
197
209
  The value of `EPS` is used for relative errors to prevent division by zero.
198
210
  ``
199
211
  """
200
-
201
212
  # Prepocess the provided name:
202
213
  # - convert to lowercase
203
214
  # - remove the word "error"
@@ -278,17 +289,13 @@ def error_metric_from_name(user_key, EPS=1e-8):
278
289
  raise ValueError(f"invalid error metric provided: {user_key}")
279
290
 
280
291
  # cast both arguments to f64 before passing them to the metric
281
- return lambda a, b: metric(
282
- a.astype(np.float64, copy=False), b.astype(np.float64, copy=False)
283
- )
292
+ return lambda a, b: metric(a.astype(np.float64, copy=False), b.astype(np.float64, copy=False))
284
293
 
285
294
 
286
295
  class AccuracyObserver(OutputObserver):
287
- """``AccuracyObserver`` measures the error on the output produced by a kernel
288
- by comparing the output against a reference output.
296
+ """``AccuracyObserver`` measures the error on the output produced by a kernel by comparing to a reference output.
289
297
 
290
- By default, it uses the root mean-squared error (RMSE) and uses the
291
- metric name ``"error"``.
298
+ By default, it uses the root mean-squared error (RMSE) and uses the metric name ``"error"``.
292
299
  """
293
300
 
294
301
  def __init__(self, metric=None, key="error", *, atol=1e-8):
@@ -303,7 +310,6 @@ class AccuracyObserver(OutputObserver):
303
310
  :param atol: The tolerance used in relative metrics to prevent
304
311
  division by zero. It is ignored by absolute error metrics.
305
312
  """
306
-
307
313
  # Default metric is RMSE
308
314
  if not metric:
309
315
  metric = "rmse"
@@ -317,6 +323,7 @@ class AccuracyObserver(OutputObserver):
317
323
  self.result = None
318
324
 
319
325
  def process_output(self, answers, outputs):
326
+ """Process the output produced by the kernel and compare it to the reference answers."""
320
327
  errors = []
321
328
 
322
329
  for answer, output in zip(answers, outputs):
@@ -326,4 +333,5 @@ class AccuracyObserver(OutputObserver):
326
333
  self.result = max(errors)
327
334
 
328
335
  def get_results(self):
336
+ """Get the results produced by this observer."""
329
337
  return dict([(self.key, self.result)])
@@ -1,13 +1,13 @@
1
- """ This module contains the functionality for running and compiling C functions """
1
+ """This module contains the functionality for running and compiling C functions"""
2
2
 
3
- from collections import namedtuple
4
- import subprocess
5
- import platform
3
+ import _ctypes
4
+ import ctypes as C
6
5
  import errno
7
- import re
8
6
  import logging
9
- import ctypes as C
10
- import _ctypes
7
+ import platform
8
+ import re
9
+ import subprocess
10
+ from collections import namedtuple
11
11
 
12
12
  import numpy as np
13
13
  import numpy.ctypeslib
@@ -15,10 +15,9 @@ import numpy.ctypeslib
15
15
  from kernel_tuner.backends.backend import CompilerBackend
16
16
  from kernel_tuner.observers.compiler import CompilerRuntimeObserver
17
17
  from kernel_tuner.util import (
18
- get_temp_filename,
19
18
  delete_temp_file,
19
+ get_temp_filename,
20
20
  write_file,
21
- SkippableFailure,
22
21
  )
23
22
 
24
23
  try:
@@ -88,7 +87,7 @@ class CompilerFunctions(CompilerBackend):
88
87
  """Class that groups the code for running and compiling C functions"""
89
88
 
90
89
  def __init__(self, iterations=7, compiler_options=None, compiler=None, observers=None):
91
- """instantiate CFunctions object used for interacting with C code
90
+ """Instantiate CFunctions object used for interacting with C code
92
91
 
93
92
  :param iterations: Number of iterations used while benchmarking a kernel, 7 by default.
94
93
  :type iterations: int
@@ -146,7 +145,7 @@ class CompilerFunctions(CompilerBackend):
146
145
  self.name = platform.processor()
147
146
 
148
147
  def ready_argument_list(self, arguments):
149
- """ready argument list to be passed to the C function
148
+ """Ready argument list to be passed to the C function
150
149
 
151
150
  :param arguments: List of arguments to be passed to the C function.
152
151
  The order should match the argument list on the C function.
@@ -181,7 +180,7 @@ class CompilerFunctions(CompilerBackend):
181
180
  return ctype_args
182
181
 
183
182
  def compile(self, kernel_instance):
184
- """call the C compiler to compile the kernel, return the function
183
+ """Call the C compiler to compile the kernel, return the function
185
184
 
186
185
  :param kernel_instance: An object representing the specific instance of the tunable kernel
187
186
  in the parameter space.
@@ -311,29 +310,33 @@ class CompilerFunctions(CompilerBackend):
311
310
  def start_event(self):
312
311
  """Records the event that marks the start of a measurement
313
312
 
314
- C backend does not use events"""
313
+ C backend does not use events
314
+ """
315
315
  pass
316
316
 
317
317
  def stop_event(self):
318
318
  """Records the event that marks the end of a measurement
319
319
 
320
- C backend does not use events"""
320
+ C backend does not use events
321
+ """
321
322
  pass
322
323
 
323
324
  def kernel_finished(self):
324
325
  """Returns True if the kernel has finished, False otherwise
325
326
 
326
- C backend does not support asynchronous launches"""
327
+ C backend does not support asynchronous launches
328
+ """
327
329
  return True
328
330
 
329
331
  def synchronize(self):
330
332
  """Halts execution until device has finished its tasks
331
333
 
332
- C backend does not support asynchronous launches"""
334
+ C backend does not support asynchronous launches
335
+ """
333
336
  pass
334
337
 
335
338
  def run_kernel(self, func, c_args, threads, grid, stream=None):
336
- """runs the kernel once, returns whatever the kernel returns
339
+ """Runs the kernel once, returns whatever the kernel returns
337
340
 
338
341
  :param func: A C function compiled for this specific configuration
339
342
  :type func: ctypes._FuncPtr
@@ -367,7 +370,7 @@ class CompilerFunctions(CompilerBackend):
367
370
  return time
368
371
 
369
372
  def memset(self, allocation, value, size):
370
- """set the memory in allocation to the value in value
373
+ """Set the memory in allocation to the value in value
371
374
 
372
375
  :param allocation: An Argument for some memory allocation unit
373
376
  :type allocation: Argument
@@ -419,7 +422,7 @@ class CompilerFunctions(CompilerBackend):
419
422
  self.memcpy_dtoh(arg, self.allocations[i])
420
423
 
421
424
  def cleanup_lib(self):
422
- """unload the previously loaded shared library"""
425
+ """Unload the previously loaded shared library"""
423
426
  if self.lib is None:
424
427
  return
425
428
 
@@ -2,6 +2,7 @@
2
2
  from __future__ import print_function
3
3
 
4
4
  import numpy as np
5
+ import uuid
5
6
 
6
7
  from kernel_tuner.backends.backend import GPUBackend
7
8
  from kernel_tuner.observers.cupy import CupyRuntimeObserver
@@ -61,28 +62,33 @@ class CupyFunctions(GPUBackend):
61
62
  # default dynamically allocated shared memory size, can be overwritten using smem_args
62
63
  self.smem_size = 0
63
64
 
64
- # setup observers
65
- self.observers = observers or []
66
- self.observers.append(CupyRuntimeObserver(self))
67
- for obs in self.observers:
68
- obs.register_device(self)
69
-
70
65
  # collect environment information
71
66
  env = dict()
72
67
  cupy_info = str(get_runtime_info()).split("\n")[:-1]
73
68
  info_dict = {
74
- s.split(":")[0].strip(): s.split(":")[1].strip() for s in cupy_info
69
+ s.split(":", 1)[0].strip(): s.split(":", 1)[1].strip() for s in cupy_info
75
70
  }
76
71
  env["device_name"] = info_dict[f"Device {device} Name"]
72
+ env["pci_bus_id"] = info_dict[f"Device {device} PCI Bus ID"]
77
73
 
78
74
  env["cuda_version"] = cp.cuda.runtime.driverGetVersion()
79
75
  env["compute_capability"] = self.cc
80
76
  env["iterations"] = self.iterations
81
77
  env["compiler_options"] = compiler_options
82
78
  env["device_properties"] = self.devprops
79
+
80
+ props = cp.cuda.runtime.getDeviceProperties(device)
81
+ env["uuid"] = str(uuid.UUID(bytes=props["uuid"]))
82
+
83
83
  self.env = env
84
84
  self.name = env["device_name"]
85
85
 
86
+ # setup observers
87
+ self.observers = observers or []
88
+ self.observers.append(CupyRuntimeObserver(self))
89
+ for obs in self.observers:
90
+ obs.register_device(self)
91
+
86
92
  def ready_argument_list(self, arguments):
87
93
  """Ready argument list to be passed to the kernel, allocates gpu mem.
88
94
 
@@ -3,12 +3,14 @@
3
3
  import ctypes
4
4
  import ctypes.util
5
5
  import logging
6
+ import json
7
+ import uuid
6
8
 
7
9
  import numpy as np
8
10
 
9
11
  from kernel_tuner.backends.backend import GPUBackend
10
- from kernel_tuner.observers.hip import HipRuntimeObserver
11
12
  from kernel_tuner.backends.hip.util import hip_check
13
+ from kernel_tuner.observers.hip import HipRuntimeObserver
12
14
 
13
15
  try:
14
16
  from hip import hip, hiprtc
@@ -32,8 +34,35 @@ dtype_map = {
32
34
 
33
35
  hipSuccess = 0
34
36
 
37
+
38
+ def extract_safe_properties(props):
39
+ """Extract those properties that are 'safe' (i.e, json serializable)"""
40
+ result = dict()
41
+
42
+ for key in props.PROPERTIES():
43
+ try:
44
+ value = getattr(props, key)
45
+ if isinstance(value, (str, int, float)):
46
+ # These are safe
47
+ result[key] = value
48
+ elif isinstance(value, (bytes, bytearray)):
49
+ # bytes/bytearray is typically a string
50
+ result[key] = value.decode("utf-8").rstrip("\x00")
51
+ else:
52
+ # As last option, try to convert to json
53
+ result[key] = json.loads(json.dumps(value))
54
+ except Exception:
55
+ continue
56
+
57
+ # Remove the 'reserved' fields as they are just filled with zeros
58
+ result.pop("reserved", None)
59
+ result.pop("hipReserved", None)
60
+
61
+ return result
62
+
63
+
35
64
  class HipFunctions(GPUBackend):
36
- """Class that groups the HIP functions on maintains state about the device."""
65
+ """Class that groups the HIP functions and maintains state about the device."""
37
66
 
38
67
  def __init__(self, device=0, iterations=7, compiler_options=None, observers=None):
39
68
  """Instantiate HipFunctions object used for interacting with the HIP device.
@@ -72,6 +101,13 @@ class HipFunctions(GPUBackend):
72
101
  env["device_name"] = self.name
73
102
  env["iterations"] = self.iterations
74
103
  env["compiler_options"] = compiler_options
104
+ env["pci_bus_id"] = props.pciBusID
105
+ env["pci_domain_id"] = props.pciDomainID
106
+ env["pci_device_id"] = props.pciDeviceID
107
+ env["uuid"] = str(uuid.UUID(bytes=props.uuid.bytes))
108
+ env["hip_driver_version"] = hip_check(hip.hipDriverGetVersion())
109
+ env["hip_runtime_version"] = hip_check(hip.hipRuntimeGetVersion())
110
+ env["device_properties"] = extract_safe_properties(props)
75
111
  self.env = env
76
112
 
77
113
  # Create stream and events
@@ -149,13 +185,16 @@ class HipFunctions(GPUBackend):
149
185
  # Format kernel string
150
186
  kernel_string = kernel_instance.kernel_string
151
187
  kernel_name = kernel_instance.name
152
- if 'extern "C"' not in kernel_string:
153
- kernel_string = 'extern "C" {\n' + kernel_string + "\n}"
188
+ expression_name = kernel_name.encode()
154
189
 
155
190
  # Create program
156
191
  prog = hip_check(hiprtc.hiprtcCreateProgram(kernel_string.encode(), kernel_name.encode(), 0, [], []))
157
192
 
158
193
  try:
194
+ # Add the kernel as an expression. This forces hiprtc to instantiate the kernel if it
195
+ # is templated or if it is in a namespace.
196
+ hip_check(hiprtc.hiprtcAddNameExpression(prog, expression_name))
197
+
159
198
  # Get device properties
160
199
  props = hip.hipDeviceProp_t()
161
200
  hip_check(hip.hipGetDeviceProperties(props, 0))
@@ -174,6 +213,10 @@ class HipFunctions(GPUBackend):
174
213
  hip_check(hiprtc.hiprtcGetProgramLog(prog, log))
175
214
  raise RuntimeError(log.decode())
176
215
 
216
+ # Get the lowered name. This is the name that can be used in hipModuleGetFunction to
217
+ # get the kernel. For templated kernels, this differs from the original kernel name.
218
+ lowered_name = hip_check(hiprtc.hiprtcGetLoweredName(prog, expression_name))
219
+
177
220
  # Get compiled code
178
221
  code_size = hip_check(hiprtc.hiprtcGetCodeSize(prog))
179
222
  code = bytearray(code_size)
@@ -182,7 +225,7 @@ class HipFunctions(GPUBackend):
182
225
  # Load module and get function
183
226
  module = hip_check(hip.hipModuleLoadData(code))
184
227
  self.current_module = module
185
- kernel = hip_check(hip.hipModuleGetFunction(module, kernel_name.encode()))
228
+ kernel = hip_check(hip.hipModuleGetFunction(module, lowered_name))
186
229
 
187
230
  except Exception as e:
188
231
  # Cleanup
@@ -27,12 +27,14 @@ class ScoreObserver(BenchmarkObserver):
27
27
  self.scores.append(self.dev.last_score)
28
28
 
29
29
  def get_results(self):
30
- results = {'score': mean(self.scores), 'scores': self.scores.copy()}
30
+ results = {"score": mean(self.scores), "scores": self.scores.copy()}
31
31
  self.scores = []
32
32
  return results
33
33
 
34
+
34
35
  class HypertunerFunctions(Backend):
35
36
  """Class for executing hyperparameter tuning."""
37
+
36
38
  units = {}
37
39
 
38
40
  def __init__(self, iterations, compiler_options=None):
@@ -51,30 +53,30 @@ class HypertunerFunctions(Backend):
51
53
  "name": "dedispersion_milo",
52
54
  "folder": folder,
53
55
  "input_file": "dedispersion_milo.json",
54
- "objective_performance_keys": ["time"]
56
+ "objective_performance_keys": ["time"],
55
57
  },
56
58
  {
57
59
  "name": "hotspot_milo",
58
60
  "folder": folder,
59
61
  "input_file": "hotspot_milo.json",
60
- "objective_performance_keys": ["GFLOP/s"]
62
+ "objective_performance_keys": ["GFLOP/s"],
61
63
  },
62
64
  {
63
65
  "name": "convolution_milo",
64
66
  "folder": folder,
65
67
  "input_file": "convolution_milo.json",
66
- "objective_performance_keys": ["time"]
68
+ "objective_performance_keys": ["time"],
67
69
  },
68
70
  {
69
71
  "name": "gemm_milo",
70
72
  "folder": folder,
71
73
  "input_file": "gemm_milo.json",
72
- "objective_performance_keys": ["time"]
73
- }
74
+ "objective_performance_keys": ["time"],
75
+ },
74
76
  ]
75
77
  # any additional settings
76
- self.override = {
77
- "experimental_groups_defaults": {
78
+ self.override = {
79
+ "experimental_groups_defaults": {
78
80
  "repeats": 25,
79
81
  "samples": self.iterations,
80
82
  "minimum_fraction_of_budget_valid": 0.1,
@@ -84,10 +86,8 @@ class HypertunerFunctions(Backend):
84
86
  "cutoff_percentile": 0.95,
85
87
  "cutoff_percentile_start": 0.01,
86
88
  "cutoff_type": "time",
87
- "objective_time_keys": [
88
- "all"
89
- ]
90
- }
89
+ "objective_time_keys": ["all"],
90
+ },
91
91
  }
92
92
 
93
93
  # override the defaults with compiler options if provided
@@ -113,7 +113,7 @@ class HypertunerFunctions(Backend):
113
113
  if arglist is None:
114
114
  arglist = []
115
115
  return arglist
116
-
116
+
117
117
  def compile(self, kernel_instance):
118
118
  super().compile(kernel_instance)
119
119
  path = Path(__file__).parent.parent.parent / "hyperparamtuning"
@@ -121,37 +121,47 @@ class HypertunerFunctions(Backend):
121
121
 
122
122
  # strategy settings
123
123
  strategy: str = kernel_instance.arguments[0]
124
- hyperparams = [{'name': k, 'value': v} for k, v in kernel_instance.params.items()]
124
+ hyperparams = [{"name": k, "value": v} for k, v in kernel_instance.params.items()]
125
125
  hyperparams_string = "_".join(f"{k}={str(v)}" for k, v in kernel_instance.params.items())
126
- searchspace_strategies = [{
127
- "autotuner": "KernelTuner",
128
- "name": f"{strategy.lower()}_{hyperparams_string}",
129
- "display_name": strategy.replace('_', ' ').capitalize(),
130
- "search_method": strategy.lower(),
131
- 'search_method_hyperparameters': hyperparams
132
- }]
126
+ searchspace_strategies = [
127
+ {
128
+ "autotuner": "KernelTuner",
129
+ "name": f"{strategy.lower()}_{hyperparams_string}",
130
+ "display_name": strategy.replace("_", " ").capitalize(),
131
+ "search_method": strategy.lower(),
132
+ "search_method_hyperparameters": hyperparams,
133
+ }
134
+ ]
133
135
 
134
136
  name = kernel_instance.name if len(kernel_instance.name) > 0 else kernel_instance.kernel_source.kernel_name
135
- experiments_filepath = generate_experiment_file(name, path, searchspace_strategies, self.applications, self.gpus,
136
- override=self.override, generate_unique_file=True, overwrite_existing_file=True)
137
+ experiments_filepath = generate_experiment_file(
138
+ name,
139
+ path,
140
+ searchspace_strategies,
141
+ self.applications,
142
+ self.gpus,
143
+ override=self.override,
144
+ generate_unique_file=True,
145
+ overwrite_existing_file=True,
146
+ )
137
147
  return str(experiments_filepath)
138
-
148
+
139
149
  def start_event(self):
140
150
  return super().start_event()
141
-
151
+
142
152
  def stop_event(self):
143
153
  return super().stop_event()
144
-
154
+
145
155
  def kernel_finished(self):
146
156
  super().kernel_finished()
147
157
  return True
148
-
158
+
149
159
  def synchronize(self):
150
160
  return super().synchronize()
151
-
161
+
152
162
  def run_kernel(self, func, gpu_args=None, threads=None, grid=None, stream=None):
153
163
  # from cProfile import Profile
154
-
164
+
155
165
  # # generate the experiments file
156
166
  # experiments_filepath = Path(func)
157
167
 
@@ -161,23 +171,23 @@ class HypertunerFunctions(Backend):
161
171
  # pr.dump_stats('diff_evo_hypertune_hotspot.prof')
162
172
  # self.last_score = scores[list(scores.keys())[0]]['score']
163
173
  # raise ValueError(scores)
164
-
174
+
165
175
  # generate the experiments file
166
176
  experiments_filepath = Path(func)
167
177
 
168
178
  # run the methodology to get a fitness score for this configuration
169
179
  scores = get_strategy_scores(str(experiments_filepath), full_validate_on_load=False)
170
- self.last_score = scores[list(scores.keys())[0]]['score']
180
+ self.last_score = scores[list(scores.keys())[0]]["score"]
171
181
 
172
182
  # remove the experiments file
173
183
  experiments_filepath.unlink()
174
-
184
+
175
185
  def memset(self, allocation, value, size):
176
186
  return super().memset(allocation, value, size)
177
-
187
+
178
188
  def memcpy_dtoh(self, dest, src):
179
189
  return super().memcpy_dtoh(dest, src)
180
-
190
+
181
191
  def memcpy_htod(self, dest, src):
182
192
  return super().memcpy_htod(dest, src)
183
193