Skip to content

Commit a6f7148

Browse files
Merge pull request #201 from KernelTuner/T4_compatibility
T4 compatibility
2 parents 580075c + 0aa9edd commit a6f7148

File tree

4 files changed

+132
-96
lines changed

4 files changed

+132
-96
lines changed

MANIFEST.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
include setup.py
22
include LICENSE
33
include README.rst
4+
include kernel_tuner/schema/T4/1.0.0/*

kernel_tuner/file_utils.py

Lines changed: 85 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
import json
55
import subprocess
66
import xmltodict
7+
from sys import platform
8+
from pathlib import Path
79

810
from importlib.metadata import requires, version, PackageNotFoundError
911
from packaging.requirements import Requirement
@@ -14,7 +16,7 @@
1416

1517

1618
def output_file_schema(target):
17-
""" Get the requested JSON schema and the version number
19+
"""Get the requested JSON schema and the version number
1820
1921
:param target: Name of the T4 schema to return, should be any of ['output', 'metadata']
2022
:type target: string
@@ -25,13 +27,13 @@ def output_file_schema(target):
2527
"""
2628
current_version = "1.0.0"
2729
output_file = schema_dir + f"/T4/{current_version}/{target}-schema.json"
28-
with open(output_file, 'r') as fh:
30+
with open(output_file, "r") as fh:
2931
json_string = json.load(fh)
3032
return current_version, json_string
3133

3234

3335
def get_configuration_validity(objective) -> str:
34-
""" Convert internal Kernel Tuner error to string """
36+
"""Convert internal Kernel Tuner error to string"""
3537
errorstring: str
3638
if not isinstance(objective, util.ErrorConfig):
3739
errorstring = "correct"
@@ -40,24 +42,33 @@ def get_configuration_validity(objective) -> str:
4042
errorstring = "compile"
4143
elif isinstance(objective, util.RuntimeFailedConfig):
4244
errorstring = "runtime"
43-
else:
45+
elif isinstance(objective, util.InvalidConfig):
4446
errorstring = "constraints"
47+
else:
48+
raise ValueError(f"Unkown objective type {type(objective)}, value {objective}")
4549
return errorstring
4650

4751

4852
def filename_ensure_json_extension(filename: str) -> str:
49-
""" Check if the filename has a .json extension, if not, add it """
53+
"""Check if the filename has a .json extension, if not, add it"""
5054
if filename[-5:] != ".json":
5155
filename += ".json"
5256
return filename
5357

5458

55-
def store_output_file(output_filename, results, tune_params, objective="time"):
56-
""" Store the obtained auto-tuning results in a JSON output file
59+
def make_filenamepath(filenamepath: Path):
60+
"""Create the given path to a filename if the path does not yet exist"""
61+
filepath = filenamepath.parents[0]
62+
if not filepath.exists():
63+
filepath.mkdir()
64+
65+
66+
def store_output_file(output_filename: str, results, tune_params, objective="time"):
67+
"""Store the obtained auto-tuning results in a JSON output file
5768
5869
This function produces a JSON file that adheres to the T4 auto-tuning output JSON schema.
5970
60-
:param output_filename: Name of the to be created output file
71+
:param output_filename: Name or 'path / name' of the to be created output file
6172
:type output_filename: string
6273
6374
:param results: Results list as return by tune_kernel
@@ -70,26 +81,20 @@ def store_output_file(output_filename, results, tune_params, objective="time"):
7081
:type objective: string
7182
7283
"""
73-
output_filename = filename_ensure_json_extension(output_filename)
84+
output_filenamepath = Path(filename_ensure_json_extension(output_filename))
85+
make_filenamepath(output_filenamepath)
7486

75-
timing_keys = [
76-
"compile_time", "benchmark_time", "framework_time", "strategy_time",
77-
"verification_time"
78-
]
79-
not_measurement_keys = list(
80-
tune_params.keys()) + timing_keys + ["timestamp"] + ["times"]
87+
timing_keys = ["compile_time", "benchmark_time", "framework_time", "strategy_time", "verification_time"]
88+
not_measurement_keys = list(tune_params.keys()) + timing_keys + ["timestamp"] + ["times"]
8189

8290
output_data = []
8391

8492
for result in results:
85-
8693
out = {}
8794

88-
out["timestamp"] = result["timestamp"]
89-
out["configuration"] = {
90-
k: v
91-
for k, v in result.items() if k in tune_params
92-
}
95+
if "timestamp" in result:
96+
out["timestamp"] = result["timestamp"]
97+
out["configuration"] = {k: v for k, v in result.items() if k in tune_params}
9398

9499
# collect configuration specific timings
95100
timings = dict()
@@ -98,7 +103,8 @@ def store_output_file(output_filename, results, tune_params, objective="time"):
98103
timings["framework"] = result["framework_time"]
99104
timings["search_algorithm"] = result["strategy_time"]
100105
timings["validation"] = result["verification_time"]
101-
timings["runtimes"] = result["times"]
106+
if "times" in result:
107+
timings["runtimes"] = result["times"]
102108
out["times"] = timings
103109

104110
# encode the validity of the configuration
@@ -112,10 +118,7 @@ def store_output_file(output_filename, results, tune_params, objective="time"):
112118
measurements = []
113119
for key, value in result.items():
114120
if key not in not_measurement_keys:
115-
measurements.append(
116-
dict(name=key,
117-
value=value,
118-
unit="ms" if key.startswith("time") else ""))
121+
measurements.append(dict(name=key, value=value, unit="ms" if key.startswith("time") else ""))
119122
out["measurements"] = measurements
120123

121124
# objectives
@@ -130,12 +133,12 @@ def store_output_file(output_filename, results, tune_params, objective="time"):
130133
# write output_data to a JSON file
131134
version, _ = output_file_schema("results")
132135
output_json = dict(results=output_data, schema_version=version)
133-
with open(output_filename, 'w+') as fh:
136+
with open(output_filenamepath, "w+") as fh:
134137
json.dump(output_json, fh, cls=util.NpEncoder)
135138

136139

137-
def get_dependencies(package='kernel_tuner'):
138-
""" Get the Python dependencies of Kernel Tuner currently installed and their version numbers """
140+
def get_dependencies(package="kernel_tuner"):
141+
"""Get the Python dependencies of Kernel Tuner currently installed and their version numbers"""
139142
requirements = requires(package)
140143
deps = [Requirement(req).name for req in requirements]
141144
depends = []
@@ -150,10 +153,9 @@ def get_dependencies(package='kernel_tuner'):
150153

151154

152155
def get_device_query(target):
153-
""" Get the information about GPUs in the current system, target is any of ['nvidia', 'amd'] """
156+
"""Get the information about GPUs in the current system, target is any of ['nvidia', 'amd']"""
154157
if target == "nvidia":
155-
nvidia_smi_out = subprocess.run(["nvidia-smi", "--query", "-x"],
156-
capture_output=True)
158+
nvidia_smi_out = subprocess.run(["nvidia-smi", "--query", "-x"], capture_output=True)
157159
nvidia_smi = xmltodict.parse(nvidia_smi_out.stdout)
158160
gpu_info = nvidia_smi["nvidia_smi_log"]["gpu"]
159161
del_key = "processes"
@@ -162,61 +164,89 @@ def get_device_query(target):
162164
for gpu in gpu_info:
163165
del gpu[del_key]
164166
elif isinstance(gpu_info, dict) and del_key in gpu_info:
165-
del gpu_info[del_key]
167+
del gpu_info[del_key]
166168
return nvidia_smi
167169
elif target == "amd":
168-
rocm_smi_out = subprocess.run(["rocm-smi", "--showallinfo", "--json"],
169-
capture_output=True)
170+
rocm_smi_out = subprocess.run(["rocm-smi", "--showallinfo", "--json"], capture_output=True)
170171
return json.loads(rocm_smi_out.stdout)
171172
else:
172173
raise ValueError("get_device_query target not supported")
173174

174175

175-
def store_metadata_file(metadata_filename):
176-
""" Store the metadata about the current hardware and software environment in a JSON output file
176+
def store_metadata_file(metadata_filename: str):
177+
"""Store the metadata about the current hardware and software environment in a JSON output file
177178
178179
This function produces a JSON file that adheres to the T4 auto-tuning metadata JSON schema.
179180
180-
:param metadata_filename: Name of the to be created metadata file
181+
:param metadata_filename: Name or 'path / name' of the to be created metadata file
181182
:type metadata_filename: string
182183
183184
"""
184-
metadata_filename = filename_ensure_json_extension(metadata_filename)
185+
metadata_filenamepath = Path(filename_ensure_json_extension(metadata_filename))
186+
make_filenamepath(metadata_filenamepath)
185187
metadata = {}
188+
supported_operating_systems = ["linux", "win32", "darwin"]
186189

187-
# lshw only works on Linux
188-
try:
189-
lshw_out = subprocess.run(["lshw", "-json"], capture_output=True)
190+
if all(platform != supported for supported in supported_operating_systems):
191+
raise ValueError(f"Platform {platform} not supported for metadata collection")
190192

191-
# sometimes lshw outputs a list of length 1, sometimes just as a dict, schema wants a list
192-
lshw_string = lshw_out.stdout.decode('utf-8').strip()
193-
if lshw_string[0] == '{' and lshw_string[-1] == '}':
194-
lshw_string = '[' + lshw_string + ']'
195-
hardware_desc = dict(lshw=json.loads(lshw_string))
193+
try:
194+
# differentiate between OSes, possible values: https://docs.python.org/3/library/sys.html#sys.platform
195+
if platform == "linux":
196+
os_string = "Linux"
197+
hardware_description_out = subprocess.run(["lshw", "-json"], capture_output=True)
198+
elif platform == "win32":
199+
os_string = "Windows"
200+
raise NotImplementedError("Hardware specification not yet implemented for Windows")
201+
elif platform == "darwin":
202+
os_string = "Mac"
203+
hardware_description_out = subprocess.run(
204+
[
205+
"system_profiler",
206+
"-json",
207+
"-detailLevel",
208+
"mini",
209+
"SPSoftwareDataType",
210+
"SPHardwareDataType",
211+
"SPiBridgeDataType",
212+
"SPPCIDataType",
213+
"SPMemoryDataType",
214+
"SPNVMeDataType",
215+
],
216+
capture_output=True,
217+
)
218+
else:
219+
raise ValueError("This code is supposed to be unreachable, the supported platform check has failed")
220+
221+
# process the hardware description output
222+
hardware_description_string = hardware_description_out.stdout.decode("utf-8").strip()
223+
if hardware_description_string[0] == "{" and hardware_description_string[-1] == "}":
224+
# sometimes lshw outputs a list of length 1, sometimes just as a dict, schema wants a list
225+
hardware_description_string = "[" + hardware_description_string + "]"
226+
metadata["operating_system"] = os_string
196227
except:
197-
hardware_desc = dict(lshw=["lshw error"])
198-
199-
metadata["hardware"] = hardware_desc
228+
hardware_description_string = "[error retrieving hardware description]"
229+
metadata["operating_system"] = "unidentified OS"
230+
metadata["hardware"] = dict(hardware_description=json.loads(hardware_description_string))
200231

201232
# attempts to use nvidia-smi or rocm-smi if present
202233
device_query = {}
203234
try:
204-
device_query['nvidia-smi'] = get_device_query("nvidia")
235+
device_query["nvidia-smi"] = get_device_query("nvidia")
205236
except FileNotFoundError:
206237
# ignore if nvidia-smi is not found
207238
pass
208239

209240
try:
210-
device_query['rocm-smi'] = get_device_query("amd")
241+
device_query["rocm-smi"] = get_device_query("amd")
211242
except FileNotFoundError:
212243
# ignore if rocm-smi is not found
213244
pass
214245

215-
metadata["environment"] = dict(device_query=device_query,
216-
requirements=get_dependencies())
246+
metadata["environment"] = dict(device_query=device_query, requirements=get_dependencies())
217247

218248
# write metadata to JSON file
219249
version, _ = output_file_schema("metadata")
220250
metadata_json = dict(metadata=metadata, schema_version=version)
221-
with open(metadata_filename, 'w+') as fh:
251+
with open(metadata_filenamepath, "w+") as fh:
222252
json.dump(metadata_json, fh, indent=" ")
Lines changed: 45 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,49 @@
11
{
2-
"$schema": "https://json-schema.org/draft/2020-12/schema",
3-
"$id": "https://github.com/odgaard/TuningSchema/blob/T4/metadata-schema.json",
4-
"title": "Open Autotuning Metadata Schema",
5-
"type": "object",
6-
"properties": {
7-
"schema_version": {
8-
"description": "The version number of the schema in major.minor.patch format.",
9-
"type": "string",
10-
"pattern": "^[0-9]{1,}.[0-9]{1,}.[0-9]{1,}$",
11-
"example": "1.0.0"
2+
"$schema": "https://json-schema.org/draft/2020-12/schema",
3+
"$id": "https://github.com/odgaard/TuningSchema/blob/T4/metadata-schema.json",
4+
"title": "Open Autotuning Metadata Schema",
5+
"type": "object",
6+
"properties": {
7+
"schema_version": {
8+
"description": "The version number of the schema in major.minor.patch format.",
9+
"type": "string",
10+
"pattern": "^[0-9]{1,}.[0-9]{1,}.[0-9]{1,}$",
11+
"example": "1.0.0"
12+
},
13+
"metadata": {
14+
"type": "object",
15+
"properties": {
16+
"zenodo": {
17+
"type": "object",
18+
"description": "The zenodo metadata used to publish the artifact"
1219
},
13-
"metadata": {
14-
"type": "object",
15-
"properties": {
16-
"zenodo": {
17-
"type": "object",
18-
"description": "The zenodo metadata used to publish the artifact"
19-
},
20-
"hardware": {
21-
"type": "object",
22-
"properties": {
23-
"lshw": {
24-
"type": "array",
25-
"description": "The output of lshw as JSON"
26-
}
27-
}
28-
},
29-
"environment": {
30-
"type": "object",
31-
"properties": {
32-
"device_query": {
33-
"type": "object",
34-
"description": "The output from tools such as nvidia-smi as JSON"
35-
},
36-
"requirements": {
37-
"type": "array",
38-
"description": "the python libraries used as a list of strings"
39-
}
40-
}
41-
}
20+
"hardware": {
21+
"type": "object",
22+
"properties": {
23+
"hardware_description": {
24+
"type": "array",
25+
"description": "The hardware description in JSON, OS-dependent (e.g. lshw on Linux)"
26+
},
27+
"operating_system": {
28+
"type": "string",
29+
"description": "The operating system used"
4230
}
31+
}
32+
},
33+
"environment": {
34+
"type": "object",
35+
"properties": {
36+
"device_query": {
37+
"type": "object",
38+
"description": "The output from tools such as nvidia-smi as JSON"
39+
},
40+
"requirements": {
41+
"type": "array",
42+
"description": "the python libraries used as a list of strings"
43+
}
44+
}
4345
}
44-
}
45-
}
46+
}
47+
}
48+
}
49+
}

setup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ def readme():
2626
license="Apache 2.0",
2727
keywords="auto-tuning gpu computing pycuda cuda pyopencl opencl",
2828
url="https://KernelTuner.github.io/kernel_tuner/",
29+
include_package_data=True, # use MANIFEST.in during install
2930
project_urls={
3031
"Documentation": "https://KernelTuner.github.io/kernel_tuner/",
3132
"Source": "https://github.com/KernelTuner/kernel_tuner",

0 commit comments

Comments
 (0)