Source code for rockverse.configure

"Manages runtime settings for the RockVerse library."

import copy
from mpi4py import MPI
from numba import cuda
from contextlib import contextmanager
from rockverse import _assert
from rockverse.errors import collective_raise, CustomCollectiveException
from rockverse.configure.orthogonal_viewer import ORTHOGONAL_VIEWER as _ORTHOGONAL_VIEWER
from rockverse.configure.latex_strings import LATEX_STRINGS as _LATEX_STRINGS

def _split_key(key):
    return key.split('.')


[docs] class Config(): """ Manages runtime settings. """ def __init__(self): self._mpi_comm = MPI.COMM_WORLD self._mpi_rank = MPI.COMM_WORLD.Get_rank() self._mpi_nprocs = MPI.COMM_WORLD.Get_size() self._processor_name = MPI.Get_processor_name() self._dict = {} if not cuda.is_available(): self._gpus = [] self._dict['selected_gpus'] = [] else: self._gpus = cuda.gpus self._dict['selected_gpus'] = list(range(len(self._gpus))) self._dict['latex.strings'] = copy.deepcopy(_LATEX_STRINGS) self._dict['orthogonal_viewer'] = copy.deepcopy(_ORTHOGONAL_VIEWER) def reset(self): self.__init__() def __getitem__(self, item): return self._dict.__getitem__(item) def __setitem__(self, key, value): if key == 'selected_gpus': _assert.iterable.any_iterable_non_negative_integers('device selection', value) if any(k not in range(len(self._gpus)) for k in value): if len(self._gpus) == 0: collective_raise(RuntimeError(f'GPU devices are not available.')) collective_raise(RuntimeError( f'GPU device indices must be less than {len(self._gpus)}.')) self._dict['selected_gpus'] = sorted(set(value)) else: raise ValueError('NO') @property def mpi_rank(self): """ Returns the rank of the calling process in the MPI communicator. """ return self._mpi_rank @property def mpi_nprocs(self): """ Returns the total number of processes in the MPI communicator. """ return self._mpi_nprocs @property def processor_name(self): """ Returns the name of the processor running MPI. """ return self._processor_name @property def mpi_comm(self): """ Returns the MPI communicator object. """ return self._mpi_comm @property def available_gpus(self): """ Returns the list of all GPUs available to the processor in ``processor_name``. """ return self._gpus
[docs] def print_available_gpus(self): """Prints the list of available GPUs. Mimics the output of the `nvidia-smi -L` terminal command. If no GPUs are available, a message indicating this is printed. """ if not self._gpus: print("GPUs not available.") else: for g, gpu in enumerate(self._gpus): print(f'GPU {g}: {gpu.name.decode()} (UUID: {gpu._device.uuid})')
[docs] def print_selected_gpus(self): """ Prints the list of user-selected GPUs. Mimics the output of the `nvidia-smi -L` terminal command. If no GPUs are available, a message indicating this is printed. """ if not self._gpus: print("GPUs not available.") else: for g, gpu in enumerate(self._gpus): if g in self['selected_gpus']: print(f'GPU {g}: {gpu.name.decode()} (UUID: {gpu._device.uuid})')
[docs] def rank_select_gpu(self): """ Selects the GPU to be used by the current MPI process at runtime. The selection is based on the user-select GPUs. Returns: The index of the selected GPU, or None if no GPUs are available. """ if not self['selected_gpus']: return None ind = self._mpi_rank % len(self['selected_gpus']) gpu_ind = self['selected_gpus'][ind] return gpu_ind
[docs] def print_rank_selected_gpu(self): """ Prints the GPU selected for use by the current MPI process. Mimics the output of the `nvidia-smi -L` terminal command. If no GPUs are available, a message indicating this is printed. """ if not self._gpus: print("GPU not available.") gpu_ind = self.rank_select_gpu() gpu = self._gpus[gpu_ind] print(f'GPU {gpu_ind}: {gpu.name.decode()} (UUID: {gpu._device.uuid})')
config = Config()
[docs] class config_context(): """ Context manager for temporarily modifying the configuration settings. This context manager allows for a temporary reassignment of configuration parameters. Changes made within the context manager are reverted back to the original settings once the context is exited. Parameters: ----------- params : dict A dictionary of configuration parameters to update. Example: -------- Temporarily change the list of allowed GPU devices: >>> with config_context({'selected_gpus': [2, 4, 6]}): >>> # Do stuff using these 3 devices >>> my_awesome_function_that_uses_gpu() >>> . >>> . >>> . >>> # After the with block, the original configuration is restored. """ def __init__(self, params): self.backup_dict = {} self.update_dict = {} self.update_dict.update(**params) def __enter__(self): #Backup current configuration self.backup_dict = copy.deepcopy(config._dict) for k, v in self.update_dict.items(): config[k] = v def __exit__(self, exc_type, exc_value, exc_tb): config._dict = copy.deepcopy(self.backup_dict) if exc_type is not None: collective_raise(CustomCollectiveException(exc_type, exc_value))