Skip to content

Commit fdf463a

Browse files
authored
Merge pull request #6700 from gmarkall/grm-get-uuid
Add UUID to CUDA devices
2 parents bbd5b43 + 4953137 commit fdf463a

6 files changed

Lines changed: 76 additions & 6 deletions

File tree

‎docs/source/cuda-reference/host.rst‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,11 @@ the functionality of the selected device:
8484

8585
.. attribute:: name
8686

87-
The name of the device (e.g. "GeForce GTX 970")
87+
The name of the device (e.g. "GeForce GTX 970").
88+
89+
.. attribute:: uuid
90+
91+
The UUID of the device (e.g. "GPU-e6489c45-5b68-3b03-bab7-0e7c8e809643").
8892

8993
.. method:: reset
9094

‎docs/source/cuda/device-management.rst‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,3 +74,19 @@ which the current GPU context can also be retrieved:
7474
:members: current
7575
:noindex:
7676

77+
78+
Device UUIDs
79+
============
80+
81+
The UUID of a device (equal to that returned by ``nvidia-smi -L``) is available
82+
in the :attr:`uuid <numba.cuda.cudadrv.driver.Device.uuid>` attribute of a CUDA
83+
device object.
84+
85+
For example, to obtain the UUID of the current device:
86+
87+
.. code-block:: python
88+
89+
dev = cuda.current_context().device
90+
# prints e.g. "GPU-e6489c45-5b68-3b03-bab7-0e7c8e809643"
91+
print(dev.uuid)
92+

‎numba/cuda/cudadrv/driver.py‎

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
from numba.core import utils, serialize, config
3434
from .error import CudaSupportError, CudaDriverError
3535
from .drvapi import API_PROTOTYPES
36-
from .drvapi import cu_occupancy_b2d_size, cu_stream_callback_pyobj
36+
from .drvapi import cu_occupancy_b2d_size, cu_stream_callback_pyobj, cu_uuid
3737
from numba.cuda.cudadrv import enums, drvapi, _extras
3838
from numba.cuda.envvars import get_numba_envvar
3939

@@ -462,17 +462,30 @@ def __init__(self, devnum):
462462
assert devnum == got_devnum.value, "Driver returned another device"
463463
self.id = got_devnum.value
464464
self.attributes = {}
465+
465466
# Read compute capability
466467
cc_major = c_int()
467468
cc_minor = c_int()
468469
driver.cuDeviceComputeCapability(byref(cc_major), byref(cc_minor),
469470
self.id)
470471
self.compute_capability = (cc_major.value, cc_minor.value)
472+
471473
# Read name
472474
bufsz = 128
473475
buf = (c_char * bufsz)()
474476
driver.cuDeviceGetName(buf, bufsz, self.id)
475477
self.name = buf.value
478+
479+
# Read UUID
480+
uuid = cu_uuid()
481+
driver.cuDeviceGetUuid(byref(uuid), self.id)
482+
b = '%02x'
483+
b2 = b * 2
484+
b4 = b * 4
485+
b6 = b * 6
486+
fmt = f'GPU-{b4}-{b2}-{b2}-{b2}-{b6}'
487+
self.uuid = fmt % tuple(bytes(uuid))
488+
476489
self.primary_context = None
477490

478491
def get_device_identity(self):

‎numba/cuda/cudadrv/drvapi.py‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
cu_link_state = c_void_p
1717
cu_function_attribute = c_int
1818
cu_ipc_mem_handle = (c_byte * _extras.CUDA_IPC_HANDLE_SIZE) # 64 bytes wide
19+
cu_uuid = (c_byte * 16) # Device UUID
1920

2021
cu_stream_callback_pyobj = CFUNCTYPE(None, cu_stream, c_int, py_object)
2122

@@ -388,4 +389,6 @@
388389
'cuDeviceCanAccessPeer': (c_int,
389390
POINTER(c_int), cu_device, cu_device),
390391

392+
# CUresult cuDeviceGetUuid ( CUuuid* uuid, CUdevice dev )
393+
'cuDeviceGetUuid': (c_int, POINTER(cu_uuid), cu_device),
391394
}

‎numba/cuda/simulator/cudadrv/devices.py‎

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,19 @@
44
_MemoryInfo = namedtuple("_MemoryInfo", "free,total")
55

66

7-
class FakeCUDAContext(object):
7+
class FakeCUDADevice:
8+
def __init__(self):
9+
self.uuid = 'GPU-00000000-0000-0000-0000-000000000000'
10+
11+
12+
class FakeCUDAContext:
813
'''
914
This stub implements functionality only for simulating a single GPU
1015
at the moment.
1116
'''
12-
def __init__(self, device):
13-
self._device = device
17+
def __init__(self, device_id):
18+
self._device_id = device_id
19+
self._device = FakeCUDADevice()
1420

1521
def __enter__(self):
1622
pass
@@ -23,6 +29,10 @@ def __str__(self):
2329

2430
@property
2531
def id(self):
32+
return self._device_id
33+
34+
@property
35+
def device(self):
2636
return self._device
2737

2838
@property
@@ -53,7 +63,7 @@ def memhostalloc(self, sz, mapped=False, portable=False, wc=False):
5363
return self.memalloc(sz)
5464

5565

56-
class FakeDeviceList(object):
66+
class FakeDeviceList:
5767
'''
5868
This stub implements a device list containing a single GPU. It also
5969
keeps track of the GPU status, i.e. whether the context is closed or not,

‎numba/cuda/tests/cudadrv/test_cuda_driver.py‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from numba.cuda.testing import unittest, CUDATestCase
66
from numba.cuda.testing import skip_on_cudasim
77

8+
89
ptx1 = '''
910
.version 1.4
1011
.target sm_10, map_f64_to_f32
@@ -190,5 +191,28 @@ def b2d(bs):
190191
self.assertTrue(block > 0)
191192

192193

194+
class TestDevice(CUDATestCase):
195+
def test_device_get_uuid(self):
196+
# A device UUID looks like:
197+
#
198+
# GPU-e6489c45-5b68-3b03-bab7-0e7c8e809643
199+
#
200+
# To test, we construct an RE that matches this form and verify that
201+
# the returned UUID matches.
202+
#
203+
# Device UUIDs may not conform to parts of the UUID specification (RFC
204+
# 4122) pertaining to versions and variants, so we do not extract and
205+
# validate the values of these bits.
206+
207+
h = '[0-9a-f]{%d}'
208+
h4 = h % 4
209+
h8 = h % 8
210+
h12 = h % 12
211+
uuid_format = f'^GPU-{h8}-{h4}-{h4}-{h4}-{h12}$'
212+
213+
dev = devices.get_context().device
214+
self.assertRegex(dev.uuid, uuid_format)
215+
216+
193217
if __name__ == '__main__':
194218
unittest.main()

0 commit comments

Comments
 (0)