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,23 @@
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
#pragma once
#include <c10/core/Device.h>
#include <c10/macros/Macros.h>
#include <c10/xpu/XPUMacros.h>
namespace c10::xpu {
namespace detail {
// Initialize the peer-to-peer access cache for XPU devices.
C10_XPU_API void init_p2p_access_cache(c10::DeviceIndex num_devices);
} // namespace detail
// Query if peer-to-peer access is available between two devices.
C10_XPU_API bool get_p2p_access(
c10::DeviceIndex dev,
c10::DeviceIndex dev_to_access);
} // namespace c10::xpu
#else
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
@@ -0,0 +1,142 @@
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
#pragma once
#include <c10/core/AllocatorConfig.h>
#include <c10/core/CachingDeviceAllocator.h>
#include <c10/xpu/XPUStream.h>
namespace c10::xpu::XPUCachingAllocator {
class XPUAllocator : public DeviceAllocator {
public:
virtual void init(c10::DeviceIndex device_count) = 0;
virtual void* raw_alloc(size_t size) = 0;
virtual void raw_delete(void* ptr) = 0;
};
C10_XPU_API extern std::atomic<XPUAllocator*> allocator;
struct AllocatorConfigInfo {
bool expandable_segments;
std::string last_allocator_settings;
};
struct SnapshotInfo {
std::vector<CachingDeviceAllocator::SegmentInfo> segments;
std::vector<std::vector<CachingDeviceAllocator::TraceEntry>> device_traces;
AllocatorConfigInfo config_metadata;
};
inline XPUAllocator* get() {
return allocator.load();
}
inline void init(c10::DeviceIndex device_count) {
get()->init(device_count);
}
inline void emptyCache(MempoolId_t mempool_id = {0, 0}) {
get()->emptyCache(mempool_id);
}
inline void resetPeakStats(DeviceIndex device) {
get()->resetPeakStats(device);
}
inline void resetAccumulatedStats(DeviceIndex device) {
get()->resetAccumulatedStats(device);
}
inline c10::CachingDeviceAllocator::DeviceStats getDeviceStats(
DeviceIndex device) {
return get()->getDeviceStats(device);
}
inline void* raw_alloc(size_t size) {
return get()->raw_alloc(size);
}
inline void raw_delete(void* ptr) {
get()->raw_delete(ptr);
}
inline void recordStream(const DataPtr& dataPtr, XPUStream stream) {
get()->recordStream(dataPtr, stream);
}
C10_XPU_API void enablePeerAccess(
c10::DeviceIndex dev,
c10::DeviceIndex dev_to_access);
C10_XPU_API double getMemoryFraction(DeviceIndex device);
C10_XPU_API void setMemoryFraction(double fraction, DeviceIndex device);
C10_XPU_API void recordHistory(
bool enabled,
CachingDeviceAllocator::CreateContextFn context_recorder,
size_t alloc_trace_max_entries,
CachingDeviceAllocator::RecordContext when,
bool clearHistory,
const std::vector<std::string>& skip_actions);
C10_XPU_API SnapshotInfo snapshot(MempoolId_t mempool_id = {0, 0});
C10_XPU_API void createOrIncrefPool(
c10::DeviceIndex device,
c10::MempoolId_t mempool_id,
XPUAllocator* allocator = nullptr);
C10_XPU_API void beginAllocateToPool(
c10::DeviceIndex device,
c10::MempoolId_t mempool_id,
std::function<bool(sycl::queue*)> filter);
C10_XPU_API void endAllocateToPool(
c10::DeviceIndex device,
c10::MempoolId_t mempool_id);
C10_XPU_API void releasePool(
c10::DeviceIndex device,
c10::MempoolId_t mempool_id);
C10_XPU_API int getPoolUseCount(
c10::DeviceIndex device,
c10::MempoolId_t mempool_id);
} // namespace c10::xpu::XPUCachingAllocator
namespace c10::xpu {
using c10::CaptureId_t;
using c10::MempoolId_t;
struct C10_XPU_API MemPool {
MemPool(
XPUCachingAllocator::XPUAllocator* allocator = nullptr,
bool is_user_created = true,
bool use_on_oom = false);
MemPool(const MemPool&) = delete;
MemPool(MemPool&&) = default;
MemPool& operator=(const MemPool&) = delete;
MemPool& operator=(MemPool&&) = default;
~MemPool();
MempoolId_t id();
XPUCachingAllocator::XPUAllocator* allocator();
int use_count();
c10::DeviceIndex device();
static MempoolId_t graph_pool_handle(bool is_user_created = true);
private:
static std::atomic<CaptureId_t> uid_;
static std::atomic<CaptureId_t> uuid_;
XPUCachingAllocator::XPUAllocator* allocator_;
bool is_user_created_;
MempoolId_t id_;
c10::DeviceIndex device_;
};
} // namespace c10::xpu
#else
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
@@ -0,0 +1,222 @@
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
#pragma once
#include <c10/xpu/XPUMacros.h>
#include <sycl/sycl.hpp>
namespace c10::xpu {
#define AT_FORALL_XPU_DEVICE_PROPERTIES(_) \
/* the device name of this SYCL device. */ \
_(name) \
\
/* the device type associated with the device. */ \
_(device_type) \
\
/* the vendor of this SYCL device. */ \
_(vendor) \
\
/* a backend-defined driver version as a std::string. */ \
_(driver_version) \
\
/* the SYCL version as a std::string in the form <major>.<minor> */ \
_(version) \
\
/* true if the SYCL device is available. Otherwise, return false. */ \
_(is_available) \
\
/* the maximum size in bytes of the arguments that can be passed to a \
* kernel. */ \
_(max_parameter_size) \
\
/* the number of parallel compute units available to the device. */ \
_(max_compute_units) \
\
/* the maximum dimensions that specify the global and local work-item IDs \
* used by the data parallel execution model. */ \
_(max_work_item_dimensions) \
\
/* the maximum number of workitems that are permitted in a work-group \
* executing a kernel on a single compute unit. */ \
_(max_work_group_size) \
\
/* the maximum number of subgroups in a work-group for any kernel executed \
* on the device. */ \
_(max_num_sub_groups) \
\
/* a std::vector of size_t containing the set of sub-group sizes supported \
* by the device. */ \
_(sub_group_sizes) \
\
/* the maximum configured clock frequency of this SYCL device in MHz. */ \
_(max_clock_frequency) \
\
/* the default compute device address space size specified as an unsigned \
* integer value in bits. Must return either 32 or 64. */ \
_(address_bits) \
\
/* the maximum size of memory object allocation in bytes. */ \
_(max_mem_alloc_size) \
\
/* the minimum value in bits of the largest supported SYCL built-in data \
* type if this SYCL device is not of device type \
* sycl::info::device_type::custom. */ \
_(mem_base_addr_align) \
\
/* a std::vector of info::fp_config describing the half/single/double \
* precision floating-point capability of this SYCL device. */ \
_(half_fp_config) \
_(single_fp_config) \
_(double_fp_config) \
\
/* the size of global device memory in bytes. */ \
_(global_mem_size) \
\
/* the type of global memory cache supported. */ \
_(global_mem_cache_type) \
\
/* the size of global memory cache in bytes. */ \
_(global_mem_cache_size) \
\
/* the size of global memory cache line in bytes. */ \
_(global_mem_cache_line_size) \
\
/* the type of local memory supported. */ \
_(local_mem_type) \
\
/* the size of local memory arena in bytes. */ \
_(local_mem_size) \
\
/* the maximum number of sub-devices that can be created when this device is \
* partitioned. */ \
_(partition_max_sub_devices) \
\
/* the resolution of device timer in nanoseconds. */ \
_(profiling_timer_resolution) \
\
/* the preferred native vector width size for built-in scalar types that can \
* be put into vectors. */ \
_(preferred_vector_width_char) \
_(preferred_vector_width_short) \
_(preferred_vector_width_int) \
_(preferred_vector_width_long) \
_(preferred_vector_width_float) \
_(preferred_vector_width_double) \
_(preferred_vector_width_half) \
\
/* the native ISA vector width. The vector width is defined as the number of \
* scalar elements that can be stored in the vector. */ \
_(native_vector_width_char) \
_(native_vector_width_short) \
_(native_vector_width_int) \
_(native_vector_width_long) \
_(native_vector_width_float) \
_(native_vector_width_double) \
_(native_vector_width_half)
#define AT_FORALL_XPU_EXT_DEVICE_PROPERTIES(_) \
/* the number of EUs associated with the Intel GPU. */ \
_(gpu_eu_count, gpu_eu_count, 512) \
\
/* the number of EUs in a subslice. */ \
_(gpu_eu_count_per_subslice, gpu_eu_count_per_subslice, 8) \
\
/* the simd width of EU of GPU. */ \
_(gpu_eu_simd_width, gpu_eu_simd_width, 8) \
\
/* the number of hardware threads per EU of GPU. */ \
_(gpu_hw_threads_per_eu, gpu_hw_threads_per_eu, 8) \
\
/* the device identifier of the Intel GPU, also known as the product ID. */ \
_(device_id, device_id, 0) \
\
/* the device descriptor for device Universal Unique ID, 16 bytes. */ \
_(uuid, device_info_uuid, (std::array<unsigned char, 16>{})) \
\
/* the maximum clock rate of device's global memory in MHz. */ \
_(memory_clock_rate, memory_clock_rate, 0) \
\
/* the maximum bus width between device and memory in bits. */ \
_(memory_bus_width, memory_bus_width, 0)
#define AT_FORALL_XPU_DEVICE_ASPECT(_) \
/* sycl::half is supported on device. */ \
_(fp16) \
\
/* double is supported on device. */ \
_(fp64) \
\
/* 64-bit atomic operation is supported on device. */ \
_(atomic64)
#define AT_FORALL_XPU_EXP_CL_ASPECT(_) \
/* conversion between single-precision 32-bit floating-point values and \
* 16-bit bfloat16 values is supported on device. */ \
_(bfloat16_conversions) \
\
/* specialized hardware to compute MMA is supported on device. */ \
_(subgroup_matrix_multiply_accumulate) \
\
/* specialized hardware to compute MMA for 32-bit floating-point is \
* supported on device. */ \
_(subgroup_matrix_multiply_accumulate_tensor_float32) \
\
/* block read operations for efficient matrix multiplication is supported on \
* device. */ \
_(subgroup_2d_block_io)
#define AT_FORALL_XPU_EXP_DEVICE_PROPERTIES(_) \
/* the device architecture of this SYCL device. */ \
_(architecture)
#define _DEFINE_SYCL_PROP(ns, property, member) \
ns::property::return_type member;
#define DEFINE_DEVICE_PROP(property) \
_DEFINE_SYCL_PROP(sycl::info::device, property, property)
#define DEFINE_PLATFORM_PROP(property, member) \
_DEFINE_SYCL_PROP(sycl::info::platform, property, member)
#define DEFINE_EXT_DEVICE_PROP(property, ...) \
_DEFINE_SYCL_PROP(sycl::ext::intel::info::device, property, property)
#define DEFINE_DEVICE_ASPECT(member) bool has_##member;
#define DEFINE_EXP_DEVICE_PROP(property) \
_DEFINE_SYCL_PROP( \
sycl::ext::oneapi::experimental::info::device, property, property)
struct C10_XPU_API DeviceProp{
AT_FORALL_XPU_DEVICE_PROPERTIES(DEFINE_DEVICE_PROP)
// the platform name.
DEFINE_PLATFORM_PROP(name, platform_name)
// ext properties.
AT_FORALL_XPU_EXT_DEVICE_PROPERTIES(DEFINE_EXT_DEVICE_PROP)
// device aspects.
AT_FORALL_XPU_DEVICE_ASPECT(DEFINE_DEVICE_ASPECT)
// experimental device aspects.
AT_FORALL_XPU_EXP_CL_ASPECT(DEFINE_DEVICE_ASPECT)
#if SYCL_COMPILER_VERSION >= 20250000
// experimental device properties.
AT_FORALL_XPU_EXP_DEVICE_PROPERTIES(DEFINE_EXP_DEVICE_PROP)
#endif
};
#undef _DEFINE_SYCL_PROP
#undef DEFINE_DEVICE_PROP
#undef DEFINE_PLATFORM_PROP
#undef DEFINE_EXT_DEVICE_PROP
#undef DEFINE_DEVICE_ASPECT
#undef DEFINE_EXP_DEVICE_PROP
} // namespace c10::xpu
#else
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
@@ -0,0 +1,183 @@
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
#pragma once
#include <c10/xpu/XPUStream.h>
namespace c10::xpu {
/*
* XPUEvent are movable not copyable wrappers around SYCL event. XPUEvent are
* constructed lazily when first recorded. It has a device, and this device is
* acquired from the first recording stream. Later streams that record the event
* must match the same device.
*
* Currently, XPUEvent does NOT support to export an inter-process event from
* another process via inter-process communication(IPC). So it means that
* inter-process communication for event handles between different processes is
* not available. This could impact some applications that rely on cross-process
* synchronization and communication.
*/
struct XPUEvent {
// Constructors
XPUEvent(bool enable_timing = false) noexcept
: enable_timing_{enable_timing} {}
~XPUEvent() {
if (isCreated()) {
const c10::impl::PyInterpreter* interp = c10::impl::GPUTrace::get_trace();
if (C10_UNLIKELY(interp)) {
(*interp)->trace_gpu_event_deletion(
c10::kXPU, reinterpret_cast<uintptr_t>(event_.get()));
}
}
}
C10_DISABLE_COPY_AND_ASSIGN(XPUEvent);
XPUEvent(XPUEvent&& other) = default;
XPUEvent& operator=(XPUEvent&& other) = default;
operator sycl::event&() const {
return event();
}
std::optional<c10::Device> device() const {
if (isCreated()) {
return c10::Device(c10::kXPU, device_index_);
} else {
return std::nullopt;
}
}
inline bool isCreated() const {
return (event_.get() != nullptr);
}
DeviceIndex device_index() const {
return device_index_;
}
sycl::event& event() const {
return *event_;
}
bool query() const {
using namespace sycl::info;
if (!isCreated()) {
return true;
}
return event().get_info<event::command_execution_status>() ==
event_command_status::complete;
}
void record() {
record(getCurrentXPUStream());
}
void recordOnce(const XPUStream& stream) {
if (!isCreated()) {
record(stream);
}
}
void record(const XPUStream& stream) {
if (!isCreated()) {
device_index_ = stream.device_index();
assignEvent(stream.queue());
const c10::impl::PyInterpreter* interp = c10::impl::GPUTrace::get_trace();
if (C10_UNLIKELY(interp)) {
(*interp)->trace_gpu_event_creation(
c10::kXPU, reinterpret_cast<uintptr_t>(event_.get()));
}
} else {
TORCH_CHECK(
device_index_ == stream.device_index(),
"Event device ",
device_index_,
" does not match recording stream's device ",
stream.device_index(),
".");
reassignEvent(stream.queue());
}
const c10::impl::PyInterpreter* interp = c10::impl::GPUTrace::get_trace();
if (C10_UNLIKELY(interp)) {
(*interp)->trace_gpu_event_record(
c10::kXPU,
reinterpret_cast<uintptr_t>(event_.get()),
reinterpret_cast<uintptr_t>(&stream.queue()));
}
}
void block(const XPUStream& stream) {
if (isCreated()) {
std::vector<sycl::event> event_list{event()};
// Make this stream wait until event_ is completed.
stream.queue().ext_oneapi_submit_barrier(event_list);
const c10::impl::PyInterpreter* interp = c10::impl::GPUTrace::get_trace();
if (C10_UNLIKELY(interp)) {
(*interp)->trace_gpu_event_wait(
c10::kXPU,
reinterpret_cast<uintptr_t>(event_.get()),
reinterpret_cast<uintptr_t>(&stream.queue()));
}
}
}
double elapsed_time(const XPUEvent& other) const {
TORCH_CHECK(
isCreated() && other.isCreated(),
"Both events must be recorded before calculating elapsed time.");
TORCH_CHECK(
query() && other.query(),
"Both events must be completed before calculating elapsed time.");
TORCH_CHECK(
enable_timing_ && other.enable_timing_,
"Both events must be created with argument 'enable_timing=True'.");
using namespace sycl::info::event_profiling;
// Block until both of the recorded events are completed.
uint64_t end_time_ns = other.event().get_profiling_info<command_end>();
uint64_t start_time_ns = event().get_profiling_info<command_end>();
// Return the eplased time in milliseconds.
return 1e-6 *
(static_cast<double>(end_time_ns) - static_cast<double>(start_time_ns));
}
void synchronize() const {
if (isCreated()) {
const c10::impl::PyInterpreter* interp = c10::impl::GPUTrace::get_trace();
if (C10_UNLIKELY(interp)) {
(*interp)->trace_gpu_event_synchronization(
c10::kXPU, reinterpret_cast<uintptr_t>(event_.get()));
}
event().wait_and_throw();
}
}
private:
void assignEvent(sycl::queue& queue) {
if (enable_timing_) {
event_ = std::make_unique<sycl::event>(
sycl::ext::oneapi::experimental::submit_profiling_tag(queue));
} else {
event_ = std::make_unique<sycl::event>(queue.ext_oneapi_submit_barrier());
}
}
void reassignEvent(sycl::queue& queue) {
event_.reset();
assignEvent(queue);
}
bool enable_timing_ = false;
c10::DeviceIndex device_index_ = -1;
// Only need to track the last event, as events in an in-order queue are
// executed sequentially.
std::unique_ptr<sycl::event> event_;
};
} // namespace c10::xpu
#else
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
@@ -0,0 +1,28 @@
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
#pragma once
#include <c10/util/Exception.h>
#include <sycl/sycl.hpp>
namespace c10::xpu {
static inline sycl::async_handler asyncHandler =
[](const sycl::exception_list& el) {
if (el.size() == 0) {
return;
}
for (const auto& e : el) {
try {
std::rethrow_exception(e);
} catch (sycl::exception& e) {
TORCH_WARN("SYCL Exception: ", e.what());
}
}
throw;
};
} // namespace c10::xpu
#else
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
@@ -0,0 +1,50 @@
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
#pragma once
#include <c10/core/Device.h>
#include <c10/xpu/XPUDeviceProp.h>
#include <c10/xpu/XPUMacros.h>
// The naming convention used here matches the naming convention of torch.xpu
namespace c10::xpu {
// Log a warning only once if no devices are detected.
C10_XPU_API DeviceIndex device_count();
// Throws an error if no devices are detected.
C10_XPU_API DeviceIndex device_count_ensure_non_zero();
C10_XPU_API DeviceIndex current_device();
C10_XPU_API void set_device(DeviceIndex device);
C10_XPU_API DeviceIndex exchange_device(DeviceIndex device);
C10_XPU_API DeviceIndex maybe_exchange_device(DeviceIndex to_device);
C10_XPU_API sycl::device& get_raw_device(DeviceIndex device);
C10_XPU_API sycl::context& get_device_context();
C10_XPU_API void get_device_properties(
DeviceProp* device_prop,
DeviceIndex device);
C10_XPU_API DeviceIndex get_device_idx_from_pointer(void* ptr);
static inline void check_device_index(DeviceIndex device_index) {
TORCH_CHECK(
device_index >= 0 && device_index < c10::xpu::device_count(),
"The device index is out of range. It must be in [0, ",
static_cast<int>(c10::xpu::device_count()),
"), but got ",
static_cast<int>(device_index),
".");
}
} // namespace c10::xpu
#else
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
@@ -0,0 +1,47 @@
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
#pragma once
#include <c10/xpu/XPUStream.h>
#include <iostream>
// XPU Graphs utils used by c10 and aten.
using namespace sycl::ext::oneapi::experimental;
namespace c10::xpu {
static_assert(
int8_t(queue_state::executing) == 0,
"unexpected int(queue_state::executing) value");
static_assert(
int8_t(queue_state::recording) == 1,
"unexpected int(queue_state::recording) value");
enum class CaptureStatus : int8_t {
Executing = int8_t(queue_state::executing),
Recording = int8_t(queue_state::recording)
};
inline std::ostream& operator<<(std::ostream& os, CaptureStatus status) {
switch (status) {
case CaptureStatus::Executing:
os << "Executing";
break;
case CaptureStatus::Recording:
os << "Recording";
break;
default:
TORCH_INTERNAL_ASSERT(
false, "Unknown XPU graph CaptureStatus", int(status));
}
return os;
}
inline CaptureStatus currentStreamCaptureStatusMayInitCtx() {
auto state = c10::xpu::getCurrentXPUStream().queue().ext_oneapi_get_state();
return CaptureStatus(state);
}
} // namespace c10::xpu
#else
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
@@ -0,0 +1,38 @@
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
#pragma once
#ifndef C10_USING_CUSTOM_GENERATED_MACROS
#include <c10/xpu/impl/xpu_cmake_macros.h>
#endif
// See c10/macros/Export.h for a detailed explanation of what the function
// of these macros are. We need one set of macros for every separate library
// we build.
#ifdef _WIN32
#if defined(C10_XPU_BUILD_SHARED_LIBS)
#define C10_XPU_EXPORT __declspec(dllexport)
#define C10_XPU_IMPORT __declspec(dllimport)
#else
#define C10_XPU_EXPORT
#define C10_XPU_IMPORT
#endif
#else // _WIN32
#if defined(__GNUC__)
#define C10_XPU_EXPORT __attribute__((__visibility__("default")))
#else // defined(__GNUC__)
#define C10_XPU_EXPORT
#endif // defined(__GNUC__)
#define C10_XPU_IMPORT C10_XPU_EXPORT
#endif // _WIN32
// This one is being used by libc10_xpu.so
#ifdef C10_XPU_BUILD_MAIN_LIB
#define C10_XPU_API C10_XPU_EXPORT
#else
#define C10_XPU_API C10_XPU_IMPORT
#endif
#else
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
@@ -0,0 +1,222 @@
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
#pragma once
#include <c10/core/Stream.h>
#include <c10/core/impl/GPUTrace.h>
#include <c10/xpu/XPUFunctions.h>
namespace c10::xpu {
/*
* Note [Stream Management]
*
* An XPUStream is an abstraction of an actual SYCL queue in which SYCL kernel
* can execute. Currently, there are several pools per device to manage SYCL
* queue, and a device's pool is lazily created.
*
* There are two pools per device. The first pool contains "normal priority"
* queues. The second pool is the "high priority" queues. There are 32 queues in
* per pool per device, and when a queue is requested one of these queues is
* returned round-robin. That is, the first queue requested is at index 0, the
* second at index 1... to index 31, then index 0 again.
*
* This means that if 33 queues are requested, the first and last queues
* requested are actually the same queue (under the covers) and kernels enqueued
* on them cannot run concurrently.
*
* It is safe to enqueue a kernel on the same queue from two different
* threads as the SYCL specification described.
*/
static constexpr int max_compile_time_stream_priorities = 3;
/*
* This serves as a wrapper around c10::Stream and acts as a representation for
* a SYCL queue, which allows asynchronous execution of XPU tasks.
*/
class C10_XPU_API XPUStream {
public:
enum Unchecked { UNCHECKED };
/// Construct a XPUStream from a Stream. This construction is checked, and
/// will raise an error if the Stream is not, in fact, a XPU stream.
explicit XPUStream(Stream stream) : stream_(stream) {
TORCH_CHECK(stream_.device_type() == DeviceType::XPU);
}
/// Construct a XPUStream from a Stream with no error checking.
explicit XPUStream(Unchecked /*unused*/, Stream stream) : stream_(stream) {}
bool operator==(const XPUStream& other) const noexcept {
return unwrap() == other.unwrap();
}
bool operator!=(const XPUStream& other) const noexcept {
return unwrap() != other.unwrap();
}
/// Implicit conversion to sycl::queue&.
operator sycl::queue&() const {
return queue();
}
/// Implicit conversion to sycl::queue*.
operator sycl::queue*() const {
return &queue();
}
/// Implicit conversion to Stream (a.k.a., forget that the stream is a
/// XPU stream).
operator Stream() const {
return unwrap();
}
/// Get the XPU device type that this stream is associated with.
DeviceType device_type() const {
return DeviceType::XPU;
}
/// Get the XPU device index that this stream is associated with.
DeviceIndex device_index() const {
return stream_.device_index();
}
/// Get the full Device that this stream is associated with. The Device is
/// guaranteed to be a XPU device.
Device device() const {
return Device(DeviceType::XPU, device_index());
}
/// Return the stream ID corresponding to this particular stream. StreamId is
/// a int64_t representation generated by its type and index.
StreamId id() const {
return stream_.id();
}
/// Return true if all enqueued tasks in this stream have been completed,
/// otherwise return false.
bool query() const {
return queue().ext_oneapi_empty();
}
/// Performs a blocking wait for the completion of all enqueued tasks in this
/// stream.
void synchronize() const {
queue().wait_and_throw();
const c10::impl::PyInterpreter* interp = c10::impl::GPUTrace::get_trace();
if (C10_UNLIKELY(interp)) {
(*interp)->trace_gpu_stream_synchronization(
c10::kXPU, reinterpret_cast<uintptr_t>(&queue()));
}
}
bool is_capturing() const {
return queue().ext_oneapi_get_state() ==
sycl::ext::oneapi::experimental::queue_state::recording;
}
/// Return the priority that this stream is associated with. Lower numbers
/// represent higher priority.
int priority() const;
/// Explicit conversion to sycl::queue&.
sycl::queue& queue() const;
/// Explicit conversion to Stream.
Stream unwrap() const {
return stream_;
}
/// Reversibly pack a XPUStream into a struct representation. The XPUStream
/// can be unpacked using unpack3().
struct c10::StreamData3 pack3() const {
return stream_.pack3();
}
/// Unpack a XPUStream from the 3 fields generated by pack3().
static XPUStream unpack3(
StreamId stream_id,
DeviceIndex device_index,
DeviceType device_type) {
return XPUStream(Stream::unpack3(stream_id, device_index, device_type));
}
/// Return the range of priority **supported by PyTorch**.
static std::tuple<int, int> priority_range() {
// See Note [XPU Stream priorities]
return std::make_tuple(1, -max_compile_time_stream_priorities + 2);
}
private:
Stream stream_;
};
/**
* Get a stream from the pool in a round-robin fashion.
*
* You can request a stream from the highest priority pool by setting
* isHighPriority to true for a specific device.
*/
C10_XPU_API XPUStream
getStreamFromPool(const bool isHighPriority = false, DeviceIndex device = -1);
/**
* Get a stream from the pool in a round-robin fashion.
*
* You can request a stream by setting a priority value for a specific device.
* The priority number lower, the priority higher.
*/
C10_XPU_API XPUStream
getStreamFromPool(const int priority, DeviceIndex device = -1);
/**
* Get an XPUStream from an external SYCL queue.
*
* This function allows interoperability with other libraries by enabling
* the use of an external SYCL queue that was not created by PyTorch. This
* can be useful for data exchange or other operations where integration
* with non-PyTorch queues is required.
*
* NOTE: It is the user's responsibility to ensure that the referenced SYCL
* queue remains alive while the corresponding XPUStream, or any c10::Stream
* derived from it, is in use. The different SYCL queue pointers will result in
* distinct XPUStream instances, even if the SYCL queues they dereference are
* equivalent.
*/
C10_XPU_API XPUStream
getStreamFromExternal(sycl::queue* ext_queue, DeviceIndex device_index);
/**
* Get the current XPU stream, for the passed XPU device, or for the current
* device if no device index is passed.
*/
C10_XPU_API XPUStream getCurrentXPUStream(DeviceIndex device = -1);
/**
* Set the current stream on the device of the passed in stream to be the passed
* in stream.
*/
C10_XPU_API void setCurrentXPUStream(XPUStream stream);
C10_XPU_API std::ostream& operator<<(std::ostream& stream, const XPUStream& s);
/**
* Block all reserved SYCL queues in the stream pools on the device, and wait
* for their synchronizations.
*/
C10_XPU_API void syncStreamsOnDevice(DeviceIndex device = -1);
} // namespace c10::xpu
namespace std {
template <>
struct hash<c10::xpu::XPUStream> {
size_t operator()(c10::xpu::XPUStream s) const noexcept {
return std::hash<c10::Stream>{}(s.unwrap());
}
};
} // namespace std
#else
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
@@ -0,0 +1,258 @@
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
#pragma once
#include <c10/core/DeviceGuard.h>
#include <c10/core/impl/DeviceGuardImplInterface.h>
#include <c10/core/impl/GPUTrace.h>
#include <c10/xpu/XPUCachingAllocator.h>
#include <c10/xpu/XPUFunctions.h>
#include <c10/xpu/XPUStream.h>
#include <vector>
namespace c10::xpu::impl {
struct XPUGuardImpl final : public c10::impl::DeviceGuardImplInterface {
static constexpr DeviceType static_type = kXPU;
XPUGuardImpl() = default;
explicit XPUGuardImpl(DeviceType t) {
TORCH_CHECK(
t == kXPU, "XPUGuardImpl initialized with non-XPU DeviceType: ", t);
}
DeviceType type() const override {
return kXPU;
}
Device exchangeDevice(Device d) const override {
TORCH_CHECK(d.is_xpu(), "Expected a XPU device, but got ", d);
const auto old_device_index = c10::xpu::exchange_device(d.index());
return Device(kXPU, old_device_index);
}
Device getDevice() const override {
const auto device = c10::xpu::current_device();
return Device(kXPU, device);
}
void setDevice(Device d) const override {
TORCH_CHECK(d.is_xpu(), "Expected a XPU device, but got ", d);
c10::xpu::set_device(d.index());
}
void uncheckedSetDevice(Device d) const noexcept override {
c10::xpu::set_device(d.index());
}
DeviceCapability getDeviceCapability(Device d) const override {
DeviceCapability cap;
cap.capability_data.capability_bits = (1ULL << kIndex_Byte) |
(1ULL << kIndex_Char) | (1ULL << kIndex_Short) | (1ULL << kIndex_Int) |
(1ULL << kIndex_Long) | (1ULL << kIndex_Float) |
(1ULL << kIndex_ComplexFloat) | (1ULL << kIndex_Bool) |
(1ULL << kIndex_Float8_e5m2) | (1ULL << kIndex_Float8_e4m3fn) |
(1ULL << kIndex_Float8_e5m2fnuz) | (1ULL << kIndex_Float8_e4m3fnuz) |
(1ULL << kIndex_Float8_e8m0fnu) | (1ULL << kIndex_UInt16) |
(1ULL << kIndex_UInt32) | (1ULL << kIndex_UInt64);
// BFloat16 may be emulated. We always assume BFloat16 is available;
// users can call is_bf16_supported() to check for native hardware support.
cap.capability_data.capability_bits |= (1ULL << kIndex_BFloat16);
auto& device = c10::xpu::get_raw_device(d.index());
if (device.has(sycl::aspect::fp16)) {
cap.capability_data.capability_bits |= (1ULL << kIndex_Half);
cap.capability_data.capability_bits |= (1ULL << kIndex_ComplexHalf);
}
if (device.has(sycl::aspect::fp64)) {
cap.capability_data.capability_bits |= (1ULL << kIndex_Double);
cap.capability_data.capability_bits |= (1ULL << kIndex_ComplexDouble);
}
return cap;
}
Stream getStream(Device d) const override {
return getCurrentXPUStream(d.index()).unwrap();
}
Stream getNewStream(Device d, int priority = 0) const override {
return getStreamFromPool(priority, d.index());
}
Stream getStreamFromGlobalPool(Device d, bool isHighPriority = false)
const override {
return getStreamFromPool(isHighPriority, d.index());
}
// NB: These do NOT set the current device
Stream exchangeStream(Stream s) const override {
const XPUStream stream(s);
const auto old_stream = getCurrentXPUStream(s.device().index());
setCurrentXPUStream(stream);
return old_stream.unwrap();
}
void* getStreamNativeHandle(const Stream s) const override {
const XPUStream stream{s};
return reinterpret_cast<void*>(&(stream.queue()));
}
DeviceIndex deviceCount() const noexcept override {
return c10::xpu::device_count();
}
// Event-related functions
void destroyEvent(void* event, const DeviceIndex device_index)
const noexcept override {
if (!event)
return;
const c10::impl::PyInterpreter* interp = c10::impl::GPUTrace::get_trace();
if (C10_UNLIKELY(interp)) {
(*interp)->trace_gpu_event_deletion(
c10::kXPU, reinterpret_cast<uintptr_t>(event));
}
delete reinterpret_cast<sycl::event*>(event);
}
void record(
void** event,
const Stream& stream,
const DeviceIndex device_index,
const EventFlag flag) const override {
TORCH_CHECK(
device_index == -1 || device_index == stream.device_index(),
"Event device index ",
device_index,
" does not match recording stream's device index ",
stream.device_index(),
".");
auto* xpu_event = reinterpret_cast<sycl::event*>(*event);
const XPUStream xpu_stream{stream};
// Delete the event previously recorded.
if (xpu_event)
delete xpu_event;
#if SYCL_COMPILER_VERSION >= 20250000
if (flag == EventFlag::BACKEND_DEFAULT) {
// Use the profiling tag to record the event to enable timing feature.
xpu_event =
new sycl::event(sycl::ext::oneapi::experimental::submit_profiling_tag(
xpu_stream.queue()));
} else {
xpu_event =
new sycl::event(xpu_stream.queue().ext_oneapi_submit_barrier());
}
#else
xpu_event = new sycl::event(xpu_stream.queue().ext_oneapi_submit_barrier());
#endif
*event = reinterpret_cast<void*>(xpu_event);
const c10::impl::PyInterpreter* interp = c10::impl::GPUTrace::get_trace();
if (C10_UNLIKELY(interp)) {
(*interp)->trace_gpu_event_record(
c10::kXPU,
reinterpret_cast<uintptr_t>(xpu_event),
reinterpret_cast<uintptr_t>(&xpu_stream.queue()));
}
}
void block(void* event, const Stream& stream) const override {
if (!event)
return;
auto* xpu_event = reinterpret_cast<sycl::event*>(event);
std::vector<sycl::event> event_list{*xpu_event};
const XPUStream xpu_stream(stream);
xpu_stream.queue().ext_oneapi_submit_barrier(event_list);
const c10::impl::PyInterpreter* interp = c10::impl::GPUTrace::get_trace();
if (C10_UNLIKELY(interp)) {
(*interp)->trace_gpu_event_wait(
c10::kXPU,
reinterpret_cast<uintptr_t>(xpu_event),
reinterpret_cast<uintptr_t>(&xpu_stream.queue()));
}
}
bool queryEvent(void* event) const override {
using namespace sycl::info;
if (!event)
return true;
auto* xpu_event = reinterpret_cast<sycl::event*>(event);
return xpu_event->get_info<event::command_execution_status>() ==
event_command_status::complete;
}
double elapsedTime(
void* start_event,
void* end_event,
const DeviceIndex device_index) const override {
#if SYCL_COMPILER_VERSION < 20250000
TORCH_CHECK_NOT_IMPLEMENTED(
false,
"elapsedTime requires PyTorch to be built with SYCL compiler version 2025.0.0 or newer.");
#endif
TORCH_CHECK(
start_event && end_event,
"Both events must be recorded before calculating elapsed time.");
auto* xpu_start_event = reinterpret_cast<sycl::event*>(start_event);
auto* xpu_end_event = reinterpret_cast<sycl::event*>(end_event);
using namespace sycl::info::event_profiling;
// Block until both of the recorded events are completed.
uint64_t end_time_ns = xpu_end_event->get_profiling_info<command_end>();
uint64_t start_time_ns = xpu_start_event->get_profiling_info<command_end>();
// Return the eplased time in milliseconds.
return 1e-6 *
(static_cast<double>(end_time_ns) - static_cast<double>(start_time_ns));
}
// Stream-related functions
bool queryStream(const Stream& stream) const override {
const XPUStream xpu_stream{stream};
return xpu_stream.query();
}
void synchronizeStream(const Stream& stream) const override {
const XPUStream xpu_stream{stream};
xpu_stream.synchronize();
}
bool isStreamCapturing(const Stream& stream) const override {
const XPUStream xpu_stream{stream};
return xpu_stream.is_capturing();
}
void synchronizeEvent(void* event) const override {
if (!event)
return;
auto* xpu_event = reinterpret_cast<sycl::event*>(event);
const c10::impl::PyInterpreter* interp = c10::impl::GPUTrace::get_trace();
if (C10_UNLIKELY(interp)) {
(*interp)->trace_gpu_event_synchronization(
c10::kXPU, reinterpret_cast<uintptr_t>(xpu_event));
}
xpu_event->wait_and_throw();
}
void synchronizeDevice(const c10::DeviceIndex device_index) const override {
const c10::impl::PyInterpreter* interp = c10::impl::GPUTrace::get_trace();
if (C10_UNLIKELY(interp)) {
(*interp)->trace_gpu_device_synchronization(c10::kXPU);
}
c10::xpu::syncStreamsOnDevice(device_index);
}
void recordDataPtrOnStream(const c10::DataPtr& data_ptr, const Stream& stream)
const override {
const XPUStream xpu_stream{stream};
XPUCachingAllocator::recordStream(data_ptr, xpu_stream);
}
};
} // namespace c10::xpu::impl
#else
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
@@ -0,0 +1,26 @@
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
#include <gtest/gtest.h>
#include <c10/util/irange.h>
static inline void initHostData(int* hostData, int numel) {
for (const auto i : c10::irange(numel)) {
hostData[i] = i;
}
}
static inline void clearHostData(int* hostData, int numel) {
for (const auto i : c10::irange(numel)) {
hostData[i] = 0;
}
}
static inline void validateHostData(int* hostData, int numel) {
for (const auto i : c10::irange(numel)) {
EXPECT_EQ(hostData[i], i);
}
}
#else
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)