Source code for kvikio.cufile_driver

# SPDX-FileCopyrightText: Copyright (c) 2024-2025, NVIDIA CORPORATION. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

import atexit
from typing import Any, Tuple, overload

import kvikio.utils
from kvikio._lib import cufile_driver  # type: ignore

properties = cufile_driver.DriverProperties()
"""cuFile driver configurations. Use kvikio.cufile_driver.get and
   kvikio.cufile_driver.set to access the configurations.
"""


[docs] class ConfigContextManager: """Context manager allowing the cuFile driver configurations to be set upon entering a `with` block, and automatically reset upon leaving the block. """
[docs] def __init__(self, config: dict[str, str]): ( self._property_getters, self._property_setters, self._readonly_property_getters, ) = self._property_getter_and_setter() self._old_properties = {} for key, value in config.items(): self._old_properties[key] = self._get_property(key) self._set_property(key, value)
def __enter__(self): return None def __exit__(self, type_unused, value, traceback_unused): for key, value in self._old_properties.items(): self._set_property(key, value) def _get_property(self, property: str) -> Any: if property in self._property_getters: func = self._property_getters[property] elif property in self._readonly_property_getters: func = self._readonly_property_getters[property] else: raise KeyError # getter signature: object.__get__(self, instance, owner=None) return func(properties) def _set_property(self, property: str, value: Any): if property in self._readonly_property_getters: raise KeyError("This property is read-only.") func = self._property_setters[property] # setter signature: object.__set__(self, instance, value) func(properties, value) @kvikio.utils.call_once def _property_getter_and_setter( self, ) -> tuple[dict[str, Any], dict[str, Any], dict[str, Any]]: class_dict = vars(cufile_driver.DriverProperties) property_getter_names = [ "poll_mode", "poll_thresh_size", "max_device_cache_size", "max_pinned_memory_size", ] property_getters = {} property_setters = {} for name in property_getter_names: property_getters[name] = class_dict[name].__get__ property_setters[name] = class_dict[name].__set__ readonly_property_getter_names = [ "is_gds_available", "major_version", "minor_version", "allow_compat_mode", "per_buffer_cache_size", ] readonly_property_getters = {} for name in readonly_property_getter_names: readonly_property_getters[name] = class_dict[name].__get__ return property_getters, property_setters, readonly_property_getters
@overload def set(config: dict[str, Any], /) -> ConfigContextManager: ... @overload def set(key: str, value: Any, /) -> ConfigContextManager: ...
[docs] def set(*config) -> ConfigContextManager: """Set cuFile driver configurations. Examples: - To set one or more properties .. code-block:: python # Set the property globally. kvikio.cufile_driver.set({"prop1": value1, "prop2": value2}) # Set the property with a context manager. # The property automatically reverts to its old value # after leaving the `with` block. with kvikio.cufile_driver.set({"prop1": value1, "prop2": value2}): ... - To set a single property .. code-block:: python # Set the property globally. kvikio.cufile_driver.set("prop", value) # Set the property with a context manager. # The property automatically reverts to its old value # after leaving the `with` block. with kvikio.cufile_driver.set("prop", value): ... Parameters ---------- config The configurations. Can either be a single parameter (dict) consisting of one or more properties, or two parameters key (string) and value (Any) indicating a single property. Valid configuration names are: - Read-only properties: - ``"is_gds_available"`` - ``"major_version"`` - ``"minor_version"`` - ``"allow_compat_mode"`` - ``"per_buffer_cache_size"`` - Settable properties: - ``"poll_mode"`` - ``"poll_thresh_size"`` - ``"max_device_cache_size"`` - ``"max_pinned_memory_size"`` Returns ------- ConfigContextManager A context manager. If used in a `with` statement, the configuration will revert to its old value upon leaving the block. """ err_msg = ( "Valid arguments are kvikio.cufile_driver.set(config: dict) or " "kvikio.cufile_driver.set(key: str, value: Any)" ) if len(config) == 1: if not isinstance(config[0], dict): raise ValueError(err_msg) return ConfigContextManager(config[0]) elif len(config) == 2: if not isinstance(config[0], str): raise ValueError(err_msg) return ConfigContextManager({config[0]: config[1]}) else: raise ValueError(err_msg)
[docs] def get(config_name: str) -> Any: """Get cuFile driver configurations. Parameters ---------- config_name: str The name of the configuration. Valid configuration names are: - Read-only properties: - ``"is_gds_available"`` - ``"major_version"`` - ``"minor_version"`` - ``"allow_compat_mode"`` - ``"per_buffer_cache_size"`` - Settable properties: - ``"poll_mode"`` - ``"poll_thresh_size"`` - ``"max_device_cache_size"`` - ``"max_pinned_memory_size"`` Returns ------- Any The value of the configuration. """ context_manager = ConfigContextManager({}) return context_manager._get_property(config_name)
[docs] def libcufile_version() -> Tuple[int, int]: """Get the libcufile version. Returns (0, 0) for cuFile versions prior to v1.8. Notes ----- This is not the version of the CUDA toolkit. cufile is part of the toolkit but follows its own version scheme. Returns ------- The version as a tuple (MAJOR, MINOR). """ v = cufile_driver.libcufile_version() # Convert the integer version like 1080 to (1, 8). major, minor = divmod(v, 1000) return (major, minor // 10)
[docs] def driver_open() -> None: """Open the cuFile driver cuFile accepts multiple calls to `driver_open()`. Only the first call opens the driver, but every call must have a matching call to `driver_close()`. Normally, it is not required to open and close the cuFile driver since it is done automatically. Raises ------ RuntimeError If cuFile isn't available. """ return cufile_driver.driver_open()
[docs] def driver_close() -> None: """Close the cuFile driver cuFile accepts multiple calls to `driver_open()`. Only the first call opens the driver, but every call must have a matching call to `driver_close()`. Raises ------ RuntimeError If cuFile isn't available. """ return cufile_driver.driver_close()
[docs] def initialize() -> None: """Open the cuFile driver and close it again at module exit Normally, it is not required to open and close the cuFile driver since it is done automatically. Notes ----- Registers an atexit handler that calls :func:`driver_close`. Raises ------ RuntimeError If cuFile isn't available. """ driver_open() atexit.register(driver_close)