Initial import: grid-bot — grid trading bot for BTC-USDT on Cifra Markets

This commit is contained in:
Kolp
2026-09-24 13:22:23 +07:00
commit 642cc11a9f
18968 changed files with 5683248 additions and 0 deletions
@@ -0,0 +1,307 @@
r"""
This package introduces support for the current :ref:`accelerator<accelerators>` in python.
"""
from functools import cache
from typing import Any
from typing_extensions import deprecated
import torch
from ._utils import _device_t, _get_device_index
from .graphs import Graph
from .memory import (
empty_cache,
empty_host_cache,
get_memory_info,
max_memory_allocated,
max_memory_reserved,
memory_allocated,
memory_reserved,
memory_stats,
reset_accumulated_memory_stats,
reset_peak_memory_stats,
)
__all__ = [
"Graph",
"current_accelerator",
"current_device_idx", # deprecated
"current_device_index",
"get_device_capability",
"current_stream",
"device_count",
"device_index",
"empty_cache",
"empty_host_cache",
"get_memory_info",
"is_available",
"max_memory_allocated",
"max_memory_reserved",
"memory_allocated",
"memory_reserved",
"memory_stats",
"reset_accumulated_memory_stats",
"reset_peak_memory_stats",
"set_device_idx", # deprecated
"set_device_index",
"set_stream",
"synchronize",
]
def device_count() -> int:
r"""Return the number of current :ref:`accelerator<accelerators>` available.
Returns:
int: the number of the current :ref:`accelerator<accelerators>` available.
If there is no available accelerators, return 0.
.. note:: This API delegates to the device-specific version of `device_count`.
On CUDA, this API will NOT poison fork if NVML discovery succeeds.
Otherwise, it will. For more details, see :ref:`multiprocessing-poison-fork-note`.
"""
acc = current_accelerator()
if acc is None:
return 0
mod = torch.get_device_module(acc)
return mod.device_count()
def is_available() -> bool:
r"""Check if the current accelerator is available at runtime: it was build, all the
required drivers are available and at least one device is visible.
See :ref:`accelerator<accelerators>` for details.
Returns:
bool: A boolean indicating if there is an available :ref:`accelerator<accelerators>`.
.. note:: This API delegates to the device-specific version of `is_available`.
On CUDA, when the environment variable ``PYTORCH_NVML_BASED_CUDA_CHECK=1`` is set,
this function will NOT poison fork. Otherwise, it will. For more details, see
:ref:`multiprocessing-poison-fork-note`.
Example::
>>> assert torch.accelerator.is_available() "No available accelerators detected."
"""
# Why not just check "device_count() > 0" like other is_available call?
# Because device like CUDA have a python implementation of is_available that is
# non-poisoning and some features like Dataloader rely on it.
# So we are careful to delegate to the Python version of the accelerator here
acc = current_accelerator()
if acc is None:
return False
mod = torch.get_device_module(acc)
return mod.is_available()
def current_accelerator(check_available: bool = False) -> torch.device | None:
r"""Return the device of the accelerator available at compilation time.
If no accelerator were available at compilation time, returns None.
See :ref:`accelerator<accelerators>` for details.
Args:
check_available (bool, optional): if True, will also do a runtime check to see
if the device :func:`torch.accelerator.is_available` on top of the compile-time
check.
Default: ``False``
Returns:
torch.device: return the current accelerator as :class:`torch.device`.
.. note:: The index of the returned :class:`torch.device` will be ``None``, please use
:func:`torch.accelerator.current_device_index` to know the current index being used.
This API does NOT poison fork. For more details, see :ref:`multiprocessing-poison-fork-note`.
Example::
>>> # xdoctest:
>>> # If an accelerator is available, sent the model to it
>>> model = torch.nn.Linear(2, 2)
>>> if (current_device := current_accelerator(check_available=True)) is not None:
>>> model.to(current_device)
"""
if (acc := torch._C._accelerator_getAccelerator()) is not None:
if (not check_available) or (check_available and is_available()):
return acc
return None
def current_device_index() -> int:
r"""Return the index of a currently selected device for the current :ref:`accelerator<accelerators>`.
Returns:
int: the index of a currently selected device.
"""
return torch._C._accelerator_getDeviceIndex()
current_device_idx = deprecated(
"Use `current_device_index` instead.",
category=FutureWarning,
)(current_device_index)
current_device_idx.__doc__ = r"""
(Deprecated) Return the index of a currently selected device for the current :ref:`accelerator<accelerators>`.
Returns:
int: the index of a currently selected device.
.. warning::
:func:`torch.accelerator.current_device_idx` is deprecated in favor of :func:`torch.accelerator.current_device_index`
and will be removed in a future PyTorch release.
"""
@cache
def get_device_capability(device: _device_t = None, /) -> dict[str, Any]:
r"""Return the capability of the currently selected device.
Args:
device (:class:`torch.device`, str, int, optional): The device to query capabilities for
:ref:`accelerator<accelerators>` device type. If not given,
use :func:`torch.accelerator.current_device_index` by default.
Returns:
dict[str, Any]: A dictionary containing device capability information. The dictionary includes:
- ``supported_dtypes`` (set(torch.dtype)): Set of PyTorch data types for which
tensors can be allocated on the accelerator and type conversion across
supported dtypes are supported. Any operator support outside of that
is not guaranteed
Examples:
>>> # xdoctest: +SKIP("requires cuda")
>>> # Query capabilities for current device
>>> capabilities = torch.accelerator.get_device_capability("cuda:0")
>>> print("Supported dtypes:", capabilities["supported_dtypes"])
"""
device_index = _get_device_index(device, optional=True)
# pyrefly: ignore [missing-attribute]
return torch._C._accelerator_getDeviceCapability(device_index)
def set_device_index(device: _device_t, /) -> None:
r"""Set the current device index to a given device.
Args:
device (:class:`torch.device`, str, int): a given device that must match the current
:ref:`accelerator<accelerators>` device type.
.. note:: This function is a no-op if this device index is negative.
"""
device_index = _get_device_index(device, optional=False)
torch._C._accelerator_setDeviceIndex(device_index)
set_device_idx = deprecated(
"Use `set_device_index` instead.",
category=FutureWarning,
)(set_device_index)
set_device_idx.__doc__ = r"""
(Deprecated) Set the current device index to a given device.
Args:
device (:class:`torch.device`, str, int): a given device that must match the current
:ref:`accelerator<accelerators>` device type.
.. warning::
:func:`torch.accelerator.set_device_idx` is deprecated in favor of :func:`torch.accelerator.set_device_index`
and will be removed in a future PyTorch release.
"""
def current_stream(device: _device_t = None, /) -> torch.Stream:
r"""Return the currently selected stream for a given device.
Args:
device (:class:`torch.device`, str, int, optional): a given device that must match the current
:ref:`accelerator<accelerators>` device type. If not given,
use :func:`torch.accelerator.current_device_index` by default.
Returns:
torch.Stream: the currently selected stream for a given device.
"""
device_index = _get_device_index(device, optional=True)
return torch._C._accelerator_getStream(device_index)
def set_stream(stream: torch.Stream) -> None:
r"""Set the current stream to a given stream.
Args:
stream (torch.Stream): a given stream that must match the current :ref:`accelerator<accelerators>` device type.
.. note:: This function will set the current device index to the device index of the given stream.
"""
torch._C._accelerator_setStream(stream)
def synchronize(device: _device_t = None, /) -> None:
r"""Wait for all kernels in all streams on the given device to complete.
Args:
device (:class:`torch.device`, str, int, optional): device for which to synchronize. It must match
the current :ref:`accelerator<accelerators>` device type. If not given,
use :func:`torch.accelerator.current_device_index` by default.
.. note:: This function is a no-op if the current :ref:`accelerator<accelerators>` is not initialized.
Example::
>>> # xdoctest: +REQUIRES(env:TORCH_DOCTEST_CUDA)
>>> assert torch.accelerator.is_available() "No available accelerators detected."
>>> start_event = torch.Event(enable_timing=True)
>>> end_event = torch.Event(enable_timing=True)
>>> start_event.record()
>>> tensor = torch.randn(100, device=torch.accelerator.current_accelerator())
>>> sum = torch.sum(tensor)
>>> end_event.record()
>>> torch.accelerator.synchronize()
>>> elapsed_time_ms = start_event.elapsed_time(end_event)
"""
device_index = _get_device_index(device, optional=True)
torch._C._accelerator_synchronizeDevice(device_index)
class device_index:
r"""Context manager to set the current device index for the current :ref:`accelerator<accelerators>`.
Temporarily changes the current device index to the specified value for the duration
of the context, and automatically restores the previous device index when exiting
the context.
Args:
device (Optional[int]): a given device index to temporarily set. If None,
no device index switching occurs.
Examples:
>>> # xdoctest: +REQUIRES(env:TORCH_DOCTEST_CUDA)
>>> # Set device 0 as the current device temporarily
>>> with torch.accelerator.device_index(0):
... # Code here runs with device 0 as the current device
... pass
>>> # Original device is now restored
>>> # No-op when None is passed
>>> with torch.accelerator.device_index(None):
... # No device switching occurs
... pass
"""
def __init__(self, device: int | None, /) -> None:
self.idx = device
self.prev_idx = -1
def __enter__(self) -> None:
if self.idx is not None:
self.prev_idx = torch._C._accelerator_exchangeDevice(self.idx)
def __exit__(self, *exc_info: object) -> None:
if self.idx is not None:
torch._C._accelerator_maybeExchangeDevice(self.prev_idx)
@@ -0,0 +1,26 @@
import torch
from torch.types import Device as _device_t
def _get_device_index(device: _device_t, optional: bool = False) -> int:
if isinstance(device, int):
return device
if isinstance(device, str):
device = torch.device(device)
device_index: int | None = None
if isinstance(device, torch.device):
acc = torch.accelerator.current_accelerator()
if acc is None:
raise RuntimeError("Accelerator expected")
if acc.type != device.type:
raise ValueError(
f"{device.type} doesn't match the current accelerator {acc}."
)
device_index = device.index
if device_index is None:
if not optional:
raise ValueError(
f"Expected a torch.device with a specified index or an integer, but got:{device}"
)
return torch.accelerator.current_device_index()
return device_index
@@ -0,0 +1,177 @@
import gc
from typing import Literal
from typing_extensions import Self
import torch
from torch._C import _acceleratorGraph
class Graph(_acceleratorGraph):
r"""
Wrapper around an :ref:`accelerator<accelerators>` graph that supports capture and replay.
A graph captures a sequence of operations and their dependencies, allowing them to be
replayed efficiently with reduced overhead. This class can be used as a context manager
to automatically capture operations on the current stream.
Arguments:
keep_graph (bool, optional): If ``False``, the underlying graph is destroyed and the
executable graph is instantiated on the GPU at the end of ``capture_end``.
If ``True``, the underlying graph is preserved after ``capture_end``. In this case,
the executable graph is not instantiated automatically; it must be explicitly created
by calling ``instantiate``, or it will be instantiated on the first call to ``replay``.
Defaults to ``False``.
pool (tuple[int, int], optional): Memory pool identifier for this graph. Multiple graphs
can share the same pool by passing the same identifier, which can reduce memory overhead.
Defaults to ``None``.
capture_error_mode (Literal["default", "global", "thread_local", "relaxed"], optional):
Specifies the behavior of graph capture. The exact semantics are backend-specific.
``"default"``: backend-defined default capture behavior.
``"global"``: potentially unsafe API calls are prohibited. Errors may occur if capture
in the current thread affects other threads.
``"thread_local"``: potentially unsafe API calls are prohibited. Errors occur only if
capture in the current thread affects itself.
``"relaxed"``: the current thread is allowed to make potentially unsafe API calls, except
for calls that inherently conflict with stream capture.
Default: ``"default"``.
Example::
>>> # xdoctest: +SKIP
>>> x = torch.zeros([2000], device=0)
>>> stream = torch.Stream()
>>> graph = torch.accelerator.Graph()
>>> with stream, graph:
... x += 1
>>> graph.replay()
"""
def __new__(
cls,
keep_graph: bool = False,
*,
pool: tuple[int, int] | None = None,
capture_error_mode: Literal[
"default", "global", "thread_local", "relaxed"
] = "default",
) -> Self:
return super().__new__(cls, keep_graph)
def __init__(
self,
keep_graph: bool = False,
*,
pool: tuple[int, int] | None = None,
capture_error_mode: Literal[
"default", "global", "thread_local", "relaxed"
] = "default",
) -> None:
super().__init__(keep_graph)
self.graph_pool = pool
self.capture_error_mode = capture_error_mode
# pyrefly: ignore [bad-override]
def capture_begin(self) -> None:
r"""
Begin graph capture on the current stream.
All operations on the current stream after this call will be recorded into the graph until
``capture_end`` is called, using the memory pool and capture error mode provided at construction time.
"""
super().capture_begin(
pool=self.graph_pool, capture_error_mode=self.capture_error_mode
)
def capture_end(self) -> None:
r"""
End graph capture on the current stream of the current device.
After this call, the graph can be replayed via ``replay``.
"""
super().capture_end()
def instantiate(self) -> None:
r"""
Instantiate the underlying graph. Will be called by ``capture_end``
if ``keep_graph=False``, or by ``replay`` if ``keep_graph=True`` and
``instantiate`` has not already been explicitly called.
"""
super().instantiate()
def replay(self) -> None:
r"""Replay the work captured by this graph."""
super().replay()
def reset(self) -> None:
r"""
Delete the graph currently held by this instance.
After this call, the graph can be recaptured. Set :attr:`graph_pool` or
:attr:`capture_error_mode` beforehand to use different settings on the next capture.
"""
super().reset()
def pool(self) -> tuple[int, int]:
r"""
Return an opaque token representing the id of this graph's memory pool.
This id can optionally be passed to another graph's ``capture_begin``,
which hints the other graph may share the same memory pool.
Example::
>>> # xdoctest: +SKIP
>>> g1 = torch.accelerator.Graph()
>>> g1.capture_begin()
>>> # ... operations ...
>>> g1.capture_end()
>>> # Share g1's memory pool with a new graph
>>> pool_id = g1.pool()
>>> g2 = torch.accelerator.Graph(pool=pool_id)
"""
return super().pool()
def enable_debug_mode(self) -> None:
r"""Enable debugging mode for ``debug_dump``."""
return super().enable_debug_mode()
def debug_dump(self, path: str) -> None:
r"""
Dump the captured graph to a file for debugging purposes if the debugging is
enabled via ``enable_debug_mode``.
Arguments:
path (str): Path to dump the graph to.
Example::
>>> # xdoctest: +SKIP
>>> s = torch.Stream()
>>> g = torch.accelerator.Graph()
>>> g.enable_debug_mode()
>>> with s, g:
>>> # ... operations ...
>>> # Dump captured graph to a file "graph_dump.dot"
>>> g.debug_dump("graph_dump.dot")
"""
return super().debug_dump(path)
def __enter__(self) -> None:
torch.accelerator.synchronize()
if torch.compiler.config.force_cudagraph_gc:
# We previously always ran garbage collection here. While this can help
# reclaim accelerator device memory held by dead Python cycles, it is
# very expensive, especially when performing multiple graph captures in sequence.
gc.collect()
torch.accelerator.empty_cache()
torch.accelerator.empty_host_cache()
self.capture_begin()
def __exit__(self, *exc_info: object) -> None:
self.capture_end()
__all__ = ["Graph"]
@@ -0,0 +1,248 @@
from collections import OrderedDict
from typing import Any
import torch
from ._utils import _device_t, _get_device_index
__all__ = [
"empty_cache",
"empty_host_cache",
"get_memory_info",
"max_memory_allocated",
"max_memory_reserved",
"memory_allocated",
"memory_reserved",
"memory_stats",
"reset_accumulated_memory_stats",
"reset_peak_memory_stats",
]
def empty_cache() -> None:
r"""Release all unoccupied cached memory currently held by the caching
allocator so that those can be used in other application.
.. note:: This function is a no-op if the memory allocator for the current
:ref:`accelerator <accelerators>` has not been initialized.
"""
if not torch._C._accelerator_isAllocatorInitialized():
return
torch._C._accelerator_emptyCache()
def empty_host_cache() -> None:
r"""Release all unoccupied cached host (pinned) memory currently held by the host caching
allocator so that it can be used by other applications.
.. note:: This function is a no-op if the memory allocator for the current
:ref:`accelerator <accelerators>` has not been initialized.
"""
torch._C._accelerator_emptyHostCache()
def memory_stats(device_index: _device_t = None, /) -> OrderedDict[str, Any]:
r"""Return a dictionary of accelerator device memory allocator statistics for a given device index.
The return value of this function is a dictionary of statistics, each of
which is a non-negative integer.
Core statistics:
- ``"allocated.{all,large_pool,small_pool}.{current,peak,allocated,freed}"``:
number of allocation requests received by the memory allocator.
- ``"allocated_bytes.{all,large_pool,small_pool}.{current,peak,allocated,freed}"``:
amount of allocated memory.
- ``"segment.{all,large_pool,small_pool}.{current,peak,allocated,freed}"``:
number of reserved segments from device memory allocation.
- ``"reserved_bytes.{all,large_pool,small_pool}.{current,peak,allocated,freed}"``:
amount of reserved memory.
- ``"active.{all,large_pool,small_pool}.{current,peak,allocated,freed}"``:
number of active memory blocks.
- ``"active_bytes.{all,large_pool,small_pool}.{current,peak,allocated,freed}"``:
amount of active memory.
- ``"inactive_split.{all,large_pool,small_pool}.{current,peak,allocated,freed}"``:
number of inactive, non-releasable memory blocks.
- ``"inactive_split_bytes.{all,large_pool,small_pool}.{current,peak,allocated,freed}"``:
amount of inactive, non-releasable memory.
For these core statistics, values are broken down as follows.
Pool type:
- ``all``: combined statistics across all memory pools.
- ``large_pool``: statistics for the large allocation pool
(as of June 2025, for size >= 1MB allocations).
- ``small_pool``: statistics for the small allocation pool
(as of June 2025, for size < 1MB allocations).
Metric type:
- ``current``: current value of this metric.
- ``peak``: maximum value of this metric.
- ``allocated``: historical total increase in this metric.
- ``freed``: historical total decrease in this metric.
In addition to the core statistics, we also provide some simple event
counters:
- ``"num_alloc_retries"``: number of failed device memory allocation calls that
result in a cache flush and retry.
- ``"num_ooms"``: number of out-of-memory errors thrown.
- ``"num_sync_all_streams"``: number of ``synchronize_and_free_events`` calls.
- ``"num_device_alloc"``: number of device memory allocation calls.
- ``"num_device_free"``: number of device memory free calls.
Args:
device_index (:class:`torch.device`, str, int, optional): the index of the device to target.
If not given, use :func:`torch.accelerator.current_device_index` by default.
If a :class:`torch.device` or str is provided, its type must match the current
:ref:`accelerator<accelerators>` device type.
Returns:
OrderedDict[str, Any]: an ordered dictionary mapping statistic names to their values.
"""
if not torch._C._accelerator_isAllocatorInitialized():
return OrderedDict()
device_index = _get_device_index(device_index, optional=True)
stats = torch._C._accelerator_getDeviceStats(device_index)
flat_stats = []
def flatten(prefix: str, value: Any) -> None:
if isinstance(value, dict):
for k, v in value.items():
nested_prefix = f"{prefix}.{k}" if prefix else k
flatten(nested_prefix, v)
else:
flat_stats.append((prefix, value))
flatten("", stats)
flat_stats.sort()
# pyrefly: ignore [no-matching-overload]
return OrderedDict(flat_stats)
def memory_allocated(device_index: _device_t = None, /) -> int:
r"""Return the current :ref:`accelerator<accelerators>` device memory occupied by tensors
in bytes for a given device index.
Args:
device_index (:class:`torch.device`, str, int, optional): the index of the device to target.
If not given, use :func:`torch.accelerator.current_device_index` by default.
If a :class:`torch.device` or str is provided, its type must match the current
:ref:`accelerator<accelerators>` device type.
Returns:
int: the current memory occupied by live tensors (in bytes) within the current process.
"""
return memory_stats(device_index).get("allocated_bytes.all.current", 0)
def max_memory_allocated(device_index: _device_t = None, /) -> int:
r"""Return the current :ref:`accelerator<accelerators>` maximum device memory occupied by tensors
in bytes for a given device index.
By default, this returns the peak allocated memory since the beginning of
this program. :func:`~torch.accelerator.reset_peak_memory_stats` can be used to
reset the starting point in tracking this metric.
Args:
device_index (:class:`torch.device`, str, int, optional): the index of the device to target.
If not given, use :func:`torch.accelerator.current_device_index` by default.
If a :class:`torch.device` or str is provided, its type must match the current
:ref:`accelerator<accelerators>` device type.
Returns:
int: the peak memory occupied by live tensors (in bytes) within the current process.
"""
return memory_stats(device_index).get("allocated_bytes.all.peak", 0)
def memory_reserved(device_index: _device_t = None, /) -> int:
r"""Return the current :ref:`accelerator<accelerators>` device memory managed by the caching allocator
in bytes for a given device index.
Args:
device_index (:class:`torch.device`, str, int, optional): the index of the device to target.
If not given, use :func:`torch.accelerator.current_device_index` by default.
If a :class:`torch.device` or str is provided, its type must match the current
:ref:`accelerator<accelerators>` device type.
Returns:
int: the current memory reserved by PyTorch (in bytes) within the current process.
"""
return memory_stats(device_index).get("reserved_bytes.all.current", 0)
def max_memory_reserved(device_index: _device_t = None, /) -> int:
r"""Return the current :ref:`accelerator<accelerators>` maximum device memory managed by the caching allocator
in bytes for a given device index.
By default, this returns the peak cached memory since the beginning of this
program. :func:`~torch.accelerator.reset_peak_memory_stats` can be used to reset
the starting point in tracking this metric.
Args:
device_index (:class:`torch.device`, str, int, optional): the index of the device to target.
If not given, use :func:`torch.accelerator.current_device_index` by default.
If a :class:`torch.device` or str is provided, its type must match the current
:ref:`accelerator<accelerators>` device type.
Returns:
int: the peak memory reserved by PyTorch (in bytes) within the current process.
"""
return memory_stats(device_index).get("reserved_bytes.all.peak", 0)
def reset_accumulated_memory_stats(device_index: _device_t = None, /) -> None:
r"""Reset the "accumulated" (historical) stats tracked by the current :ref:`accelerator<accelerators>`
memory allocator for a given device index.
Args:
device_index (:class:`torch.device`, str, int, optional): the index of the device to target.
If not given, use :func:`torch.accelerator.current_device_index` by default.
If a :class:`torch.device` or str is provided, its type must match the current
:ref:`accelerator<accelerators>` device type.
.. note:: This function is a no-op if the memory allocator for the current
:ref:`accelerator <accelerators>` has not been initialized.
"""
device_index = _get_device_index(device_index, optional=True)
return torch._C._accelerator_resetAccumulatedStats(device_index)
def reset_peak_memory_stats(device_index: _device_t = None, /) -> None:
r"""Reset the "peak" stats tracked by the current :ref:`accelerator<accelerators>`
memory allocator for a given device index.
Args:
device_index (:class:`torch.device`, str, int, optional): the index of the device to target.
If not given, use :func:`torch.accelerator.current_device_index` by default.
If a :class:`torch.device` or str is provided, its type must match the current
:ref:`accelerator<accelerators>` device type.
.. note:: This function is a no-op if the memory allocator for the current
:ref:`accelerator <accelerators>` has not been initialized.
"""
device_index = _get_device_index(device_index, optional=True)
return torch._C._accelerator_resetPeakStats(device_index)
def get_memory_info(device_index: _device_t = None, /) -> tuple[int, int]:
r"""Return the current device memory information for a given device index.
Args:
device_index (:class:`torch.device`, str, int, optional): the index of the device to target.
If not given, use :func:`torch.accelerator.current_device_index` by default.
If a :class:`torch.device` or str is provided, its type must match the current
:ref:`accelerator<accelerators>` device type.
Returns:
tuple[int, int]: a tuple of two integers (free_memory, total_memory) in bytes.
The first value is the free memory on the device (available across all processes and applications),
The second value is the device's total hardware memory capacity.
"""
device_index = _get_device_index(device_index, optional=True)
# pyrefly: ignore [missing-attribute]
return torch._C._accelerator_getMemoryInfo(device_index)