Spaces:
Running on Zero
Running on Zero
| # Copyright 2025 Bytedance Ltd. and/or its affiliates | |
| # | |
| # Licensed under the Apache License, Version 2.0 (the "License"); | |
| # you may not use this file except in compliance with the License. | |
| # You may obtain a copy of the License at | |
| # | |
| # http://www.apache.org/licenses/LICENSE-2.0 | |
| # | |
| # Unless required by applicable law or agreed to in writing, software | |
| # distributed under the License is distributed on an "AS IS" BASIS, | |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| # See the License for the specific language governing permissions and | |
| # limitations under the License. | |
| # Following codes are inspired from https://github.com/volcengine/verl/blob/main/verl/utils/device.py | |
| from typing import Any | |
| import torch | |
| from . import logging | |
| from .import_utils import is_torch_npu_available | |
| logger = logging.get_logger(__name__) | |
| IS_CUDA_AVAILABLE = torch.cuda.is_available() | |
| IS_NPU_AVAILABLE = is_torch_npu_available() | |
| if IS_NPU_AVAILABLE: | |
| torch.npu.config.allow_internal_format = False | |
| def get_device_type() -> str: | |
| """Get device type based on current machine, currently only support CPU, CUDA, NPU.""" | |
| if IS_CUDA_AVAILABLE: | |
| device = "cuda" | |
| elif IS_NPU_AVAILABLE: | |
| device = "npu" | |
| else: | |
| device = "cpu" | |
| return device | |
| def get_device_name() -> str: | |
| """Get real device name, e.g. A100, H100""" | |
| return get_torch_device().get_device_name() | |
| def get_torch_device() -> Any: | |
| """Get torch attribute based on device type, e.g. torch.cuda or torch.npu""" | |
| device_name = get_device_type() | |
| try: | |
| return getattr(torch, device_name) | |
| except AttributeError: | |
| logger.warning(f"Device namespace '{device_name}' not found in torch, try to load 'torch.cuda'.") | |
| return torch.cuda | |
| def get_device_id() -> int: | |
| """Get current device id based on device type.""" | |
| return get_torch_device().current_device() | |
| def get_dist_comm_backend() -> str: | |
| """Return distributed communication backend type based on device type.""" | |
| if IS_CUDA_AVAILABLE: | |
| return "nccl" | |
| elif IS_NPU_AVAILABLE: | |
| return "hccl" | |
| else: | |
| raise RuntimeError(f"No available distributed communication backend found on device type {get_device_type()}.") | |
| def synchronize() -> None: | |
| """Execute torch synchronize operation.""" | |
| get_torch_device().synchronize() | |
| def stream_synchronize() -> None: | |
| """Execute device stream synchronize operation.""" | |
| if IS_CUDA_AVAILABLE: | |
| torch.cuda.current_stream().synchronize() | |
| elif IS_NPU_AVAILABLE: | |
| torch.npu.current_stream().synchronize() | |
| else: | |
| synchronize() | |
| def empty_cache() -> None: | |
| """Execute torch empty cache operation.""" | |
| get_torch_device().empty_cache() | |
| def set_device(device: torch.types.Device) -> None: | |
| """Execute set device operation.""" | |
| get_torch_device().set_device(device) | |
| def is_nccl_backend() -> bool: | |
| """Check if the distributed communication backend is NCCL.""" | |
| return get_dist_comm_backend() == "nccl" | |
| def is_hccl_backend() -> bool: | |
| """Check if the distributed communication backend is HCCL.""" | |
| return get_dist_comm_backend() == "hccl" | |
| def get_gpu_compute_capability() -> int: | |
| """Return the compute capability as an integer (e.g. 70, 80, 90), or 0 if no GPU.""" | |
| if not IS_CUDA_AVAILABLE: | |
| return 0 | |
| major, minor = torch.cuda.get_device_capability() | |
| return major * 10 + minor | |
| def is_sm90_or_above() -> bool: | |
| """Check if the current CUDA device has SM90+ capability.""" | |
| return get_gpu_compute_capability() >= 90 | |
| def get_compute_units(): | |
| """ | |
| Returns the number of streaming multiprocessors (SMs) or equivalent compute units | |
| for the available accelerator. Assigns the value to NUM_SMS. | |
| """ | |
| NUM_SMS = None | |
| device_type = getattr(torch.accelerator.current_accelerator(), "type", "cpu") | |
| # Use match/case for device-specific logic (Python 3.10+) | |
| match device_type: | |
| case "cuda": | |
| device_properties = torch.cuda.get_device_properties(0) | |
| NUM_SMS = device_properties.multi_processor_count | |
| case "xpu": | |
| device_properties = torch.xpu.get_device_properties(0) | |
| NUM_SMS = device_properties.max_compute_units | |
| case _: | |
| print("No CUDA or XPU device available. Using CPU.") | |
| # For CPU, you might want to use the number of CPU cores | |
| NUM_SMS = torch.get_num_threads() | |
| return NUM_SMS | |