Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add the cuda.core.experimental.system singleton #256

Merged
merged 15 commits into from
Dec 10, 2024
Merged
1 change: 1 addition & 0 deletions cuda_core/cuda/core/experimental/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@
from cuda.core.experimental._launcher import LaunchConfig, launch
from cuda.core.experimental._program import Program
from cuda.core.experimental._stream import Stream, StreamOptions
from cuda.core.experimental._system import system
68 changes: 68 additions & 0 deletions cuda_core/cuda/core/experimental/_system.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
from typing import Tuple

from cuda import cuda, cudart
from cuda.core.experimental._device import Device
from cuda.core.experimental._utils import handle_return


class System:
""" Provide information about the cuda system.
This class is a singleton and should not be instantiated directly.
"""

_instance = None

def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance

def __init__(self):
if hasattr(self, '_initialized') and self._initialized:
return
self._initialized = True

@property
def driver_version(self) -> Tuple[int, int]:
"""
Query the CUDA driver version.

Returns
-------
tuple of int
A 2-tuple of (major, minor) version numbers.
"""
version = handle_return(cuda.cuDriverGetVersion())
major = version // 1000
minor = (version % 1000) // 10
return (major, minor)

@property
def num_devices(self) -> int:
"""
Query the number of available GPUs.

Returns
-------
int
The number of available GPU devices.
"""
return handle_return(cudart.cudaGetDeviceCount())

@property
def devices(self) -> tuple:
"""
Query the available device instances.

Returns
-------
tuple of Device
A tuple containing instances of available devices.
"""
total = self.num_devices
return tuple(Device(device_id) for device_id in range(total))

system = System()
system.__doc__ = """
Singleton instance of the :obj:`~cuda.core.experimental._system.System` class.
"""
1 change: 1 addition & 0 deletions cuda_core/docs/source/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ CUDA runtime

Device
launch
system

:template: dataclass.rst

Expand Down
1 change: 1 addition & 0 deletions cuda_core/docs/source/api_private.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ CUDA runtime
_memory.Buffer
_stream.Stream
_event.Event
_system.System
ksimpson-work marked this conversation as resolved.
Show resolved Hide resolved


CUDA compilation toolchain
Expand Down
2 changes: 2 additions & 0 deletions cuda_core/docs/source/release.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,6 @@ maxdepth: 3
---

0.1.0 <release/0.1.0-notes>
0.2.0 <release/0.2.0-notes>
ksimpson-work marked this conversation as resolved.
Show resolved Hide resolved

```
10 changes: 10 additions & 0 deletions cuda_core/docs/source/release/0.2.0-notes.md
ksimpson-work marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# `cuda.core` Release notes

Released on <TODO>, 2024

## Hightlights
- Addition of the system singleton
ksimpson-work marked this conversation as resolved.
Show resolved Hide resolved

## Limitations

<TODO>
34 changes: 34 additions & 0 deletions cuda_core/tests/test_system.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
try:
from cuda.bindings import driver, runtime
except ImportError:
from cuda import cuda as driver
from cuda import cudart as runtime

from cuda.core.experimental import Device, system
from cuda.core.experimental._utils import handle_return


def test_system_singleton():
system1 = system
system2 = system
assert system1 is system2, "system is not a singleton"
ksimpson-work marked this conversation as resolved.
Show resolved Hide resolved

def test_driver_version():
driver_version = system.driver_version
print(driver_version)
version = handle_return(driver.cuDriverGetVersion())
expected_driver_version = (version // 1000, (version % 1000) // 10)
assert driver_version == expected_driver_version, "Driver version does not match expected value"

def test_num_devices():
num_devices = system.num_devices
expected_num_devices = handle_return(runtime.cudaGetDeviceCount())
assert num_devices == expected_num_devices, "Number of devices does not match expected value"

def test_devices():
devices = system.devices
expected_num_devices = handle_return(runtime.cudaGetDeviceCount())
expected_devices = tuple(Device(device_id) for device_id in range(expected_num_devices))
assert len(devices) == len(expected_devices), "Number of devices does not match expected value"
for device, expected_device in zip(devices, expected_devices):
assert device.device_id == expected_device.device_id, "Device ID does not match expected value"