hipfile 0.2.0.dev0__tar.gz → 0.3.0.dev0__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.
- hipfile-0.3.0.dev0/CHANGELOG.md +38 -0
- {hipfile-0.2.0.dev0 → hipfile-0.3.0.dev0}/CMakeLists.txt +23 -4
- {hipfile-0.2.0.dev0 → hipfile-0.3.0.dev0}/PKG-INFO +3 -2
- {hipfile-0.2.0.dev0 → hipfile-0.3.0.dev0}/hipfile/__init__.py +5 -1
- {hipfile-0.2.0.dev0 → hipfile-0.3.0.dev0}/hipfile/_chipfile.pxd +13 -13
- {hipfile-0.2.0.dev0 → hipfile-0.3.0.dev0}/hipfile/_hipfile.pyx +63 -33
- hipfile-0.3.0.dev0/hipfile/buffer.py +133 -0
- hipfile-0.3.0.dev0/hipfile/driver.py +77 -0
- {hipfile-0.2.0.dev0 → hipfile-0.3.0.dev0}/hipfile/enums.py +6 -1
- hipfile-0.3.0.dev0/hipfile/error.py +54 -0
- hipfile-0.3.0.dev0/hipfile/file.py +271 -0
- {hipfile-0.2.0.dev0 → hipfile-0.3.0.dev0}/hipfile/hipMalloc.py +24 -0
- hipfile-0.3.0.dev0/hipfile/properties.py +51 -0
- {hipfile-0.2.0.dev0 → hipfile-0.3.0.dev0}/main.py +4 -0
- {hipfile-0.2.0.dev0 → hipfile-0.3.0.dev0}/pyproject.toml +3 -2
- hipfile-0.2.0.dev0/hipfile/buffer.py +0 -59
- hipfile-0.2.0.dev0/hipfile/driver.py +0 -31
- hipfile-0.2.0.dev0/hipfile/error.py +0 -23
- hipfile-0.2.0.dev0/hipfile/file.py +0 -128
- hipfile-0.2.0.dev0/hipfile/properties.py +0 -20
- {hipfile-0.2.0.dev0 → hipfile-0.3.0.dev0}/README.md +0 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to the hipFile Python bindings will be documented in this file.
|
|
4
|
+
|
|
5
|
+
## [Unreleased]
|
|
6
|
+
|
|
7
|
+
## [0.3.0dev0]
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- Docstrings for the public Python API.
|
|
12
|
+
|
|
13
|
+
## [0.2.0.dev1]
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
|
|
17
|
+
- Release the Python GIL during all C function calls to prevent blocking other
|
|
18
|
+
threads during GPU IO operations. This resolves a performance regression
|
|
19
|
+
observed in multi-threaded applications (e.g., LMCache) when switching from
|
|
20
|
+
ctypes-based bindings to the Cython bindings.
|
|
21
|
+
|
|
22
|
+
### Added
|
|
23
|
+
|
|
24
|
+
- Complete typing hints for the public API.
|
|
25
|
+
|
|
26
|
+
## [0.2.0.dev0]
|
|
27
|
+
|
|
28
|
+
### Added
|
|
29
|
+
|
|
30
|
+
- Initial release of the hipFile Python bindings.
|
|
31
|
+
- Cython-based low-level wrappers for the hipFile C API (`_hipfile.pyx`).
|
|
32
|
+
- High-level Pythonic API: `Driver`, `FileHandle`, `Buffer` classes with
|
|
33
|
+
context manager support.
|
|
34
|
+
- `hipMalloc` / `hipFree` helpers for GPU memory allocation.
|
|
35
|
+
- Error handling via `HipFileException` with hipFile and HIP driver error codes.
|
|
36
|
+
- `FileHandleType` and `OpError` enums.
|
|
37
|
+
- `get_version()` and `driver_get_properties()` utility functions.
|
|
38
|
+
- scikit-build-core based build system.
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
# Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: MIT
|
|
4
|
+
|
|
1
5
|
cmake_minimum_required(VERSION 3.21)
|
|
2
6
|
project(hipfile-python LANGUAGES C)
|
|
3
7
|
|
|
@@ -8,11 +12,27 @@ find_program(CYTHON_EXECUTABLE cython REQUIRED)
|
|
|
8
12
|
|
|
9
13
|
# ---- hipFile library & headers --------------------------------------------
|
|
10
14
|
|
|
15
|
+
# ROCm install hints: prefer $ROCM_PATH from env; fall back to a glob of
|
|
16
|
+
# /opt/rocm/core-* (7.11+ layout) plus legacy /opt/rocm.
|
|
17
|
+
if(DEFINED ENV{ROCM_PATH})
|
|
18
|
+
set(_ROCM_ROOTS "$ENV{ROCM_PATH}")
|
|
19
|
+
else()
|
|
20
|
+
file(GLOB _ROCM_ROOTS "/opt/rocm/core-*")
|
|
21
|
+
list(APPEND _ROCM_ROOTS "/opt/rocm")
|
|
22
|
+
endif()
|
|
23
|
+
|
|
24
|
+
set(_ROCM_INCLUDE_HINTS)
|
|
25
|
+
set(_ROCM_LIB_HINTS)
|
|
26
|
+
foreach(_r IN LISTS _ROCM_ROOTS)
|
|
27
|
+
list(APPEND _ROCM_INCLUDE_HINTS "${_r}/include")
|
|
28
|
+
list(APPEND _ROCM_LIB_HINTS "${_r}/lib")
|
|
29
|
+
endforeach()
|
|
30
|
+
|
|
11
31
|
# hipfile.h location (prefer sibling include/ from source, fall back to installed)
|
|
12
32
|
find_path(HIPFILE_INCLUDE_DIR hipfile.h
|
|
13
33
|
HINTS
|
|
14
34
|
"${CMAKE_CURRENT_SOURCE_DIR}/../include"
|
|
15
|
-
|
|
35
|
+
${_ROCM_INCLUDE_HINTS}
|
|
16
36
|
PATH "Path to directory containing hipfile.h"
|
|
17
37
|
)
|
|
18
38
|
if(NOT HIPFILE_INCLUDE_DIR)
|
|
@@ -25,7 +45,7 @@ endif()
|
|
|
25
45
|
find_library(HIPFILE_LIBRARY hipfile
|
|
26
46
|
HINTS
|
|
27
47
|
"${CMAKE_CURRENT_SOURCE_DIR}/../build/src/amd_detail"
|
|
28
|
-
|
|
48
|
+
${_ROCM_LIB_HINTS}
|
|
29
49
|
)
|
|
30
50
|
if(NOT HIPFILE_LIBRARY)
|
|
31
51
|
message(FATAL_ERROR
|
|
@@ -36,8 +56,7 @@ endif()
|
|
|
36
56
|
# HIP runtime headers (needed because hipfile.h includes hip/hip_runtime_api.h)
|
|
37
57
|
find_path(HIP_INCLUDE_DIR hip/hip_runtime_api.h
|
|
38
58
|
HINTS
|
|
39
|
-
|
|
40
|
-
"/opt/rocm/hip/include"
|
|
59
|
+
${_ROCM_INCLUDE_HINTS}
|
|
41
60
|
)
|
|
42
61
|
if(NOT HIP_INCLUDE_DIR)
|
|
43
62
|
message(FATAL_ERROR
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: hipfile
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0.dev0
|
|
4
4
|
Summary: Python bindings for hipFile — direct-to-GPU file IO via AMD Infinity Storage (AIS)
|
|
5
5
|
Keywords: hipfile,rocm,amd,hip,AIS
|
|
6
6
|
Maintainer-Email: AMD hipFile Team <hipfile-maintainer@amd.com>, Riley Dixon <riley.dixon@amd.com>
|
|
7
7
|
License: MIT
|
|
8
8
|
Classifier: Development Status :: 3 - Alpha
|
|
9
|
-
Project-URL:
|
|
9
|
+
Project-URL: Homepage, https://github.com/ROCm/rocm-systems/tree/develop/projects/hipfile
|
|
10
|
+
Project-URL: Changelog, https://github.com/ROCm/rocm-systems/blob/develop/projects/hipfile/python/CHANGELOG.md
|
|
10
11
|
Requires-Python: >=3.10
|
|
11
12
|
Description-Content-Type: text/markdown
|
|
12
13
|
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: MIT
|
|
4
|
+
|
|
5
|
+
"""Python bindings for the hipFile GPU-accelerated file I/O library."""
|
|
2
6
|
|
|
3
7
|
from hipfile._hipfile import ( # pylint: disable=E0401,E0611
|
|
4
8
|
# Constants
|
|
@@ -18,7 +18,7 @@ cdef extern from "hip/hip_runtime_api.h":
|
|
|
18
18
|
ctypedef enum hipError_t:
|
|
19
19
|
hipSuccess = 0
|
|
20
20
|
|
|
21
|
-
hipError_t hipPeekAtLastError()
|
|
21
|
+
hipError_t hipPeekAtLastError() nogil
|
|
22
22
|
|
|
23
23
|
|
|
24
24
|
# ---------------------------------------------------------------------------
|
|
@@ -158,33 +158,33 @@ cdef extern from "hipfile.h":
|
|
|
158
158
|
# -- Function declarations ----------------------------------------------
|
|
159
159
|
|
|
160
160
|
# Error
|
|
161
|
-
const char *hipFileGetOpErrorString(hipFileOpError_t status)
|
|
161
|
+
const char *hipFileGetOpErrorString(hipFileOpError_t status) nogil
|
|
162
162
|
|
|
163
163
|
# File handles
|
|
164
164
|
hipFileError_t hipFileHandleRegister(hipFileHandle_t *fh,
|
|
165
|
-
hipFileDescr_t *descr)
|
|
166
|
-
void hipFileHandleDeregister(hipFileHandle_t fh)
|
|
165
|
+
hipFileDescr_t *descr) nogil
|
|
166
|
+
void hipFileHandleDeregister(hipFileHandle_t fh) nogil
|
|
167
167
|
|
|
168
168
|
# Buffer registration
|
|
169
169
|
hipFileError_t hipFileBufRegister(const void *buffer_base,
|
|
170
|
-
size_t length, int flags)
|
|
171
|
-
hipFileError_t hipFileBufDeregister(const void *buffer_base)
|
|
170
|
+
size_t length, int flags) nogil
|
|
171
|
+
hipFileError_t hipFileBufDeregister(const void *buffer_base) nogil
|
|
172
172
|
|
|
173
173
|
# Synchronous I/O
|
|
174
174
|
ssize_t hipFileRead(hipFileHandle_t fh, void *buffer_base, size_t size,
|
|
175
|
-
hoff_t file_offset, hoff_t buffer_offset)
|
|
175
|
+
hoff_t file_offset, hoff_t buffer_offset) nogil
|
|
176
176
|
ssize_t hipFileWrite(hipFileHandle_t fh, const void *buffer_base,
|
|
177
177
|
size_t size, hoff_t file_offset,
|
|
178
|
-
hoff_t buffer_offset)
|
|
178
|
+
hoff_t buffer_offset) nogil
|
|
179
179
|
|
|
180
180
|
# Driver lifecycle
|
|
181
|
-
hipFileError_t hipFileDriverOpen()
|
|
182
|
-
hipFileError_t hipFileDriverClose()
|
|
183
|
-
int64_t hipFileUseCount()
|
|
181
|
+
hipFileError_t hipFileDriverOpen() nogil
|
|
182
|
+
hipFileError_t hipFileDriverClose() nogil
|
|
183
|
+
int64_t hipFileUseCount() nogil
|
|
184
184
|
|
|
185
185
|
# Driver properties
|
|
186
|
-
hipFileError_t hipFileDriverGetProperties(hipFileDriverProps_t *props)
|
|
186
|
+
hipFileError_t hipFileDriverGetProperties(hipFileDriverProps_t *props) nogil
|
|
187
187
|
|
|
188
188
|
# Version
|
|
189
189
|
hipFileError_t hipFileGetVersion(unsigned *major, unsigned *minor,
|
|
190
|
-
unsigned *patch)
|
|
190
|
+
unsigned *patch) nogil
|
|
@@ -9,7 +9,7 @@ Functions that return ``hipFileError_t`` in C return a
|
|
|
9
9
|
|
|
10
10
|
from libc.errno cimport errno
|
|
11
11
|
from libc.string cimport memset
|
|
12
|
-
from libc.stdint cimport uintptr_t
|
|
12
|
+
from libc.stdint cimport int64_t, uintptr_t
|
|
13
13
|
|
|
14
14
|
cimport hipfile._chipfile as _c
|
|
15
15
|
|
|
@@ -96,7 +96,9 @@ def is_hipfile_err(int err_code):
|
|
|
96
96
|
|
|
97
97
|
def hipfile_errstr(int err_code):
|
|
98
98
|
"""Equivalent of the ``HIPFILE_ERRSTR`` C macro."""
|
|
99
|
-
cdef const char *s
|
|
99
|
+
cdef const char *s
|
|
100
|
+
with nogil:
|
|
101
|
+
s = _c.hipFileGetOpErrorString(<_c.hipFileOpError_t>abs(err_code))
|
|
100
102
|
if s == NULL:
|
|
101
103
|
return ""
|
|
102
104
|
return s.decode("utf-8")
|
|
@@ -120,7 +122,9 @@ def hip_drv_err(tuple err):
|
|
|
120
122
|
|
|
121
123
|
def hipFileGetOpErrorString(int status):
|
|
122
124
|
"""Wrapper for ``hipFileGetOpErrorString``."""
|
|
123
|
-
cdef const char *s
|
|
125
|
+
cdef const char *s
|
|
126
|
+
with nogil:
|
|
127
|
+
s = _c.hipFileGetOpErrorString(<_c.hipFileOpError_t>status)
|
|
124
128
|
if s == NULL:
|
|
125
129
|
return ""
|
|
126
130
|
return s.decode("utf-8")
|
|
@@ -132,17 +136,26 @@ def hipFileGetOpErrorString(int status):
|
|
|
132
136
|
|
|
133
137
|
def hipFileDriverOpen():
|
|
134
138
|
"""Wrapper for ``hipFileDriverOpen``."""
|
|
135
|
-
|
|
139
|
+
cdef _c.hipFileError_t e
|
|
140
|
+
with nogil:
|
|
141
|
+
e = _c.hipFileDriverOpen()
|
|
142
|
+
return _err(e)
|
|
136
143
|
|
|
137
144
|
|
|
138
145
|
def hipFileDriverClose():
|
|
139
146
|
"""Wrapper for ``hipFileDriverClose``."""
|
|
140
|
-
|
|
147
|
+
cdef _c.hipFileError_t e
|
|
148
|
+
with nogil:
|
|
149
|
+
e = _c.hipFileDriverClose()
|
|
150
|
+
return _err(e)
|
|
141
151
|
|
|
142
152
|
|
|
143
153
|
def hipFileUseCount():
|
|
144
154
|
"""Wrapper for ``hipFileUseCount``."""
|
|
145
|
-
|
|
155
|
+
cdef int64_t count
|
|
156
|
+
with nogil:
|
|
157
|
+
count = _c.hipFileUseCount()
|
|
158
|
+
return <int>count
|
|
146
159
|
|
|
147
160
|
|
|
148
161
|
# ---------------------------------------------------------------------------
|
|
@@ -155,7 +168,9 @@ def hipFileGetVersion():
|
|
|
155
168
|
Returns ``((major, minor, patch), error_tuple)``.
|
|
156
169
|
"""
|
|
157
170
|
cdef unsigned major = 0, minor = 0, patch = 0
|
|
158
|
-
cdef _c.hipFileError_t e
|
|
171
|
+
cdef _c.hipFileError_t e
|
|
172
|
+
with nogil:
|
|
173
|
+
e = _c.hipFileGetVersion(&major, &minor, &patch)
|
|
159
174
|
return ((major, minor, patch), _err(e))
|
|
160
175
|
|
|
161
176
|
|
|
@@ -178,19 +193,22 @@ def hipFileHandleRegister(uintptr_t handle_value, int handle_type):
|
|
|
178
193
|
"""
|
|
179
194
|
cdef _c.hipFileHandle_t fh = NULL
|
|
180
195
|
cdef _c.hipFileDescr_t descr
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
descr.
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
196
|
+
cdef _c.hipFileError_t e
|
|
197
|
+
with nogil:
|
|
198
|
+
memset(&descr, 0, sizeof(descr))
|
|
199
|
+
descr.type = <_c.hipFileFileHandleType_t>handle_type
|
|
200
|
+
if handle_type == <int>_c.hipFileHandleTypeOpaqueWin32:
|
|
201
|
+
descr.hFile = <void *>handle_value
|
|
202
|
+
else:
|
|
203
|
+
descr.fd = <int>handle_value
|
|
204
|
+
e = _c.hipFileHandleRegister(&fh, &descr)
|
|
188
205
|
return (<uintptr_t>fh, _err(e))
|
|
189
206
|
|
|
190
207
|
|
|
191
208
|
def hipFileHandleDeregister(uintptr_t handle):
|
|
192
209
|
"""Wrapper for ``hipFileHandleDeregister``."""
|
|
193
|
-
|
|
210
|
+
with nogil:
|
|
211
|
+
_c.hipFileHandleDeregister(<_c.hipFileHandle_t>handle)
|
|
194
212
|
|
|
195
213
|
|
|
196
214
|
# ---------------------------------------------------------------------------
|
|
@@ -199,12 +217,18 @@ def hipFileHandleDeregister(uintptr_t handle):
|
|
|
199
217
|
|
|
200
218
|
def hipFileBufRegister(uintptr_t buffer_base, size_t length, int flags=0):
|
|
201
219
|
"""Wrapper for ``hipFileBufRegister``."""
|
|
202
|
-
|
|
220
|
+
cdef _c.hipFileError_t e
|
|
221
|
+
with nogil:
|
|
222
|
+
e = _c.hipFileBufRegister(<const void *>buffer_base, length, flags)
|
|
223
|
+
return _err(e)
|
|
203
224
|
|
|
204
225
|
|
|
205
226
|
def hipFileBufDeregister(uintptr_t buffer_base):
|
|
206
227
|
"""Wrapper for ``hipFileBufDeregister``."""
|
|
207
|
-
|
|
228
|
+
cdef _c.hipFileError_t e
|
|
229
|
+
with nogil:
|
|
230
|
+
e = _c.hipFileBufDeregister(<const void *>buffer_base)
|
|
231
|
+
return _err(e)
|
|
208
232
|
|
|
209
233
|
|
|
210
234
|
# ---------------------------------------------------------------------------
|
|
@@ -222,14 +246,16 @@ def hipFileRead(uintptr_t handle, uintptr_t buffer_base, size_t size,
|
|
|
222
246
|
``-hipFileHipDriverError``, ``extra = hipError_t`` from
|
|
223
247
|
``hipPeekAtLastError()``, otherwise ``extra = 0``
|
|
224
248
|
"""
|
|
225
|
-
cdef ssize_t ret
|
|
226
|
-
<void *>buffer_base, size,
|
|
227
|
-
file_offset, buffer_offset)
|
|
249
|
+
cdef ssize_t ret
|
|
228
250
|
cdef int extra = 0
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
251
|
+
with nogil:
|
|
252
|
+
ret = _c.hipFileRead(<_c.hipFileHandle_t>handle,
|
|
253
|
+
<void *>buffer_base, size,
|
|
254
|
+
file_offset, buffer_offset)
|
|
255
|
+
if ret == -1:
|
|
256
|
+
extra = errno
|
|
257
|
+
elif ret == -<int>_c.hipFileHipDriverError:
|
|
258
|
+
extra = <int>_c.hipPeekAtLastError()
|
|
233
259
|
return (ret, extra)
|
|
234
260
|
|
|
235
261
|
|
|
@@ -244,14 +270,16 @@ def hipFileWrite(uintptr_t handle, uintptr_t buffer_base, size_t size,
|
|
|
244
270
|
``-hipFileHipDriverError``, ``extra = hipError_t`` from
|
|
245
271
|
``hipPeekAtLastError()``, otherwise ``extra = 0``
|
|
246
272
|
"""
|
|
247
|
-
cdef ssize_t ret
|
|
248
|
-
<const void *>buffer_base, size,
|
|
249
|
-
file_offset, buffer_offset)
|
|
273
|
+
cdef ssize_t ret
|
|
250
274
|
cdef int extra = 0
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
275
|
+
with nogil:
|
|
276
|
+
ret = _c.hipFileWrite(<_c.hipFileHandle_t>handle,
|
|
277
|
+
<const void *>buffer_base, size,
|
|
278
|
+
file_offset, buffer_offset)
|
|
279
|
+
if ret == -1:
|
|
280
|
+
extra = errno
|
|
281
|
+
elif ret == -<int>_c.hipFileHipDriverError:
|
|
282
|
+
extra = <int>_c.hipPeekAtLastError()
|
|
255
283
|
return (ret, extra)
|
|
256
284
|
|
|
257
285
|
|
|
@@ -265,8 +293,10 @@ def hipFileDriverGetProperties():
|
|
|
265
293
|
Returns ``(props_dict, error_tuple)``.
|
|
266
294
|
"""
|
|
267
295
|
cdef _c.hipFileDriverProps_t props
|
|
268
|
-
|
|
269
|
-
|
|
296
|
+
cdef _c.hipFileError_t e
|
|
297
|
+
with nogil:
|
|
298
|
+
memset(&props, 0, sizeof(props))
|
|
299
|
+
e = _c.hipFileDriverGetProperties(&props)
|
|
270
300
|
d = {
|
|
271
301
|
"nvfs_major_version": props.nvfs_major_version,
|
|
272
302
|
"nvfs_minor_version": props.nvfs_minor_version,
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: MIT
|
|
4
|
+
|
|
5
|
+
"""GPU memory buffer registration for hipFile I/O."""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from typing import TYPE_CHECKING
|
|
10
|
+
from sys import stderr
|
|
11
|
+
|
|
12
|
+
from hipfile._hipfile import ( # pylint: disable=E0401,E0611
|
|
13
|
+
hipFileBufDeregister,
|
|
14
|
+
hipFileBufRegister,
|
|
15
|
+
)
|
|
16
|
+
from hipfile.error import HipFileException
|
|
17
|
+
|
|
18
|
+
if TYPE_CHECKING:
|
|
19
|
+
from ctypes import c_void_p
|
|
20
|
+
from types import TracebackType
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class Buffer:
|
|
24
|
+
"""Manage registration of a GPU memory buffer with hipFile.
|
|
25
|
+
|
|
26
|
+
``Buffer`` does **not** own the underlying GPU allocation; it only
|
|
27
|
+
manages the hipFile registration lifetime.
|
|
28
|
+
|
|
29
|
+
Supports the context-manager protocol for automatic
|
|
30
|
+
``register``/``deregister``::
|
|
31
|
+
|
|
32
|
+
with Buffer.from_ctypes_void_p(ptr, length, 0) as buf:
|
|
33
|
+
fh.read(buf, length, 0, 0)
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
@classmethod
|
|
37
|
+
def from_ctypes_void_p(
|
|
38
|
+
cls, ctypes_void_p: c_void_p, length: int, flags: int
|
|
39
|
+
) -> Buffer:
|
|
40
|
+
"""Create a ``Buffer`` from a ``ctypes.c_void_p``.
|
|
41
|
+
|
|
42
|
+
Parameters
|
|
43
|
+
----------
|
|
44
|
+
ctypes_void_p : ctypes.c_void_p
|
|
45
|
+
Pointer to GPU memory. Must not be null.
|
|
46
|
+
length : int
|
|
47
|
+
Size of the buffer in bytes.
|
|
48
|
+
flags : int
|
|
49
|
+
Registration flags (pass ``0`` for default behavior).
|
|
50
|
+
|
|
51
|
+
Raises
|
|
52
|
+
------
|
|
53
|
+
ValueError
|
|
54
|
+
If *ctypes_void_p* is null.
|
|
55
|
+
"""
|
|
56
|
+
if ctypes_void_p.value is None:
|
|
57
|
+
raise ValueError("Cannot pass in a null pointer.")
|
|
58
|
+
return cls(ctypes_void_p.value, length, flags)
|
|
59
|
+
|
|
60
|
+
def __init__(self, buffer_ptr: int, length: int, flags: int) -> None:
|
|
61
|
+
"""Initialize a ``Buffer`` from a raw integer pointer.
|
|
62
|
+
|
|
63
|
+
Parameters
|
|
64
|
+
----------
|
|
65
|
+
buffer_ptr : int
|
|
66
|
+
Integer address of the GPU memory.
|
|
67
|
+
length : int
|
|
68
|
+
Size of the buffer in bytes.
|
|
69
|
+
flags : int
|
|
70
|
+
Registration flags (pass ``0`` for default behavior).
|
|
71
|
+
"""
|
|
72
|
+
self._buffer_ptr = buffer_ptr
|
|
73
|
+
self._flags = flags
|
|
74
|
+
self._length = length
|
|
75
|
+
self._registered = False
|
|
76
|
+
|
|
77
|
+
def __del__(self) -> None:
|
|
78
|
+
"""Deregister on garbage collection if still registered."""
|
|
79
|
+
# We did not create the underlying buffer. Don't try to free it.
|
|
80
|
+
try:
|
|
81
|
+
self.deregister()
|
|
82
|
+
except Exception: # pylint: disable=W0718 # Suppress exceptions in a dtor
|
|
83
|
+
print(
|
|
84
|
+
"Failed to deregister hipFile.Buffer at destruction time.", file=stderr
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
def __enter__(self) -> Buffer:
|
|
88
|
+
"""Register the buffer and return *self*."""
|
|
89
|
+
self.register()
|
|
90
|
+
return self
|
|
91
|
+
|
|
92
|
+
def __exit__(
|
|
93
|
+
self,
|
|
94
|
+
exc_type: type[BaseException] | None,
|
|
95
|
+
exc: BaseException | None,
|
|
96
|
+
tb: TracebackType | None,
|
|
97
|
+
) -> None:
|
|
98
|
+
"""Deregister the buffer."""
|
|
99
|
+
self.deregister()
|
|
100
|
+
|
|
101
|
+
@property
|
|
102
|
+
def ptr(self) -> int:
|
|
103
|
+
"""Integer address of the GPU memory."""
|
|
104
|
+
return self._buffer_ptr
|
|
105
|
+
|
|
106
|
+
def deregister(self) -> None:
|
|
107
|
+
"""Deregister the buffer from the hipFile driver.
|
|
108
|
+
|
|
109
|
+
This is a no-op if the buffer is not currently registered.
|
|
110
|
+
|
|
111
|
+
Raises
|
|
112
|
+
------
|
|
113
|
+
HipFileException
|
|
114
|
+
If the deregistration call fails.
|
|
115
|
+
"""
|
|
116
|
+
if self._registered:
|
|
117
|
+
err = hipFileBufDeregister(self._buffer_ptr)
|
|
118
|
+
if err[0] != 0:
|
|
119
|
+
raise HipFileException(err[0], err[1])
|
|
120
|
+
self._registered = False
|
|
121
|
+
|
|
122
|
+
def register(self) -> None:
|
|
123
|
+
"""Register the buffer with the hipFile driver.
|
|
124
|
+
|
|
125
|
+
Raises
|
|
126
|
+
------
|
|
127
|
+
HipFileException
|
|
128
|
+
If the registration call fails.
|
|
129
|
+
"""
|
|
130
|
+
err = hipFileBufRegister(self._buffer_ptr, self._length, self._flags)
|
|
131
|
+
if err[0] != 0:
|
|
132
|
+
raise HipFileException(err[0], err[1])
|
|
133
|
+
self._registered = True
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: MIT
|
|
4
|
+
|
|
5
|
+
"""hipFile driver lifecycle management."""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from typing import TYPE_CHECKING
|
|
10
|
+
|
|
11
|
+
from hipfile._hipfile import ( # pylint: disable=E0401,E0611
|
|
12
|
+
hipFileDriverOpen,
|
|
13
|
+
hipFileDriverClose,
|
|
14
|
+
hipFileUseCount,
|
|
15
|
+
)
|
|
16
|
+
from hipfile.error import HipFileException
|
|
17
|
+
|
|
18
|
+
if TYPE_CHECKING:
|
|
19
|
+
from types import TracebackType
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class Driver:
|
|
23
|
+
"""Manage the hipFile driver lifecycle.
|
|
24
|
+
|
|
25
|
+
Wraps the driver open/close calls and supports the
|
|
26
|
+
context-manager protocol::
|
|
27
|
+
|
|
28
|
+
with Driver() as drv:
|
|
29
|
+
... # driver is open
|
|
30
|
+
# driver is closed
|
|
31
|
+
|
|
32
|
+
The driver is reference-counted internally; multiple ``open``
|
|
33
|
+
calls are balanced by an equal number of ``close`` calls.
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
@staticmethod
|
|
37
|
+
def use_count() -> int:
|
|
38
|
+
"""Return the current driver reference count."""
|
|
39
|
+
return hipFileUseCount()
|
|
40
|
+
|
|
41
|
+
def __enter__(self) -> Driver:
|
|
42
|
+
"""Open the driver and return *self*."""
|
|
43
|
+
self.open()
|
|
44
|
+
return self
|
|
45
|
+
|
|
46
|
+
def __exit__(
|
|
47
|
+
self,
|
|
48
|
+
exc_type: type[BaseException] | None,
|
|
49
|
+
exc_value: BaseException | None,
|
|
50
|
+
traceback: TracebackType | None,
|
|
51
|
+
) -> None:
|
|
52
|
+
"""Close the driver."""
|
|
53
|
+
self.close()
|
|
54
|
+
|
|
55
|
+
def close(self) -> None:
|
|
56
|
+
"""Close the hipFile driver.
|
|
57
|
+
|
|
58
|
+
Raises
|
|
59
|
+
------
|
|
60
|
+
HipFileException
|
|
61
|
+
If the close call fails.
|
|
62
|
+
"""
|
|
63
|
+
err = hipFileDriverClose()
|
|
64
|
+
if err[0] != 0:
|
|
65
|
+
raise HipFileException(err[0], err[1])
|
|
66
|
+
|
|
67
|
+
def open(self) -> None:
|
|
68
|
+
"""Open the hipFile driver.
|
|
69
|
+
|
|
70
|
+
Raises
|
|
71
|
+
------
|
|
72
|
+
HipFileException
|
|
73
|
+
If the open call fails.
|
|
74
|
+
"""
|
|
75
|
+
err = hipFileDriverOpen()
|
|
76
|
+
if err[0] != 0:
|
|
77
|
+
raise HipFileException(err[0], err[1])
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: MIT
|
|
4
|
+
|
|
5
|
+
"""Enumerations mirroring hipFile C types."""
|
|
6
|
+
|
|
2
7
|
from enum import IntEnum
|
|
3
8
|
|
|
4
9
|
from hipfile._hipfile import ( # pylint: disable=E0401,E0611
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: MIT
|
|
4
|
+
|
|
5
|
+
"""Exception type for hipFile operations."""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from hipfile._hipfile import hipFileGetOpErrorString # pylint: disable=E0401,E0611
|
|
10
|
+
from hipfile.enums import OpError
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class HipFileException(Exception):
|
|
14
|
+
"""Exception raised when a hipFile operation fails.
|
|
15
|
+
|
|
16
|
+
Wraps both the ``hipFileOpError_t`` code and, when the error is
|
|
17
|
+
``HIP_DRIVER_ERROR``, the underlying ``hipError_t`` from the HIP
|
|
18
|
+
runtime.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
def __init__(self, hipfile_err: int, hip_err: int) -> None:
|
|
22
|
+
"""Initialize a ``HipFileException``.
|
|
23
|
+
|
|
24
|
+
Parameters
|
|
25
|
+
----------
|
|
26
|
+
hipfile_err : int
|
|
27
|
+
``hipFileOpError_t`` value describing the failure.
|
|
28
|
+
hip_err : int
|
|
29
|
+
``hipError_t`` value from the HIP runtime. Only meaningful
|
|
30
|
+
when *hipfile_err* equals ``OpError.HIP_DRIVER_ERROR``.
|
|
31
|
+
"""
|
|
32
|
+
self._hipfile_err = hipfile_err
|
|
33
|
+
self._hip_err = hip_err
|
|
34
|
+
|
|
35
|
+
@property
|
|
36
|
+
def hipfile_err(self) -> int:
|
|
37
|
+
"""``hipFileOpError_t`` code for this error."""
|
|
38
|
+
return self._hipfile_err
|
|
39
|
+
|
|
40
|
+
@property
|
|
41
|
+
def hip_err(self) -> int:
|
|
42
|
+
"""``hipError_t`` code from the HIP runtime.
|
|
43
|
+
|
|
44
|
+
Only meaningful when ``hipfile_err`` equals
|
|
45
|
+
``OpError.HIP_DRIVER_ERROR``.
|
|
46
|
+
"""
|
|
47
|
+
return self._hip_err
|
|
48
|
+
|
|
49
|
+
def __str__(self) -> str:
|
|
50
|
+
"""Return a human-readable description of the error."""
|
|
51
|
+
err_msg = f"{self._hipfile_err} - {hipFileGetOpErrorString(self._hipfile_err)}"
|
|
52
|
+
if self._hipfile_err == OpError.HIP_DRIVER_ERROR:
|
|
53
|
+
err_msg += f" {self._hip_err}"
|
|
54
|
+
return err_msg
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
# Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: MIT
|
|
4
|
+
|
|
5
|
+
"""GPU-accelerated file I/O through hipFile."""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import os
|
|
10
|
+
import stat
|
|
11
|
+
from sys import stderr
|
|
12
|
+
from typing import TYPE_CHECKING
|
|
13
|
+
|
|
14
|
+
from hipfile._hipfile import ( # pylint: disable=E0401,E0611
|
|
15
|
+
hipFileHandleRegister,
|
|
16
|
+
hipFileHandleDeregister,
|
|
17
|
+
hipFileRead,
|
|
18
|
+
hipFileWrite,
|
|
19
|
+
)
|
|
20
|
+
from hipfile.enums import FileHandleType
|
|
21
|
+
from hipfile.error import HipFileException
|
|
22
|
+
|
|
23
|
+
if TYPE_CHECKING:
|
|
24
|
+
from types import TracebackType
|
|
25
|
+
|
|
26
|
+
from hipfile.buffer import Buffer
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class FileHandle:
|
|
30
|
+
"""Manage a file descriptor registered with the hipFile driver.
|
|
31
|
+
|
|
32
|
+
Wraps ``os.open``/``os.close`` together with hipFile handle
|
|
33
|
+
registration so that GPU-accelerated reads and writes can be
|
|
34
|
+
performed through a single object.
|
|
35
|
+
|
|
36
|
+
Supports the context-manager protocol for automatic
|
|
37
|
+
``open``/``close``::
|
|
38
|
+
|
|
39
|
+
with FileHandle(path, os.O_RDONLY | os.O_DIRECT) as fh:
|
|
40
|
+
fh.read(buf, size, 0, 0)
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
DEFAULT_MODE = stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH # 0o644
|
|
44
|
+
|
|
45
|
+
def __init__(
|
|
46
|
+
self,
|
|
47
|
+
path: str | os.PathLike[str],
|
|
48
|
+
flags: int,
|
|
49
|
+
mode: int = DEFAULT_MODE,
|
|
50
|
+
handle_type: FileHandleType = FileHandleType.OPAQUE_FD,
|
|
51
|
+
) -> None:
|
|
52
|
+
"""Initialize a ``FileHandle``.
|
|
53
|
+
|
|
54
|
+
The file is **not** opened until ``open`` is called (or the
|
|
55
|
+
context manager is entered).
|
|
56
|
+
|
|
57
|
+
Parameters
|
|
58
|
+
----------
|
|
59
|
+
path : str or os.PathLike[str]
|
|
60
|
+
Filesystem path to open.
|
|
61
|
+
flags : int
|
|
62
|
+
Flags passed to ``os.open`` (e.g. ``os.O_RDONLY | os.O_DIRECT``).
|
|
63
|
+
mode : int, optional
|
|
64
|
+
Permission bits used when creating a file. Defaults to
|
|
65
|
+
``0o644``.
|
|
66
|
+
handle_type : FileHandleType, optional
|
|
67
|
+
Type of handle to register. Defaults to
|
|
68
|
+
``FileHandleType.OPAQUE_FD``.
|
|
69
|
+
"""
|
|
70
|
+
self._fd: int | None = None
|
|
71
|
+
self._flags = flags
|
|
72
|
+
self._handle: int | None = None
|
|
73
|
+
self._handle_type: FileHandleType | None = None
|
|
74
|
+
self._mode = mode
|
|
75
|
+
self._path = path
|
|
76
|
+
|
|
77
|
+
self.handle_type = handle_type
|
|
78
|
+
|
|
79
|
+
def __del__(self) -> None:
|
|
80
|
+
"""Close on garbage collection if still open."""
|
|
81
|
+
try:
|
|
82
|
+
self.close()
|
|
83
|
+
except Exception: # pylint: disable=W0718 # Suppress exceptions in a dtor
|
|
84
|
+
print(
|
|
85
|
+
"Failed to deregister hipFile.FileHandle at destruction time.",
|
|
86
|
+
file=stderr,
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
def __enter__(self) -> FileHandle:
|
|
90
|
+
"""Open the file and return *self*."""
|
|
91
|
+
self.open()
|
|
92
|
+
return self
|
|
93
|
+
|
|
94
|
+
def __exit__(
|
|
95
|
+
self,
|
|
96
|
+
exc_type: type[BaseException] | None,
|
|
97
|
+
exc_value: BaseException | None,
|
|
98
|
+
traceback: TracebackType | None,
|
|
99
|
+
) -> None:
|
|
100
|
+
"""Close the file."""
|
|
101
|
+
self.close()
|
|
102
|
+
|
|
103
|
+
@property
|
|
104
|
+
def flags(self) -> int:
|
|
105
|
+
"""Flags passed to ``os.open``."""
|
|
106
|
+
return self._flags
|
|
107
|
+
|
|
108
|
+
@property
|
|
109
|
+
def handle(self) -> int | None:
|
|
110
|
+
"""Opaque hipFile handle, or ``None`` if not open."""
|
|
111
|
+
return self._handle
|
|
112
|
+
|
|
113
|
+
@property
|
|
114
|
+
def handle_type(self) -> FileHandleType | None:
|
|
115
|
+
"""Handle type used for registration."""
|
|
116
|
+
return self._handle_type
|
|
117
|
+
|
|
118
|
+
@handle_type.setter
|
|
119
|
+
def handle_type(self, _handle_type: FileHandleType) -> None:
|
|
120
|
+
"""Set the handle type.
|
|
121
|
+
|
|
122
|
+
Raises
|
|
123
|
+
------
|
|
124
|
+
RuntimeError
|
|
125
|
+
If the file handle is already open.
|
|
126
|
+
ValueError
|
|
127
|
+
If *_handle_type* is not a ``FileHandleType`` member.
|
|
128
|
+
NotImplementedError
|
|
129
|
+
If *_handle_type* is ``OPAQUE_WIN32``.
|
|
130
|
+
"""
|
|
131
|
+
if self._handle is not None:
|
|
132
|
+
raise RuntimeError("Cannot modify handle_type while FileHandle is open")
|
|
133
|
+
if _handle_type not in FileHandleType:
|
|
134
|
+
raise ValueError(f"'{_handle_type}' is not a member of enum FileHandleType")
|
|
135
|
+
if _handle_type == FileHandleType.OPAQUE_WIN32:
|
|
136
|
+
raise NotImplementedError(
|
|
137
|
+
"FileHandle does not currently support Win32 Handles"
|
|
138
|
+
)
|
|
139
|
+
self._handle_type = _handle_type
|
|
140
|
+
|
|
141
|
+
@property
|
|
142
|
+
def mode(self) -> int:
|
|
143
|
+
"""File creation permission bits."""
|
|
144
|
+
return self._mode
|
|
145
|
+
|
|
146
|
+
@property
|
|
147
|
+
def path(self) -> str | os.PathLike[str]:
|
|
148
|
+
"""Filesystem path."""
|
|
149
|
+
return self._path
|
|
150
|
+
|
|
151
|
+
def open(self) -> None:
|
|
152
|
+
"""Open the file and register it with the hipFile driver.
|
|
153
|
+
|
|
154
|
+
Raises
|
|
155
|
+
------
|
|
156
|
+
RuntimeError
|
|
157
|
+
If the file handle is already open.
|
|
158
|
+
HipFileException
|
|
159
|
+
If hipFile handle registration fails.
|
|
160
|
+
"""
|
|
161
|
+
if self._handle is not None:
|
|
162
|
+
raise RuntimeError("The FileHandle is already open.")
|
|
163
|
+
self._fd = os.open(self._path, self._flags, self._mode)
|
|
164
|
+
handle, err = hipFileHandleRegister(self._fd, self._handle_type)
|
|
165
|
+
if err[0] != 0:
|
|
166
|
+
os.close(self._fd)
|
|
167
|
+
self._fd = None
|
|
168
|
+
raise HipFileException(err[0], err[1])
|
|
169
|
+
self._handle = handle
|
|
170
|
+
|
|
171
|
+
def close(self) -> None:
|
|
172
|
+
"""Deregister the hipFile handle and close the file descriptor.
|
|
173
|
+
|
|
174
|
+
Safe to call multiple times; subsequent calls are no-ops.
|
|
175
|
+
"""
|
|
176
|
+
if self._handle is not None:
|
|
177
|
+
hipFileHandleDeregister(self._handle)
|
|
178
|
+
self._handle = None
|
|
179
|
+
if self._fd is not None:
|
|
180
|
+
os.close(self._fd)
|
|
181
|
+
self._fd = None
|
|
182
|
+
|
|
183
|
+
def read(
|
|
184
|
+
self, buffer: Buffer, size: int, file_offset: int, buffer_offset: int
|
|
185
|
+
) -> int:
|
|
186
|
+
"""Read from the file into a GPU buffer.
|
|
187
|
+
|
|
188
|
+
Parameters
|
|
189
|
+
----------
|
|
190
|
+
buffer : Buffer
|
|
191
|
+
GPU buffer to read into.
|
|
192
|
+
size : int
|
|
193
|
+
Number of bytes to read.
|
|
194
|
+
file_offset : int
|
|
195
|
+
Byte offset within the file to start reading from.
|
|
196
|
+
buffer_offset : int
|
|
197
|
+
Byte offset within the GPU buffer to read into.
|
|
198
|
+
|
|
199
|
+
Returns
|
|
200
|
+
-------
|
|
201
|
+
int
|
|
202
|
+
Number of bytes actually read.
|
|
203
|
+
|
|
204
|
+
Raises
|
|
205
|
+
------
|
|
206
|
+
RuntimeError
|
|
207
|
+
If the file handle is not open.
|
|
208
|
+
OSError
|
|
209
|
+
On a system-level I/O error (wraps ``errno``).
|
|
210
|
+
HipFileException
|
|
211
|
+
On a hipFile or HIP driver error.
|
|
212
|
+
"""
|
|
213
|
+
if self._handle is None:
|
|
214
|
+
raise RuntimeError("The FileHandle is not open.")
|
|
215
|
+
bytes_read, extra_err = hipFileRead(
|
|
216
|
+
self._handle, buffer.ptr, size, file_offset, buffer_offset
|
|
217
|
+
)
|
|
218
|
+
if bytes_read == -1:
|
|
219
|
+
# extra_err is errno
|
|
220
|
+
raise OSError(extra_err, os.strerror(extra_err))
|
|
221
|
+
if bytes_read < -1:
|
|
222
|
+
# hipFile Error
|
|
223
|
+
# If -bytes_read == OpError.HIP_DRIVER_ERROR, extra_err is hipError_t.
|
|
224
|
+
# Otherwise, extra_err is 0.
|
|
225
|
+
raise HipFileException(-bytes_read, extra_err)
|
|
226
|
+
return bytes_read
|
|
227
|
+
|
|
228
|
+
def write(
|
|
229
|
+
self, buffer: Buffer, size: int, file_offset: int, buffer_offset: int
|
|
230
|
+
) -> int:
|
|
231
|
+
"""Write from a GPU buffer into the file.
|
|
232
|
+
|
|
233
|
+
Parameters
|
|
234
|
+
----------
|
|
235
|
+
buffer : Buffer
|
|
236
|
+
GPU buffer to write from.
|
|
237
|
+
size : int
|
|
238
|
+
Number of bytes to write.
|
|
239
|
+
file_offset : int
|
|
240
|
+
Byte offset within the file to start writing to.
|
|
241
|
+
buffer_offset : int
|
|
242
|
+
Byte offset within the GPU buffer to write from.
|
|
243
|
+
|
|
244
|
+
Returns
|
|
245
|
+
-------
|
|
246
|
+
int
|
|
247
|
+
Number of bytes actually written.
|
|
248
|
+
|
|
249
|
+
Raises
|
|
250
|
+
------
|
|
251
|
+
RuntimeError
|
|
252
|
+
If the file handle is not open.
|
|
253
|
+
OSError
|
|
254
|
+
On a system-level I/O error (wraps ``errno``).
|
|
255
|
+
HipFileException
|
|
256
|
+
On a hipFile or HIP driver error.
|
|
257
|
+
"""
|
|
258
|
+
if self._handle is None:
|
|
259
|
+
raise RuntimeError("The FileHandle is not open.")
|
|
260
|
+
bytes_written, extra_err = hipFileWrite(
|
|
261
|
+
self._handle, buffer.ptr, size, file_offset, buffer_offset
|
|
262
|
+
)
|
|
263
|
+
if bytes_written == -1:
|
|
264
|
+
# extra_err is errno
|
|
265
|
+
raise OSError(extra_err, os.strerror(extra_err))
|
|
266
|
+
if bytes_written < -1:
|
|
267
|
+
# hipFile Error
|
|
268
|
+
# If -bytes_written == OpError.HIP_DRIVER_ERROR, extra_err is hipError_t.
|
|
269
|
+
# Otherwise, extra_err is 0.
|
|
270
|
+
raise HipFileException(-bytes_written, extra_err)
|
|
271
|
+
return bytes_written
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
+
# Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: MIT
|
|
4
|
+
|
|
1
5
|
# pylint: disable=all
|
|
6
|
+
|
|
2
7
|
"""
|
|
3
8
|
This is a hack to have some semblance of GPU memory management
|
|
4
9
|
without introducing a dependency at this early stage of
|
|
@@ -28,6 +33,18 @@ _hip.hipFree.restype = ctypes.c_int
|
|
|
28
33
|
|
|
29
34
|
|
|
30
35
|
def hipMalloc(size_bytes: int) -> ctypes.c_void_p:
|
|
36
|
+
"""Allocate *size_bytes* of GPU device memory.
|
|
37
|
+
|
|
38
|
+
Returns
|
|
39
|
+
-------
|
|
40
|
+
ctypes.c_void_p
|
|
41
|
+
Pointer to the allocated device memory.
|
|
42
|
+
|
|
43
|
+
Raises
|
|
44
|
+
------
|
|
45
|
+
RuntimeError
|
|
46
|
+
If the HIP runtime reports an error.
|
|
47
|
+
"""
|
|
31
48
|
d_ptr = ctypes.c_void_p()
|
|
32
49
|
status = _hip.hipMalloc(ctypes.byref(d_ptr), ctypes.c_size_t(size_bytes))
|
|
33
50
|
if status != 0:
|
|
@@ -36,6 +53,13 @@ def hipMalloc(size_bytes: int) -> ctypes.c_void_p:
|
|
|
36
53
|
|
|
37
54
|
|
|
38
55
|
def hipFree(ptr: ctypes.c_void_p) -> None:
|
|
56
|
+
"""Free GPU device memory previously allocated by ``hipMalloc``.
|
|
57
|
+
|
|
58
|
+
Raises
|
|
59
|
+
------
|
|
60
|
+
RuntimeError
|
|
61
|
+
If the HIP runtime reports an error.
|
|
62
|
+
"""
|
|
39
63
|
status = _hip.hipFree(ptr)
|
|
40
64
|
if status != 0:
|
|
41
65
|
raise RuntimeError(f"hipFree failed ({status})")
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Copyright (c) Advanced Micro Devices, Inc. All rights reserved.
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: MIT
|
|
4
|
+
|
|
5
|
+
"""Query hipFile driver properties and version information."""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from hipfile._hipfile import ( # pylint: disable=E0401,E0611
|
|
10
|
+
hipFileDriverGetProperties,
|
|
11
|
+
hipFileGetVersion,
|
|
12
|
+
)
|
|
13
|
+
from hipfile.error import HipFileException
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def driver_get_properties() -> dict[str, int]:
|
|
17
|
+
"""Return the current hipFile driver properties.
|
|
18
|
+
|
|
19
|
+
Returns
|
|
20
|
+
-------
|
|
21
|
+
dict[str, int]
|
|
22
|
+
Property names mapped to their integer values.
|
|
23
|
+
|
|
24
|
+
Raises
|
|
25
|
+
------
|
|
26
|
+
HipFileException
|
|
27
|
+
If the properties query fails.
|
|
28
|
+
"""
|
|
29
|
+
_props, err = hipFileDriverGetProperties()
|
|
30
|
+
if err[0] != 0:
|
|
31
|
+
raise HipFileException(err[0], err[1])
|
|
32
|
+
return _props
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def get_version() -> tuple[int, int, int]:
|
|
36
|
+
"""Return the hipFile driver version.
|
|
37
|
+
|
|
38
|
+
Returns
|
|
39
|
+
-------
|
|
40
|
+
tuple[int, int, int]
|
|
41
|
+
``(major, minor, patch)`` version components.
|
|
42
|
+
|
|
43
|
+
Raises
|
|
44
|
+
------
|
|
45
|
+
HipFileException
|
|
46
|
+
If the version query fails.
|
|
47
|
+
"""
|
|
48
|
+
version_tuple, err = hipFileGetVersion()
|
|
49
|
+
if err[0] != 0:
|
|
50
|
+
raise HipFileException(err[0], err[1])
|
|
51
|
+
return version_tuple
|
|
@@ -4,7 +4,7 @@ build-backend = "scikit_build_core.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "hipfile"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.3.0.dev0"
|
|
8
8
|
classifiers = [
|
|
9
9
|
"Development Status :: 3 - Alpha",
|
|
10
10
|
]
|
|
@@ -19,7 +19,8 @@ readme = "README.md"
|
|
|
19
19
|
requires-python = ">=3.10"
|
|
20
20
|
|
|
21
21
|
[project.urls]
|
|
22
|
-
|
|
22
|
+
Homepage = "https://github.com/ROCm/rocm-systems/tree/develop/projects/hipfile"
|
|
23
|
+
Changelog = "https://github.com/ROCm/rocm-systems/blob/develop/projects/hipfile/python/CHANGELOG.md"
|
|
23
24
|
|
|
24
25
|
[tool.scikit-build]
|
|
25
26
|
cmake.build-type = "Release"
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
# pylint: disable=C0114,C0115,C0116
|
|
2
|
-
from __future__ import annotations
|
|
3
|
-
from typing import TYPE_CHECKING
|
|
4
|
-
from sys import stderr
|
|
5
|
-
|
|
6
|
-
from hipfile._hipfile import ( # pylint: disable=E0401,E0611
|
|
7
|
-
hipFileBufDeregister,
|
|
8
|
-
hipFileBufRegister,
|
|
9
|
-
)
|
|
10
|
-
from hipfile.error import HipFileException
|
|
11
|
-
|
|
12
|
-
if TYPE_CHECKING:
|
|
13
|
-
from ctypes import c_void_p
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
class Buffer:
|
|
17
|
-
|
|
18
|
-
@classmethod
|
|
19
|
-
def from_ctypes_void_p(cls, ctypes_void_p: c_void_p, length, flags):
|
|
20
|
-
return cls(ctypes_void_p.value, length, flags)
|
|
21
|
-
|
|
22
|
-
def __init__(self, buffer_ptr, length, flags) -> None:
|
|
23
|
-
self._buffer_ptr = buffer_ptr
|
|
24
|
-
self._flags = flags
|
|
25
|
-
self._length = length
|
|
26
|
-
self._registered = False
|
|
27
|
-
|
|
28
|
-
def __del__(self):
|
|
29
|
-
# We did not create the underlying buffer. Don't try to free it.
|
|
30
|
-
try:
|
|
31
|
-
self.deregister()
|
|
32
|
-
except Exception: # pylint: disable=W0718 # Suppress exceptions in a dtor
|
|
33
|
-
print(
|
|
34
|
-
"Failed to deregister hipFile.Buffer at destruction time.", file=stderr
|
|
35
|
-
)
|
|
36
|
-
|
|
37
|
-
def __enter__(self):
|
|
38
|
-
self.register()
|
|
39
|
-
return self
|
|
40
|
-
|
|
41
|
-
def __exit__(self, exc_type, exc, tb):
|
|
42
|
-
self.deregister()
|
|
43
|
-
|
|
44
|
-
@property
|
|
45
|
-
def ptr(self):
|
|
46
|
-
return self._buffer_ptr
|
|
47
|
-
|
|
48
|
-
def deregister(self):
|
|
49
|
-
if self._registered:
|
|
50
|
-
err = hipFileBufDeregister(self._buffer_ptr)
|
|
51
|
-
if err[0] != 0:
|
|
52
|
-
raise HipFileException(err[0], err[1])
|
|
53
|
-
self._registered = False
|
|
54
|
-
|
|
55
|
-
def register(self):
|
|
56
|
-
err = hipFileBufRegister(self._buffer_ptr, self._length, self._flags)
|
|
57
|
-
if err[0] != 0:
|
|
58
|
-
raise HipFileException(err[0], err[1])
|
|
59
|
-
self._registered = True
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
# pylint: disable=C0114,C0115,C0116
|
|
2
|
-
from hipfile._hipfile import ( # pylint: disable=E0401,E0611
|
|
3
|
-
hipFileDriverOpen,
|
|
4
|
-
hipFileDriverClose,
|
|
5
|
-
hipFileUseCount,
|
|
6
|
-
)
|
|
7
|
-
from hipfile.error import HipFileException
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
class Driver:
|
|
11
|
-
|
|
12
|
-
@staticmethod
|
|
13
|
-
def use_count():
|
|
14
|
-
return hipFileUseCount()
|
|
15
|
-
|
|
16
|
-
def __enter__(self):
|
|
17
|
-
self.open()
|
|
18
|
-
return self
|
|
19
|
-
|
|
20
|
-
def __exit__(self, exc_type, exc_value, traceback):
|
|
21
|
-
self.close()
|
|
22
|
-
|
|
23
|
-
def close(self):
|
|
24
|
-
err = hipFileDriverClose()
|
|
25
|
-
if err[0] != 0:
|
|
26
|
-
raise HipFileException(err[0], err[1])
|
|
27
|
-
|
|
28
|
-
def open(self):
|
|
29
|
-
err = hipFileDriverOpen()
|
|
30
|
-
if err[0] != 0:
|
|
31
|
-
raise HipFileException(err[0], err[1])
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
# pylint: disable=C0114,C0115,C0116
|
|
2
|
-
from hipfile._hipfile import hipFileGetOpErrorString # pylint: disable=E0401,E0611
|
|
3
|
-
from hipfile.enums import OpError
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
class HipFileException(Exception):
|
|
7
|
-
def __init__(self, hipfile_err, hip_err):
|
|
8
|
-
self._hipfile_err = hipfile_err
|
|
9
|
-
self._hip_err = hip_err
|
|
10
|
-
|
|
11
|
-
@property
|
|
12
|
-
def hipfile_err(self):
|
|
13
|
-
return self._hipfile_err
|
|
14
|
-
|
|
15
|
-
@property
|
|
16
|
-
def hip_err(self):
|
|
17
|
-
return self._hip_err
|
|
18
|
-
|
|
19
|
-
def __str__(self):
|
|
20
|
-
err_msg = f"{self._hipfile_err} - {hipFileGetOpErrorString(self._hipfile_err)}"
|
|
21
|
-
if self._hipfile_err == OpError.HIP_DRIVER_ERROR:
|
|
22
|
-
err_msg += f" {self._hip_err}"
|
|
23
|
-
return err_msg
|
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
# pylint: disable=C0114,C0115,C0116
|
|
2
|
-
import os
|
|
3
|
-
import stat
|
|
4
|
-
from sys import stderr
|
|
5
|
-
|
|
6
|
-
from hipfile._hipfile import ( # pylint: disable=E0401,E0611
|
|
7
|
-
hipFileHandleRegister,
|
|
8
|
-
hipFileHandleDeregister,
|
|
9
|
-
hipFileRead,
|
|
10
|
-
hipFileWrite,
|
|
11
|
-
)
|
|
12
|
-
from hipfile.enums import FileHandleType
|
|
13
|
-
from hipfile.error import HipFileException
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
class FileHandle:
|
|
17
|
-
DEFAULT_MODE = stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH
|
|
18
|
-
|
|
19
|
-
def __init__(
|
|
20
|
-
self, path, flags, mode=DEFAULT_MODE, handle_type=FileHandleType.OPAQUE_FD
|
|
21
|
-
):
|
|
22
|
-
self._fd = None
|
|
23
|
-
self._flags = flags
|
|
24
|
-
self._handle = None
|
|
25
|
-
self._handle_type = None
|
|
26
|
-
self._mode = mode
|
|
27
|
-
self._path = path
|
|
28
|
-
|
|
29
|
-
self.handle_type = handle_type
|
|
30
|
-
|
|
31
|
-
def __del__(self):
|
|
32
|
-
try:
|
|
33
|
-
self.close()
|
|
34
|
-
except Exception: # pylint: disable=W0718 # Suppress exceptions in a dtor
|
|
35
|
-
print(
|
|
36
|
-
"Failed to deregister hipFile.FileHandle at destruction time.",
|
|
37
|
-
file=stderr,
|
|
38
|
-
)
|
|
39
|
-
|
|
40
|
-
def __enter__(self):
|
|
41
|
-
self.open()
|
|
42
|
-
return self
|
|
43
|
-
|
|
44
|
-
def __exit__(self, exc_type, exc_value, traceback):
|
|
45
|
-
self.close()
|
|
46
|
-
|
|
47
|
-
@property
|
|
48
|
-
def flags(self):
|
|
49
|
-
return self._flags
|
|
50
|
-
|
|
51
|
-
@property
|
|
52
|
-
def handle(self):
|
|
53
|
-
return self._handle
|
|
54
|
-
|
|
55
|
-
@property
|
|
56
|
-
def handle_type(self):
|
|
57
|
-
return self._handle_type
|
|
58
|
-
|
|
59
|
-
@handle_type.setter
|
|
60
|
-
def handle_type(self, _handle_type):
|
|
61
|
-
if self._handle is not None:
|
|
62
|
-
raise RuntimeError("Cannot modify handle_type while FileHandle is open")
|
|
63
|
-
if _handle_type not in FileHandleType:
|
|
64
|
-
raise ValueError(f"'{_handle_type}' is not a member of enum FileHandleType")
|
|
65
|
-
if _handle_type == FileHandleType.OPAQUE_WIN32:
|
|
66
|
-
raise NotImplementedError(
|
|
67
|
-
"FileHandle does not currently support Win32 Handles"
|
|
68
|
-
)
|
|
69
|
-
self._handle_type = _handle_type
|
|
70
|
-
|
|
71
|
-
@property
|
|
72
|
-
def mode(self):
|
|
73
|
-
return self._mode
|
|
74
|
-
|
|
75
|
-
@property
|
|
76
|
-
def path(self):
|
|
77
|
-
return self._path
|
|
78
|
-
|
|
79
|
-
def open(self):
|
|
80
|
-
if self._handle is not None:
|
|
81
|
-
raise RuntimeError("The FileHandle is already open.")
|
|
82
|
-
self._fd = os.open(self._path, self._flags, self._mode)
|
|
83
|
-
handle, err = hipFileHandleRegister(self._fd, self._handle_type)
|
|
84
|
-
if err[0] != 0:
|
|
85
|
-
os.close(self._fd)
|
|
86
|
-
self._fd = None
|
|
87
|
-
raise HipFileException(err[0], err[1])
|
|
88
|
-
self._handle = handle
|
|
89
|
-
|
|
90
|
-
def close(self):
|
|
91
|
-
if self._handle is not None:
|
|
92
|
-
hipFileHandleDeregister(self._handle)
|
|
93
|
-
self._handle = None
|
|
94
|
-
if self._fd is not None:
|
|
95
|
-
os.close(self._fd)
|
|
96
|
-
self._fd = None
|
|
97
|
-
|
|
98
|
-
def read(self, buffer, size, file_offset, buffer_offset):
|
|
99
|
-
if self._handle is None:
|
|
100
|
-
raise RuntimeError("The FileHandle is not open.")
|
|
101
|
-
bytes_read, extra_err = hipFileRead(
|
|
102
|
-
self._handle, buffer.ptr, size, file_offset, buffer_offset
|
|
103
|
-
)
|
|
104
|
-
if bytes_read == -1:
|
|
105
|
-
# extra_err is errno
|
|
106
|
-
raise OSError(extra_err, os.strerror(extra_err))
|
|
107
|
-
if bytes_read < -1:
|
|
108
|
-
# hipFile Error
|
|
109
|
-
# If -bytes_read == OpError.HIP_DRIVER_ERROR, extra_err is hipError_t.
|
|
110
|
-
# Otherwise, extra_err is 0.
|
|
111
|
-
raise HipFileException(-bytes_read, extra_err)
|
|
112
|
-
return bytes_read
|
|
113
|
-
|
|
114
|
-
def write(self, buffer, size, file_offset, buffer_offset):
|
|
115
|
-
if self._handle is None:
|
|
116
|
-
raise RuntimeError("The FileHandle is not open.")
|
|
117
|
-
bytes_written, extra_err = hipFileWrite(
|
|
118
|
-
self._handle, buffer.ptr, size, file_offset, buffer_offset
|
|
119
|
-
)
|
|
120
|
-
if bytes_written == -1:
|
|
121
|
-
# extra_err is errno
|
|
122
|
-
raise OSError(extra_err, os.strerror(extra_err))
|
|
123
|
-
if bytes_written < -1:
|
|
124
|
-
# hipFile Error
|
|
125
|
-
# If -bytes_written == OpError.HIP_DRIVER_ERROR, extra_err is hipError_t.
|
|
126
|
-
# Otherwise, extra_err is 0.
|
|
127
|
-
raise HipFileException(-bytes_written, extra_err)
|
|
128
|
-
return bytes_written
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
# pylint: disable=C0114,C0116
|
|
2
|
-
from hipfile._hipfile import ( # pylint: disable=E0401,E0611
|
|
3
|
-
hipFileDriverGetProperties,
|
|
4
|
-
hipFileGetVersion,
|
|
5
|
-
)
|
|
6
|
-
from hipfile.error import HipFileException
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
def driver_get_properties():
|
|
10
|
-
_props, err = hipFileDriverGetProperties()
|
|
11
|
-
if err[0] != 0:
|
|
12
|
-
raise HipFileException(err[0], err[1])
|
|
13
|
-
return _props
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
def get_version():
|
|
17
|
-
version_tuple, err = hipFileGetVersion()
|
|
18
|
-
if err[0] != 0:
|
|
19
|
-
raise HipFileException(err[0], err[1])
|
|
20
|
-
return version_tuple
|
|
File without changes
|