Skip to content

Commit 653f617

Browse files
Merge pull request #186 from KernelTuner/additional_tests
Additional tests
2 parents 02619be + 9ad9472 commit 653f617

File tree

7 files changed

+93
-54
lines changed

7 files changed

+93
-54
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
88
- Support for using time_limit in simulation mode
99
- Helper functions for energy tuning
1010
- Example to show ridge frequency and power-frequency model
11+
- Functions to store tuning output and metadata
1112

1213
### Changed
1314
- Changed what timings are stored in cache files

examples/cuda/vector_add.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
#!/usr/bin/env python
22
"""This is the minimal example from the README"""
33

4-
import json
54
import numpy
65
from kernel_tuner import tune_kernel
6+
from kernel_tuner.file_utils import store_output_file, store_metadata_file
77

88
def tune():
99

@@ -28,12 +28,15 @@ def tune():
2828
tune_params = dict()
2929
tune_params["block_size_x"] = [128+64*i for i in range(15)]
3030

31-
result = tune_kernel("vector_add", kernel_string, size, args, tune_params)
31+
results, env = tune_kernel("vector_add", kernel_string, size, args, tune_params)
3232

33-
with open("vector_add.json", 'w') as fp:
34-
json.dump(result, fp)
33+
# Store the tuning results in an output file
34+
store_output_file("vector_add.json", results, tune_params)
3535

36-
return result
36+
# Store the metadata of this run
37+
store_metadata_file("vector_add-metadata.json")
38+
39+
return results
3740

3841

3942
if __name__ == "__main__":

examples/opencl/vector_add.py

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
#!/usr/bin/env python
2+
"""This is the minimal example from the README"""
3+
24
import numpy
35
from kernel_tuner import tune_kernel
6+
from kernel_tuner.file_utils import store_output_file, store_metadata_file
7+
8+
def tune():
49

5-
kernel_string = """
10+
kernel_string = """
611
__kernel void vector_add(__global float *c, __global const float *a, __global const float *b, int n) {
712
int i = get_global_id(0);
813
if (i<n) {
@@ -11,17 +16,28 @@
1116
}
1217
"""
1318

14-
size = 10000000
19+
size = 10000000
20+
21+
a = numpy.random.rand(size).astype(numpy.float32)
22+
b = numpy.random.rand(size).astype(numpy.float32)
23+
c = numpy.zeros_like(a)
24+
n = numpy.int32(size)
25+
26+
args = [c, a, b, n]
27+
28+
tune_params = dict()
29+
tune_params["block_size_x"] = [128+64*i for i in range(15)]
30+
31+
results, env = tune_kernel("vector_add", kernel_string, size, args, tune_params)
1532

16-
a = numpy.random.rand(size).astype(numpy.float32)
17-
b = numpy.random.rand(size).astype(numpy.float32)
18-
c = numpy.zeros_like(a)
19-
n = numpy.int32(size)
33+
# Store the tuning results in an output file
34+
store_output_file("vector_add.json", results, tune_params)
2035

21-
args = [c, a, b, n]
36+
# Store the metadata of this run
37+
store_metadata_file("vector_add-metadata.json")
2238

23-
tune_params = dict()
24-
tune_params["block_size_x"] = [128+64*i for i in range(15)]
39+
return results
2540

26-
tune_kernel("vector_add", kernel_string, size, args, tune_params)
2741

42+
if __name__ == "__main__":
43+
tune()

kernel_tuner/energy/energy.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
}
4242
"""
4343

44-
def get_frequency_power_relation_fp32(device, n_samples=10, nvidia_smi_fallback=None, use_locked_clocks=False, cache=None):
44+
def get_frequency_power_relation_fp32(device, n_samples=10, nvidia_smi_fallback=None, use_locked_clocks=False, cache=None, simulation_mode=None):
4545
""" Use NVML and PyCUDA with a synthetic kernel to obtain samples of frequency-power pairs """
4646

4747
# get some numbers about the device
@@ -85,7 +85,7 @@ def get_frequency_power_relation_fp32(device, n_samples=10, nvidia_smi_fallback=
8585

8686
results, _ = tune_kernel("fp32_kernel", fp32_kernel_string, problem_size=(multiprocessor_count, 64),
8787
arguments=arguments, tune_params=tune_params, observers=[nvmlobserver],
88-
verbose=False, quiet=True, metrics=metrics, iterations=10,
88+
verbose=False, quiet=True, metrics=metrics, iterations=10, simulation_mode=simulation_mode,
8989
grid_div_x=[], grid_div_y=[], cache=cache or f"synthetic_fp32_cache_{device_name}.json")
9090

9191
freqs = np.array([res["core_freq"] for res in results])
@@ -147,7 +147,7 @@ def fit_power_frequency_model(freqs, nvml_power):
147147
return clock_threshold + clock_min, fit_parameters, scale_parameters
148148

149149

150-
def create_power_frequency_model(device=0, n_samples=10, verbose=False, nvidia_smi_fallback=None, use_locked_clocks=False, cache=None):
150+
def create_power_frequency_model(device=0, n_samples=10, verbose=False, nvidia_smi_fallback=None, use_locked_clocks=False, cache=None, simulation_mode=None):
151151
""" Calculate the most energy-efficient clock frequency of device
152152
153153
This function uses a performance model to fit the power-frequency curve
@@ -181,7 +181,7 @@ def create_power_frequency_model(device=0, n_samples=10, verbose=False, nvidia_s
181181
:rtype: float
182182
183183
"""
184-
freqs, nvml_power = get_frequency_power_relation_fp32(device, n_samples, nvidia_smi_fallback, use_locked_clocks, cache=cache)
184+
freqs, nvml_power = get_frequency_power_relation_fp32(device, n_samples, nvidia_smi_fallback, use_locked_clocks, cache=cache, simulation_mode=simulation_mode)
185185

186186
if verbose:
187187
print("Clock frequencies:", freqs.tolist())

kernel_tuner/file_utils.py

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -165,27 +165,41 @@ def get_device_query(target):
165165
raise ValueError("get_device_query target not supported")
166166

167167

168-
def store_metadata_file(metadata_filename, target="nvidia"):
168+
def store_metadata_file(metadata_filename):
169169
""" Store the metadata about the current hardware and software environment in a JSON output file
170170
171171
This function produces a JSON file that adheres to the T4 auto-tuning metadata JSON schema.
172172
173173
:param metadata_filename: Name of the to be created metadata file
174174
:type metadata_filename: string
175175
176-
:param target: Target specifies whether to include the metadata of the 'nvidia' or 'amd' GPUs in the system
177-
:type target: string
178-
179176
"""
180177
metadata_filename = filename_ensure_json_extension(metadata_filename)
181178
metadata = {}
182179

183180
# lshw only works on Linux, this intentionally raises a FileNotFoundError when ran on systems that do not have it
184181
lshw_out = subprocess.run(["lshw", "-json"], capture_output=True)
185-
metadata["hardware"] = dict(lshw=json.loads(lshw_out.stdout))
186182

187-
# only works if nvidia-smi (for NVIDIA) or rocm-smi (for AMD) is present, raises FileNotFoundError when not present
188-
device_query = get_device_query(target)
183+
# sometimes lshw outputs a list of length 1, sometimes just as a dict, schema wants a list
184+
lshw_string = lshw_out.stdout.decode('utf-8').strip()
185+
if lshw_string[0] == '{' and lshw_string[-1] == '}':
186+
lshw_string = '[' + lshw_string + ']'
187+
188+
metadata["hardware"] = dict(lshw=json.loads(lshw_string))
189+
190+
# attempts to use nvidia-smi or rocm-smi if present
191+
device_query = {}
192+
try:
193+
device_query['nvidia-smi'] = get_device_query("nvidia")
194+
except FileNotFoundError:
195+
# ignore if nvidia-smi is not found
196+
pass
197+
198+
try:
199+
device_query['rocm-smi'] = get_device_query("amd")
200+
except FileNotFoundError:
201+
# ignore if rocm-smi is not found
202+
pass
189203

190204
metadata["environment"] = dict(device_query=device_query,
191205
requirements=get_dependencies())

test/test_energy.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@
88
@skip_if_no_pycuda
99
def test_create_power_frequency_model():
1010

11-
ridge_frequency, freqs, nvml_power, fitted_params, scaling = energy.create_power_frequency_model(cache=cache_filename)
11+
ridge_frequency, freqs, nvml_power, fitted_params, scaling = energy.create_power_frequency_model(cache=cache_filename, simulation_mode=True)
1212
assert ridge_frequency == 1350
1313

test/test_file_utils.py

Lines changed: 32 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -11,41 +11,46 @@
1111
def test_store_output_file(env):
1212
# setup variables
1313
filename = "test_output_file.json"
14-
results, _ = tune_kernel(*env, cache=cache_filename, simulation_mode=True)
15-
tune_params = env[-1]
1614

17-
# run store_output_file
18-
store_output_file(filename, results, tune_params)
15+
try:
16+
results, _ = tune_kernel(*env, cache=cache_filename, simulation_mode=True)
17+
tune_params = env[-1]
18+
19+
# run store_output_file
20+
store_output_file(filename, results, tune_params)
1921

20-
# retrieve output file
21-
_, schema = output_file_schema("results")
22-
with open(filename) as json_file:
23-
output_json = json.load(json_file)
22+
# retrieve output file
23+
_, schema = output_file_schema("results")
24+
with open(filename) as json_file:
25+
output_json = json.load(json_file)
2426

25-
# validate
26-
validate(output_json, schema=schema)
27+
# validate
28+
validate(output_json, schema=schema)
2729

28-
# clean up
29-
delete_temp_file(filename)
30+
finally:
31+
# clean up
32+
delete_temp_file(filename)
3033

3134

3235
def test_store_metadata_file():
3336
# setup variables
3437
filename = "test_metadata_file.json"
3538

36-
# run store_metadata_file
3739
try:
38-
store_metadata_file(filename, target="nvidia")
39-
except FileNotFoundError:
40-
pytest.skip("'lshw' or 'nvidia-smi' not present on this system")
41-
42-
# retrieve metadata file
43-
_, schema = output_file_schema("metadata")
44-
with open(filename) as json_file:
45-
metadata_json = json.load(json_file)
46-
47-
# validate
48-
validate(metadata_json, schema=schema)
49-
50-
# clean up
51-
delete_temp_file(filename)
40+
# run store_metadata_file
41+
try:
42+
store_metadata_file(filename)
43+
except FileNotFoundError:
44+
pytest.skip("'lshw' not present on this system")
45+
46+
# retrieve metadata file
47+
_, schema = output_file_schema("metadata")
48+
with open(filename) as json_file:
49+
metadata_json = json.load(json_file)
50+
51+
# validate
52+
validate(metadata_json, schema=schema)
53+
54+
finally:
55+
# clean up
56+
delete_temp_file(filename)

0 commit comments

Comments
 (0)