chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,278 @@
|
||||
// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// The file has been adapted from pytorch project
|
||||
// Licensed under BSD-style license -
|
||||
// https://github.com/pytorch/pytorch/blob/main/LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <c10/core/Device.h>
|
||||
#include <c10/core/DeviceType.h>
|
||||
#include <c10/util/Exception.h>
|
||||
#include <c10/util/UniqueVoidPtr.h>
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include "paddle/phi/common/place.h"
|
||||
#include "paddle/phi/core/allocator.h"
|
||||
|
||||
namespace c10 {
|
||||
|
||||
// Deleter function pointer type (compatible with LibTorch)
|
||||
using DeleterFnPtr = void (*)(void*);
|
||||
|
||||
using CaptureId_t = uint64_t;
|
||||
using MempoolId_t = std::pair<CaptureId_t, CaptureId_t>;
|
||||
|
||||
struct MempoolIdHash {
|
||||
std::size_t operator()(const MempoolId_t& mempool_id) const noexcept {
|
||||
return mempool_id.first != 0 ? mempool_id.first : mempool_id.second;
|
||||
}
|
||||
};
|
||||
|
||||
// DataPtr class compatible with LibTorch's c10::DataPtr
|
||||
// Wraps a pointer with associated device and deleter
|
||||
class DataPtr {
|
||||
public:
|
||||
DataPtr() : device_(phi::CPUPlace()) {}
|
||||
|
||||
DataPtr(void* data, Device device)
|
||||
: ptr_(data), device_(device._PD_GetInner()) {}
|
||||
|
||||
DataPtr(void* data, void* ctx, DeleterFnPtr ctx_deleter, Device device)
|
||||
: ptr_(data, ctx, ctx_deleter), device_(device._PD_GetInner()) {}
|
||||
|
||||
// DataPtr is move-only, matching PyTorch's c10::DataPtr interface.
|
||||
DataPtr(const DataPtr&) = delete;
|
||||
DataPtr& operator=(const DataPtr&) = delete;
|
||||
DataPtr(DataPtr&&) = default;
|
||||
DataPtr& operator=(DataPtr&&) = default;
|
||||
|
||||
void* operator->() const { return ptr_.get(); }
|
||||
|
||||
bool unsafe_reset_data_and_ctx(void* new_data_and_ctx) {
|
||||
return ptr_.unsafe_reset_data_and_ctx(new_data_and_ctx);
|
||||
}
|
||||
|
||||
void clear() { ptr_.clear(); }
|
||||
void* get() const { return ptr_.get(); }
|
||||
void* mutable_get() { return ptr_.get(); }
|
||||
void* get_context() const { return ptr_.get_context(); }
|
||||
void* release_context() { return ptr_.release_context(); }
|
||||
|
||||
std::unique_ptr<void, DeleterFnPtr>&& move_context() {
|
||||
return ptr_.move_context();
|
||||
}
|
||||
|
||||
operator bool() const { return static_cast<bool>(ptr_); }
|
||||
|
||||
template <typename T>
|
||||
T* cast_context(DeleterFnPtr expected_deleter) const {
|
||||
return ptr_.cast_context<T>(expected_deleter);
|
||||
}
|
||||
|
||||
DeleterFnPtr get_deleter() const { return ptr_.get_deleter(); }
|
||||
|
||||
// Atomically replaces the deleter if it matches expected_deleter.
|
||||
// Returns true and installs new_deleter on match; does nothing and
|
||||
// returns false otherwise.
|
||||
[[nodiscard]] bool compare_exchange_deleter(DeleterFnPtr expected_deleter,
|
||||
DeleterFnPtr new_deleter) {
|
||||
return ptr_.compare_exchange_deleter(expected_deleter, new_deleter);
|
||||
}
|
||||
|
||||
Device device() const { return Device(device_); }
|
||||
|
||||
void unsafe_set_device(Device device) { device_ = device._PD_GetInner(); }
|
||||
|
||||
private:
|
||||
c10::detail::UniqueVoidPtr ptr_;
|
||||
phi::Place device_;
|
||||
};
|
||||
|
||||
inline bool operator==(const DataPtr& dp, std::nullptr_t) noexcept {
|
||||
return !dp;
|
||||
}
|
||||
|
||||
inline bool operator==(std::nullptr_t, const DataPtr& dp) noexcept {
|
||||
return !dp;
|
||||
}
|
||||
|
||||
inline bool operator!=(const DataPtr& dp, std::nullptr_t) noexcept {
|
||||
return static_cast<bool>(dp);
|
||||
}
|
||||
|
||||
inline bool operator!=(std::nullptr_t, const DataPtr& dp) noexcept {
|
||||
return static_cast<bool>(dp);
|
||||
}
|
||||
|
||||
struct Allocator {
|
||||
virtual ~Allocator() = default;
|
||||
|
||||
virtual DataPtr allocate(size_t n) = 0;
|
||||
|
||||
// Clones an allocation that came from this allocator.
|
||||
//
|
||||
// To perform the copy, this function calls `copy_data`, which
|
||||
// must be implemented by derived classes.
|
||||
//
|
||||
// Note that this explicitly ignores any context that may have been
|
||||
// attached to the input data.
|
||||
//
|
||||
// Requires: input data was allocated by the same allocator.
|
||||
DataPtr clone(const void* data, std::size_t n) {
|
||||
auto new_data = allocate(n);
|
||||
copy_data(new_data.mutable_get(), data, n);
|
||||
return new_data;
|
||||
}
|
||||
|
||||
// Checks if DataPtr has a simple context, not wrapped with any out of the
|
||||
// ordinary contexts.
|
||||
virtual bool is_simple_data_ptr(const DataPtr& data_ptr) const {
|
||||
return data_ptr.get() == data_ptr.get_context();
|
||||
}
|
||||
|
||||
// If this returns a non nullptr, it means that allocate()
|
||||
// is guaranteed to return a unique_ptr with this deleter attached;
|
||||
// it means the rawAllocate and rawDeallocate APIs are safe to use.
|
||||
// This function MUST always return the same BoundDeleter.
|
||||
virtual DeleterFnPtr raw_deleter() const { return nullptr; }
|
||||
void* raw_allocate(size_t n) {
|
||||
auto dptr = allocate(n);
|
||||
TORCH_CHECK(dptr.get() == dptr.get_context(),
|
||||
"raw_allocate: DataPtr context must equal data pointer");
|
||||
return dptr.release_context();
|
||||
}
|
||||
void raw_deallocate(void* ptr) {
|
||||
auto d = raw_deleter();
|
||||
TORCH_CHECK(d != nullptr, "raw_deallocate: deleter must not be null");
|
||||
d(ptr);
|
||||
}
|
||||
|
||||
// Copies data from one allocation to another.
|
||||
// Pure virtual, so derived classes must define behavior.
|
||||
// Derived class implementation can simply call `default_copy_data`
|
||||
// to use `std::memcpy`.
|
||||
//
|
||||
// Requires: src and dest were allocated by this allocator
|
||||
// Requires: src and dest both have length >= count
|
||||
virtual void copy_data(void* dest,
|
||||
const void* src,
|
||||
std::size_t count) const = 0;
|
||||
|
||||
protected:
|
||||
// Uses `std::memcpy` to copy data.
|
||||
// Child classes can use this as `copy_data` when an alternative copy
|
||||
// API is not needed.
|
||||
void default_copy_data(void* dest, const void* src, std::size_t count) const {
|
||||
std::memcpy(dest, src, count);
|
||||
}
|
||||
};
|
||||
|
||||
struct InefficientStdFunctionContext {
|
||||
void* ptr_{nullptr};
|
||||
std::function<void(void*)> deleter_;
|
||||
|
||||
InefficientStdFunctionContext(void* ptr, std::function<void(void*)> deleter)
|
||||
: ptr_(ptr), deleter_(std::move(deleter)) {}
|
||||
|
||||
InefficientStdFunctionContext(const InefficientStdFunctionContext&) = delete;
|
||||
|
||||
InefficientStdFunctionContext(InefficientStdFunctionContext&& rhs) noexcept
|
||||
: ptr_(std::exchange(rhs.ptr_, nullptr)),
|
||||
deleter_(std::move(rhs.deleter_)) {}
|
||||
|
||||
InefficientStdFunctionContext& operator=(
|
||||
const InefficientStdFunctionContext&) = delete;
|
||||
|
||||
InefficientStdFunctionContext& operator=(
|
||||
InefficientStdFunctionContext&& rhs) {
|
||||
this->~InefficientStdFunctionContext();
|
||||
ptr_ = std::exchange(rhs.ptr_, nullptr);
|
||||
deleter_ = std::move(rhs.deleter_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
~InefficientStdFunctionContext() {
|
||||
if (deleter_) {
|
||||
deleter_(ptr_);
|
||||
}
|
||||
}
|
||||
|
||||
static DataPtr makeDataPtr(void* ptr,
|
||||
std::function<void(void*)> deleter,
|
||||
Device device) {
|
||||
return DataPtr(ptr,
|
||||
new InefficientStdFunctionContext(ptr, std::move(deleter)),
|
||||
&deleteContext,
|
||||
device);
|
||||
}
|
||||
|
||||
private:
|
||||
static void deleteContext(void* ptr) {
|
||||
delete static_cast<InefficientStdFunctionContext*>(ptr);
|
||||
}
|
||||
};
|
||||
|
||||
inline constexpr size_t kAllocatorRegistrySize =
|
||||
static_cast<size_t>(DeviceType::CUSTOM) + 1;
|
||||
|
||||
inline std::array<Allocator*, kAllocatorRegistrySize> g_allocator_array{};
|
||||
inline std::array<uint8_t, kAllocatorRegistrySize> g_allocator_priority{};
|
||||
|
||||
inline size_t allocator_device_index(DeviceType t) {
|
||||
const size_t index = static_cast<size_t>(t);
|
||||
TORCH_CHECK(index < kAllocatorRegistrySize,
|
||||
"Allocator device type index out of range: ",
|
||||
index);
|
||||
return index;
|
||||
}
|
||||
|
||||
inline void SetAllocator(DeviceType t, Allocator* alloc, uint8_t priority = 0) {
|
||||
const size_t index = allocator_device_index(t);
|
||||
if (priority >= g_allocator_priority[index]) {
|
||||
g_allocator_array[index] = alloc;
|
||||
g_allocator_priority[index] = priority;
|
||||
}
|
||||
}
|
||||
|
||||
inline Allocator* GetAllocator(const DeviceType& t) {
|
||||
const size_t index = allocator_device_index(t);
|
||||
auto* alloc = g_allocator_array[index];
|
||||
TORCH_CHECK(alloc != nullptr, "Allocator for ", t, " is not set.");
|
||||
return alloc;
|
||||
}
|
||||
|
||||
template <DeviceType t>
|
||||
struct AllocatorRegisterer {
|
||||
explicit AllocatorRegisterer(Allocator* alloc) { SetAllocator(t, alloc); }
|
||||
};
|
||||
|
||||
#define REGISTER_ALLOCATOR(t, f) \
|
||||
namespace { \
|
||||
static c10::AllocatorRegisterer<t> g_allocator_d(f); \
|
||||
}
|
||||
|
||||
} // namespace c10
|
||||
|
||||
namespace at {
|
||||
using DataPtr = c10::DataPtr;
|
||||
} // namespace at
|
||||
@@ -0,0 +1,77 @@
|
||||
// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace c10 {
|
||||
/**
|
||||
* This legacy enum class defines the set of backends supported by old school,
|
||||
* code generated Type-based ATen. A "backend" in this sense roughly
|
||||
* corresponds to the cartesian product of (device type, layout), but restricted
|
||||
* only to combinations which we actually have kernels for. Backend does NOT
|
||||
* include dtype.
|
||||
*
|
||||
* The reason we are sunsetting this enum class is because it doesn't allow for
|
||||
* open registration; e.g., if you want to add SparseXLA, you'd have to
|
||||
* edit this enum; you wouldn't be able to do it out of tree. DispatchKey is
|
||||
* the replacement for Backend which supports open registration.
|
||||
*
|
||||
* NB: The concept of 'Backend' here disagrees with the notion of backend
|
||||
* exposed to users in torch.backends. Backend here is something like "CPU"
|
||||
* or "SparseCUDA"; backend in torch.backends is something like "MKL" or
|
||||
* "CUDNN".
|
||||
*/
|
||||
|
||||
enum class Backend {
|
||||
CPU,
|
||||
CUDA,
|
||||
HIP,
|
||||
VE,
|
||||
FPGA,
|
||||
IPU,
|
||||
XPU,
|
||||
SparseCPU,
|
||||
SparseCUDA,
|
||||
SparseCsrCPU,
|
||||
SparseCsrCUDA,
|
||||
SparseCsrMPS,
|
||||
SparseMPS,
|
||||
SparseHIP,
|
||||
SparseVE,
|
||||
SparseXPU,
|
||||
SparsePrivateUse1,
|
||||
SparseCsrHIP,
|
||||
SparseCsrVE,
|
||||
SparseCsrXPU,
|
||||
SparseCsrPrivateUse1,
|
||||
MAIA,
|
||||
XLA,
|
||||
Vulkan,
|
||||
Metal,
|
||||
Meta,
|
||||
QuantizedCPU,
|
||||
QuantizedCUDA,
|
||||
QuantizedXPU,
|
||||
QuantizedPrivateUse1,
|
||||
Undefined,
|
||||
MkldnnCPU,
|
||||
MPS,
|
||||
HPU,
|
||||
Lazy,
|
||||
MTIA,
|
||||
PrivateUse1,
|
||||
NumOptions
|
||||
};
|
||||
|
||||
} // namespace c10
|
||||
@@ -0,0 +1,50 @@
|
||||
// Copyright (c) 2026 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// 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.
|
||||
|
||||
#include <c10/core/DefaultDtype.h>
|
||||
#include <c10/util/complex.h>
|
||||
#include <c10/util/typeid.h>
|
||||
|
||||
namespace c10 {
|
||||
static auto default_dtype = caffe2::TypeMeta::Make<float>();
|
||||
static auto default_dtype_as_scalartype = default_dtype.toScalarType();
|
||||
static auto default_complex_dtype =
|
||||
caffe2::TypeMeta::Make<c10::complex<float>>();
|
||||
|
||||
void set_default_dtype(caffe2::TypeMeta dtype) {
|
||||
default_dtype = dtype;
|
||||
default_dtype_as_scalartype = default_dtype.toScalarType();
|
||||
switch (default_dtype_as_scalartype) {
|
||||
case ScalarType::Half:
|
||||
default_complex_dtype = ScalarType::ComplexHalf;
|
||||
break;
|
||||
case ScalarType::Double:
|
||||
default_complex_dtype = ScalarType::ComplexDouble;
|
||||
break;
|
||||
default:
|
||||
default_complex_dtype = ScalarType::ComplexFloat;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const caffe2::TypeMeta get_default_dtype() { return default_dtype; }
|
||||
|
||||
ScalarType get_default_dtype_as_scalartype() {
|
||||
return default_dtype_as_scalartype;
|
||||
}
|
||||
|
||||
const caffe2::TypeMeta get_default_complex_dtype() {
|
||||
return default_complex_dtype;
|
||||
}
|
||||
} // namespace c10
|
||||
@@ -0,0 +1,30 @@
|
||||
// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <c10/core/ScalarType.h>
|
||||
|
||||
#include "paddle/common/macros.h"
|
||||
|
||||
namespace caffe2 {
|
||||
class TypeMeta;
|
||||
} // namespace caffe2
|
||||
|
||||
namespace c10 {
|
||||
PADDLE_API void set_default_dtype(caffe2::TypeMeta dtype);
|
||||
PADDLE_API const caffe2::TypeMeta get_default_dtype();
|
||||
PADDLE_API ScalarType get_default_dtype_as_scalartype();
|
||||
PADDLE_API const caffe2::TypeMeta get_default_complex_dtype();
|
||||
} // namespace c10
|
||||
@@ -0,0 +1,161 @@
|
||||
// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// The file has been adapted from pytorch project
|
||||
// Licensed under BSD-style license -
|
||||
// https://github.com/pytorch/pytorch/blob/main/LICENSE
|
||||
|
||||
#include <c10/core/Device.h>
|
||||
#include <c10/util/Exception.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cctype>
|
||||
#include <exception>
|
||||
#include <string>
|
||||
|
||||
#include "paddle/common/enforce.h"
|
||||
|
||||
namespace c10 {
|
||||
|
||||
namespace {
|
||||
|
||||
const char* DeviceTypeToString(DeviceType type) {
|
||||
switch (type) {
|
||||
case DeviceType::CPU:
|
||||
return "cpu";
|
||||
case DeviceType::CUDA:
|
||||
return "cuda";
|
||||
case DeviceType::XPU:
|
||||
return "xpu";
|
||||
case DeviceType::IPU:
|
||||
return "ipu";
|
||||
case DeviceType::CUSTOM:
|
||||
return "privateuseone";
|
||||
}
|
||||
return "cpu";
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
DeviceType parse_type(const std::string& device_string) {
|
||||
static const std::array<std::pair<const char*, DeviceType>,
|
||||
static_cast<size_t>(5)>
|
||||
types = {{
|
||||
{"cpu", DeviceType::CPU},
|
||||
{"cuda", DeviceType::CUDA},
|
||||
{"ipu", DeviceType::IPU},
|
||||
{"xpu", DeviceType::XPU},
|
||||
{"privateuseone", DeviceType::PrivateUse1},
|
||||
}};
|
||||
auto device = std::find_if(
|
||||
types.begin(),
|
||||
types.end(),
|
||||
[&device_string](const std::pair<const char*, DeviceType>& p) {
|
||||
return p.first && p.first == device_string;
|
||||
});
|
||||
if (device != types.end()) {
|
||||
return device->second;
|
||||
}
|
||||
TORCH_CHECK(false,
|
||||
"Expected one of cpu, cuda, ipu, xpu, privateuseone device type "
|
||||
"at start of device string: ",
|
||||
device_string);
|
||||
}
|
||||
|
||||
enum DeviceStringParsingState { kStart, kIndexStart, kIndexRest, kError };
|
||||
|
||||
Device::Device(const std::string& device_string) : Device(Type::CPU) {
|
||||
TORCH_CHECK(!device_string.empty(), "Device string must not be empty");
|
||||
|
||||
std::string device_name, device_index_str;
|
||||
DeviceStringParsingState pstate = DeviceStringParsingState::kStart;
|
||||
|
||||
for (size_t i = 0;
|
||||
pstate != DeviceStringParsingState::kError && i < device_string.size();
|
||||
++i) {
|
||||
const char ch = device_string.at(i);
|
||||
const unsigned char uch = static_cast<unsigned char>(ch);
|
||||
switch (pstate) {
|
||||
case DeviceStringParsingState::kStart:
|
||||
if (ch != ':') {
|
||||
if (std::isalpha(uch) || ch == '_') {
|
||||
device_name.push_back(ch);
|
||||
} else {
|
||||
pstate = DeviceStringParsingState::kError;
|
||||
}
|
||||
} else {
|
||||
pstate = DeviceStringParsingState::kIndexStart;
|
||||
}
|
||||
break;
|
||||
case DeviceStringParsingState::kIndexStart:
|
||||
if (std::isdigit(uch)) {
|
||||
device_index_str.push_back(ch);
|
||||
pstate = DeviceStringParsingState::kIndexRest;
|
||||
} else {
|
||||
pstate = DeviceStringParsingState::kError;
|
||||
}
|
||||
break;
|
||||
case DeviceStringParsingState::kIndexRest:
|
||||
if (device_index_str.at(0) == '0') {
|
||||
pstate = DeviceStringParsingState::kError;
|
||||
break;
|
||||
}
|
||||
if (std::isdigit(uch)) {
|
||||
device_index_str.push_back(ch);
|
||||
} else {
|
||||
pstate = DeviceStringParsingState::kError;
|
||||
}
|
||||
break;
|
||||
case DeviceStringParsingState::kError:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const bool has_error = device_name.empty() ||
|
||||
pstate == DeviceStringParsingState::kError ||
|
||||
(pstate == DeviceStringParsingState::kIndexStart &&
|
||||
device_index_str.empty());
|
||||
TORCH_CHECK(!has_error, "Invalid device string: '", device_string, "'");
|
||||
|
||||
try {
|
||||
if (!device_index_str.empty()) {
|
||||
index_ = static_cast<DeviceIndex>(std::stoi(device_index_str));
|
||||
}
|
||||
} catch (const std::exception&) {
|
||||
TORCH_CHECK(false,
|
||||
"Could not parse device index '",
|
||||
device_index_str,
|
||||
"' in device string '",
|
||||
device_string,
|
||||
"'");
|
||||
}
|
||||
type_ = parse_type(device_name);
|
||||
validate();
|
||||
}
|
||||
|
||||
std::string Device::str() const {
|
||||
std::string str = DeviceTypeToString(type());
|
||||
if (has_index()) {
|
||||
str.push_back(':');
|
||||
str.append(std::to_string(index()));
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& stream, const Device& device) {
|
||||
stream << device.str();
|
||||
return stream;
|
||||
}
|
||||
} // namespace c10
|
||||
@@ -0,0 +1,191 @@
|
||||
// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
#ifdef PADDLE_WITH_CUDA
|
||||
#include <cuda_runtime.h>
|
||||
using gpuStream_t = cudaStream_t;
|
||||
#endif
|
||||
|
||||
#ifdef PADDLE_WITH_HIP
|
||||
#include <hip/hip_runtime.h>
|
||||
using gpuStream_t = hipStream_t;
|
||||
#endif
|
||||
|
||||
#include <c10/core/DeviceType.h>
|
||||
#include <c10/util/Exception.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <iosfwd>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "paddle/common/macros.h"
|
||||
#include "paddle/phi/core/platform/device/gpu/gpu_info.h"
|
||||
#include "paddle/phi/core/platform/device_event_base.h"
|
||||
|
||||
namespace c10 {
|
||||
using DeviceIndex = int8_t;
|
||||
|
||||
struct PADDLE_API Device final {
|
||||
using Type = DeviceType;
|
||||
Device() = default;
|
||||
Device(phi::Place place)
|
||||
: type_(PhiToDeviceType(place.GetType())),
|
||||
index_(place.GetType() == phi::AllocationType::CPU
|
||||
? static_cast<DeviceIndex>(-1)
|
||||
: place.GetDeviceId()),
|
||||
custom_device_type_(place.GetDeviceType()) {
|
||||
validate();
|
||||
}
|
||||
Device(DeviceType type, DeviceIndex index = -1)
|
||||
: type_(type), index_(index) { // NOLINT
|
||||
validate();
|
||||
}
|
||||
Device(DeviceType type, DeviceIndex index, std::string custom_device_type)
|
||||
: type_(type),
|
||||
index_(index),
|
||||
custom_device_type_(std::move(custom_device_type)) { // NOLINT
|
||||
validate();
|
||||
}
|
||||
|
||||
/// Constructs a `Device` from a string description, for convenience.
|
||||
/// The string supplied must follow the following schema:
|
||||
/// `(cpu|cuda)[:<device-index>]`
|
||||
/// where `cpu` or `cuda` specifies the device type, and
|
||||
/// `:<device-index>` optionally specifies a device index.
|
||||
/* implicit */ Device(const std::string& device_string);
|
||||
|
||||
DeviceIndex index() const noexcept { return index_; }
|
||||
|
||||
bool has_index() const noexcept { return index() != -1; }
|
||||
|
||||
DeviceType type() const noexcept { return type_; }
|
||||
|
||||
bool operator!=(const Device& other) const noexcept {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
void set_index(DeviceIndex index) {
|
||||
index_ = index;
|
||||
validate();
|
||||
}
|
||||
|
||||
bool is_cuda() const noexcept { return type_ == DeviceType::CUDA; }
|
||||
|
||||
bool is_privateuseone() const noexcept {
|
||||
return type_ == DeviceType::PrivateUse1;
|
||||
}
|
||||
|
||||
bool is_mps() const noexcept { return false; }
|
||||
|
||||
bool is_hip() const noexcept { return false; }
|
||||
|
||||
bool is_ve() const noexcept { return false; }
|
||||
|
||||
bool is_xpu() const noexcept { return type_ == DeviceType::XPU; }
|
||||
|
||||
bool is_ipu() const noexcept { return type_ == DeviceType::IPU; }
|
||||
|
||||
bool is_xla() const noexcept { return false; }
|
||||
|
||||
bool is_mtia() const noexcept { return false; }
|
||||
|
||||
bool is_hpu() const noexcept { return false; }
|
||||
|
||||
bool is_lazy() const noexcept { return false; }
|
||||
|
||||
bool is_vulkan() const noexcept { return false; }
|
||||
|
||||
bool is_metal() const noexcept { return false; }
|
||||
|
||||
bool is_maia() const noexcept { return false; }
|
||||
|
||||
bool is_meta() const noexcept { return false; }
|
||||
|
||||
bool is_cpu() const noexcept { return type_ == DeviceType::CPU; }
|
||||
|
||||
bool supports_as_strided() const noexcept { return type_ != DeviceType::IPU; }
|
||||
|
||||
std::string str() const;
|
||||
|
||||
bool operator==(const Device& other) const noexcept {
|
||||
return type() == other.type() && this->index() == other.index() &&
|
||||
custom_device_type_ == other.custom_device_type_;
|
||||
}
|
||||
|
||||
phi::Place _PD_GetInner() const {
|
||||
switch (type_) {
|
||||
case DeviceType::CPU:
|
||||
return phi::CPUPlace();
|
||||
case DeviceType::CUDA:
|
||||
return has_index() ? phi::GPUPlace(index_) : paddle::DefaultGPUPlace();
|
||||
case DeviceType::XPU:
|
||||
return has_index() ? phi::XPUPlace(index_) : paddle::DefaultXPUPlace();
|
||||
case DeviceType::IPU:
|
||||
return has_index() ? phi::IPUPlace(index_) : phi::IPUPlace();
|
||||
case DeviceType::CUSTOM:
|
||||
return phi::CustomPlace(
|
||||
custom_device_type_.empty() ? "custom" : custom_device_type_,
|
||||
has_index() ? index_ : 0);
|
||||
}
|
||||
return phi::CPUPlace();
|
||||
}
|
||||
|
||||
private:
|
||||
DeviceType type_{DeviceType::CPU};
|
||||
DeviceIndex index_{-1};
|
||||
std::string custom_device_type_;
|
||||
|
||||
void validate() {
|
||||
#ifndef NDEBUG
|
||||
TORCH_INTERNAL_ASSERT(index_ >= -1,
|
||||
"Device index must be -1 or non-negative, got ",
|
||||
static_cast<int>(index_));
|
||||
TORCH_INTERNAL_ASSERT(!is_cpu() || index_ <= 0,
|
||||
"CPU device index must be -1 or zero, got ",
|
||||
static_cast<int>(index_));
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
PADDLE_API std::ostream& operator<<(std::ostream& stream, const Device& device);
|
||||
|
||||
} // namespace c10
|
||||
|
||||
namespace std {
|
||||
template <>
|
||||
struct hash<c10::Device> {
|
||||
size_t operator()(c10::Device d) const noexcept {
|
||||
static_assert(sizeof(c10::DeviceType) == 1, "DeviceType is not 8-bit");
|
||||
static_assert(sizeof(c10::DeviceIndex) == 1, "DeviceIndex is not 8-bit");
|
||||
uint32_t bits = static_cast<uint32_t>(static_cast<uint8_t>(d.type()))
|
||||
<< 16 |
|
||||
static_cast<uint32_t>(static_cast<uint8_t>(d.index()));
|
||||
return std::hash<uint32_t>{}(bits);
|
||||
}
|
||||
};
|
||||
} // namespace std
|
||||
|
||||
namespace at {
|
||||
using c10::Device;
|
||||
using c10::DeviceIndex;
|
||||
} // namespace at
|
||||
|
||||
namespace torch {
|
||||
using c10::Device;
|
||||
using c10::DeviceIndex;
|
||||
} // namespace torch
|
||||
@@ -0,0 +1,94 @@
|
||||
// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
// If you modified DeviceType in this file, please also sync your changes into
|
||||
// torch/headeronly/core/DeviceType.h.
|
||||
#include <torch/headeronly/core/DeviceType.h>
|
||||
|
||||
#include <ostream>
|
||||
|
||||
#include "paddle/phi/common/place.h"
|
||||
|
||||
namespace c10 {
|
||||
|
||||
inline phi::AllocationType DeviceTypeToPhi(DeviceType d) {
|
||||
switch (d) {
|
||||
case DeviceType::CPU:
|
||||
return phi::AllocationType::CPU;
|
||||
case DeviceType::CUDA:
|
||||
return phi::AllocationType::GPU;
|
||||
case DeviceType::XPU:
|
||||
return phi::AllocationType::XPU;
|
||||
case DeviceType::IPU:
|
||||
return phi::AllocationType::IPU;
|
||||
case DeviceType::CUSTOM:
|
||||
return phi::AllocationType::CUSTOM;
|
||||
}
|
||||
return phi::AllocationType::UNDEFINED;
|
||||
}
|
||||
|
||||
inline DeviceType PhiToDeviceType(phi::AllocationType d) {
|
||||
switch (d) {
|
||||
case phi::AllocationType::CPU:
|
||||
return DeviceType::CPU;
|
||||
case phi::AllocationType::GPU:
|
||||
return DeviceType::CUDA;
|
||||
case phi::AllocationType::XPU:
|
||||
return DeviceType::XPU;
|
||||
case phi::AllocationType::IPU:
|
||||
return DeviceType::IPU;
|
||||
case phi::AllocationType::CUSTOM:
|
||||
return DeviceType::CUSTOM;
|
||||
default:
|
||||
return DeviceType::CPU;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool isValidDeviceType(DeviceType d) {
|
||||
switch (d) {
|
||||
case DeviceType::CPU:
|
||||
case DeviceType::CUDA:
|
||||
case DeviceType::XPU:
|
||||
case DeviceType::IPU:
|
||||
case DeviceType::CUSTOM:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& os, DeviceType d) {
|
||||
switch (d) {
|
||||
case DeviceType::CPU:
|
||||
os << "cpu";
|
||||
break;
|
||||
case DeviceType::CUDA:
|
||||
os << "cuda";
|
||||
break;
|
||||
case DeviceType::XPU:
|
||||
os << "xpu";
|
||||
break;
|
||||
case DeviceType::IPU:
|
||||
os << "ipu";
|
||||
break;
|
||||
case DeviceType::CUSTOM:
|
||||
os << "privateuseone";
|
||||
break;
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
} // namespace c10
|
||||
@@ -0,0 +1,598 @@
|
||||
// Copyright (c) 2026 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <c10/core/DeviceType.h>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
|
||||
namespace c10 {
|
||||
|
||||
#define C10_FORALL_BACKEND_COMPONENTS(_, extra) \
|
||||
_(CPU, extra) \
|
||||
_(CUDA, extra) \
|
||||
_(HIP, extra) \
|
||||
_(XLA, extra) \
|
||||
_(MPS, extra) \
|
||||
_(IPU, extra) \
|
||||
_(XPU, extra) \
|
||||
_(HPU, extra) \
|
||||
_(VE, extra) \
|
||||
_(Lazy, extra) \
|
||||
_(MTIA, extra) \
|
||||
_(MAIA, extra) \
|
||||
_(PrivateUse1, extra) \
|
||||
_(PrivateUse2, extra) \
|
||||
_(PrivateUse3, extra) \
|
||||
_(Meta, extra)
|
||||
|
||||
#define C10_FORALL_FUNCTIONALITY_KEYS(_) \
|
||||
_(Dense, ) /* NOLINT */ \
|
||||
_(Quantized, Quantized) \
|
||||
_(Sparse, Sparse) \
|
||||
_(SparseCsr, SparseCsr) \
|
||||
_(NestedTensor, NestedTensor) \
|
||||
_(AutogradFunctionality, Autograd)
|
||||
|
||||
enum class BackendComponent : uint8_t {
|
||||
InvalidBit = 0,
|
||||
#define DEFINE_BACKEND_COMPONENT(n, _) n##Bit,
|
||||
C10_FORALL_BACKEND_COMPONENTS(DEFINE_BACKEND_COMPONENT, unused)
|
||||
#undef DEFINE_BACKEND_COMPONENT
|
||||
|
||||
EndOfBackendKeys = MetaBit,
|
||||
};
|
||||
|
||||
enum class DispatchKey : uint16_t {
|
||||
Undefined = 0,
|
||||
|
||||
CatchAll = Undefined,
|
||||
|
||||
Dense,
|
||||
|
||||
FPGA,
|
||||
|
||||
Vulkan,
|
||||
Metal,
|
||||
|
||||
Quantized,
|
||||
|
||||
CustomRNGKeyId,
|
||||
|
||||
MkldnnCPU,
|
||||
|
||||
Sparse,
|
||||
|
||||
SparseCsr,
|
||||
|
||||
NestedTensor,
|
||||
|
||||
BackendSelect,
|
||||
|
||||
Python,
|
||||
|
||||
Fake,
|
||||
FuncTorchDynamicLayerBackMode,
|
||||
|
||||
Functionalize,
|
||||
|
||||
Named,
|
||||
|
||||
Conjugate,
|
||||
|
||||
Negative,
|
||||
|
||||
ZeroTensor,
|
||||
|
||||
ADInplaceOrView,
|
||||
|
||||
AutogradOther,
|
||||
|
||||
AutogradFunctionality,
|
||||
|
||||
AutogradNestedTensor,
|
||||
|
||||
Tracer,
|
||||
|
||||
AutocastCPU,
|
||||
AutocastMTIA,
|
||||
AutocastMAIA,
|
||||
AutocastXPU,
|
||||
AutocastIPU,
|
||||
AutocastHPU,
|
||||
AutocastXLA,
|
||||
AutocastMPS,
|
||||
AutocastCUDA,
|
||||
AutocastPrivateUse1,
|
||||
|
||||
FuncTorchBatched,
|
||||
|
||||
BatchedNestedTensor,
|
||||
|
||||
FuncTorchVmapMode,
|
||||
|
||||
Batched,
|
||||
|
||||
VmapMode,
|
||||
|
||||
FuncTorchGradWrapper,
|
||||
|
||||
DeferredInit,
|
||||
|
||||
PythonTLSSnapshot,
|
||||
|
||||
FuncTorchDynamicLayerFrontMode,
|
||||
|
||||
TESTING_ONLY_GenericWrapper,
|
||||
|
||||
TESTING_ONLY_GenericMode,
|
||||
|
||||
PreDispatch,
|
||||
|
||||
PythonDispatcher,
|
||||
|
||||
EndOfFunctionalityKeys,
|
||||
|
||||
#define DEFINE_PER_BACKEND_KEYS_FOR_BACKEND(n, prefix) prefix##n,
|
||||
|
||||
#define DEFINE_PER_BACKEND_KEYS(fullname, prefix) \
|
||||
StartOf##fullname##Backends, \
|
||||
C10_FORALL_BACKEND_COMPONENTS(DEFINE_PER_BACKEND_KEYS_FOR_BACKEND, \
|
||||
prefix) EndOf##fullname##Backends = \
|
||||
prefix##Meta,
|
||||
|
||||
C10_FORALL_FUNCTIONALITY_KEYS(DEFINE_PER_BACKEND_KEYS)
|
||||
|
||||
#undef DEFINE_PER_BACKEND_KEYS
|
||||
#undef DEFINE_PER_BACKEND_KEYS_FOR_BACKEND
|
||||
|
||||
EndOfRuntimeBackendKeys = EndOfAutogradFunctionalityBackends,
|
||||
|
||||
Autograd,
|
||||
CompositeImplicitAutograd,
|
||||
|
||||
FuncTorchBatchedDecomposition,
|
||||
CompositeImplicitAutogradNestedTensor,
|
||||
CompositeExplicitAutograd,
|
||||
CompositeExplicitAutogradNonFunctional,
|
||||
|
||||
StartOfAliasKeys = Autograd,
|
||||
EndOfAliasKeys = CompositeExplicitAutogradNonFunctional,
|
||||
|
||||
CPUTensorId = CPU,
|
||||
CUDATensorId = CUDA,
|
||||
DefaultBackend = CompositeExplicitAutograd,
|
||||
PrivateUse1_PreAutograd = AutogradPrivateUse1,
|
||||
PrivateUse2_PreAutograd = AutogradPrivateUse2,
|
||||
PrivateUse3_PreAutograd = AutogradPrivateUse3,
|
||||
Autocast = AutocastCUDA,
|
||||
};
|
||||
|
||||
static_assert(
|
||||
(static_cast<uint8_t>(BackendComponent::EndOfBackendKeys) +
|
||||
static_cast<uint8_t>(DispatchKey::EndOfFunctionalityKeys)) <= 64,
|
||||
"The BackendComponent and DispatchKey enums (below EndOfFunctionalityKeys)"
|
||||
" both map to backend and functionality bits"
|
||||
" into a 64-bit bitmask; you must have less than 64 total entries between "
|
||||
"them");
|
||||
|
||||
constexpr bool isAliasDispatchKey(DispatchKey k) {
|
||||
return k >= DispatchKey::StartOfAliasKeys && k <= DispatchKey::EndOfAliasKeys;
|
||||
}
|
||||
|
||||
constexpr bool isPerBackendFunctionalityKey(DispatchKey k) {
|
||||
if (k == DispatchKey::Dense || k == DispatchKey::Quantized ||
|
||||
k == DispatchKey::Sparse || k == DispatchKey::SparseCsr ||
|
||||
k == DispatchKey::AutogradFunctionality ||
|
||||
k == DispatchKey::NestedTensor) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr uint8_t num_functionality_keys =
|
||||
static_cast<uint8_t>(DispatchKey::EndOfFunctionalityKeys);
|
||||
|
||||
constexpr uint8_t num_backends =
|
||||
static_cast<uint8_t>(BackendComponent::EndOfBackendKeys);
|
||||
|
||||
static_assert(static_cast<uint8_t>(BackendComponent::EndOfBackendKeys) <= 16,
|
||||
"BackendComponent currently only supports <= 16 backends. "
|
||||
"If we really need to extend this, "
|
||||
"there are a few places where this invariant is baked in");
|
||||
|
||||
constexpr uint8_t numPerBackendFunctionalityKeys() {
|
||||
uint8_t count = 0;
|
||||
for (uint8_t k = 0; k <= num_functionality_keys; ++k) {
|
||||
if (isPerBackendFunctionalityKey(static_cast<DispatchKey>(k))) ++count;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
#if defined(C10_MOBILE_TRIM_DISPATCH_KEYS)
|
||||
constexpr uint16_t num_runtime_entries = 8;
|
||||
#else
|
||||
constexpr uint16_t num_runtime_entries =
|
||||
num_functionality_keys +
|
||||
(numPerBackendFunctionalityKeys() * (num_backends - 1));
|
||||
#endif
|
||||
|
||||
constexpr uint16_t full_backend_mask =
|
||||
(static_cast<uint16_t>(1) << num_backends) - 1;
|
||||
|
||||
const char* toString(DispatchKey /*t*/);
|
||||
const char* toString(BackendComponent /*t*/);
|
||||
std::ostream& operator<<(std::ostream& /*str*/, DispatchKey /*rhs*/);
|
||||
std::ostream& operator<<(std::ostream& /*str*/, BackendComponent /*rhs*/);
|
||||
|
||||
DispatchKey getAutogradKeyFromBackend(BackendComponent k);
|
||||
|
||||
c10::DispatchKey parseDispatchKey(const std::string& k);
|
||||
|
||||
constexpr DispatchKey kAutograd = DispatchKey::Autograd;
|
||||
|
||||
constexpr BackendComponent toBackendComponent(DispatchKey k) {
|
||||
if (k >= DispatchKey::StartOfDenseBackends &&
|
||||
k <= DispatchKey::EndOfDenseBackends) {
|
||||
return static_cast<BackendComponent>(
|
||||
static_cast<uint8_t>(k) -
|
||||
static_cast<uint8_t>(DispatchKey::StartOfDenseBackends));
|
||||
} else if (k >= DispatchKey::StartOfQuantizedBackends &&
|
||||
k <= DispatchKey::EndOfQuantizedBackends) {
|
||||
return static_cast<BackendComponent>(
|
||||
static_cast<uint8_t>(k) -
|
||||
static_cast<uint8_t>(DispatchKey::StartOfQuantizedBackends));
|
||||
} else if (k >= DispatchKey::StartOfSparseBackends &&
|
||||
k <= DispatchKey::EndOfSparseBackends) {
|
||||
return static_cast<BackendComponent>(
|
||||
static_cast<uint8_t>(k) -
|
||||
static_cast<uint8_t>(DispatchKey::StartOfSparseBackends));
|
||||
} else if (k >= DispatchKey::StartOfSparseCsrBackends &&
|
||||
k <= DispatchKey::EndOfSparseCsrBackends) {
|
||||
return static_cast<BackendComponent>(
|
||||
static_cast<uint8_t>(k) -
|
||||
static_cast<uint8_t>(DispatchKey::StartOfSparseCsrBackends));
|
||||
} else if (k >= DispatchKey::StartOfNestedTensorBackends &&
|
||||
k <= DispatchKey::EndOfNestedTensorBackends) {
|
||||
return static_cast<BackendComponent>(
|
||||
static_cast<uint8_t>(k) -
|
||||
static_cast<uint8_t>(DispatchKey::StartOfNestedTensorBackends));
|
||||
} else if (k >= DispatchKey::StartOfAutogradFunctionalityBackends &&
|
||||
k <= DispatchKey::EndOfAutogradFunctionalityBackends) {
|
||||
return static_cast<BackendComponent>(
|
||||
static_cast<uint8_t>(k) -
|
||||
static_cast<uint8_t>(
|
||||
DispatchKey::StartOfAutogradFunctionalityBackends));
|
||||
} else {
|
||||
return BackendComponent::InvalidBit;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr DispatchKey toFunctionalityKey(DispatchKey k) {
|
||||
if (k <= DispatchKey::EndOfFunctionalityKeys) {
|
||||
return k;
|
||||
} else if (k <= DispatchKey::EndOfDenseBackends) {
|
||||
return DispatchKey::Dense;
|
||||
} else if (k <= DispatchKey::EndOfQuantizedBackends) {
|
||||
return DispatchKey::Quantized;
|
||||
} else if (k <= DispatchKey::EndOfSparseBackends) {
|
||||
return DispatchKey::Sparse;
|
||||
} else if (k <= DispatchKey::EndOfSparseCsrBackends) {
|
||||
return DispatchKey::SparseCsr;
|
||||
} else if (k <= DispatchKey::EndOfNestedTensorBackends) {
|
||||
return DispatchKey::NestedTensor;
|
||||
} else if (k <= DispatchKey::EndOfAutogradFunctionalityBackends) {
|
||||
return DispatchKey::AutogradFunctionality;
|
||||
} else {
|
||||
return DispatchKey::Undefined;
|
||||
}
|
||||
}
|
||||
|
||||
inline BackendComponent toBackendComponent(DeviceType device_type) {
|
||||
switch (device_type) {
|
||||
case DeviceType::CPU:
|
||||
return BackendComponent::CPUBit;
|
||||
case DeviceType::CUDA:
|
||||
return BackendComponent::CUDABit;
|
||||
case DeviceType::XPU:
|
||||
return BackendComponent::XPUBit;
|
||||
default:
|
||||
return BackendComponent::InvalidBit;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr DispatchKey toRuntimePerBackendFunctionalityKey(
|
||||
DispatchKey functionality_k, BackendComponent backend_k) {
|
||||
if (functionality_k == DispatchKey::Dense) {
|
||||
return static_cast<DispatchKey>(
|
||||
static_cast<uint8_t>(DispatchKey::StartOfDenseBackends) +
|
||||
static_cast<uint8_t>(backend_k));
|
||||
}
|
||||
if (functionality_k == DispatchKey::Sparse) {
|
||||
return static_cast<DispatchKey>(
|
||||
static_cast<uint8_t>(DispatchKey::StartOfSparseBackends) +
|
||||
static_cast<uint8_t>(backend_k));
|
||||
}
|
||||
if (functionality_k == DispatchKey::SparseCsr) {
|
||||
return static_cast<DispatchKey>(
|
||||
static_cast<uint8_t>(DispatchKey::StartOfSparseCsrBackends) +
|
||||
static_cast<uint8_t>(backend_k));
|
||||
}
|
||||
if (functionality_k == DispatchKey::Quantized) {
|
||||
return static_cast<DispatchKey>(
|
||||
static_cast<uint8_t>(DispatchKey::StartOfQuantizedBackends) +
|
||||
static_cast<uint8_t>(backend_k));
|
||||
}
|
||||
if (functionality_k == DispatchKey::NestedTensor) {
|
||||
return static_cast<DispatchKey>(
|
||||
static_cast<uint8_t>(DispatchKey::StartOfNestedTensorBackends) +
|
||||
static_cast<uint8_t>(backend_k));
|
||||
}
|
||||
if (functionality_k == DispatchKey::AutogradFunctionality) {
|
||||
return static_cast<DispatchKey>(
|
||||
static_cast<uint8_t>(
|
||||
DispatchKey::StartOfAutogradFunctionalityBackends) +
|
||||
static_cast<uint8_t>(backend_k));
|
||||
}
|
||||
return DispatchKey::Undefined;
|
||||
}
|
||||
|
||||
// toString implementations
|
||||
inline const char* toString(DispatchKey t) {
|
||||
switch (t) {
|
||||
case DispatchKey::Undefined:
|
||||
return "Undefined";
|
||||
case DispatchKey::Dense:
|
||||
return "Dense";
|
||||
case DispatchKey::FPGA:
|
||||
return "FPGA";
|
||||
case DispatchKey::Vulkan:
|
||||
return "Vulkan";
|
||||
case DispatchKey::Metal:
|
||||
return "Metal";
|
||||
case DispatchKey::Quantized:
|
||||
return "Quantized";
|
||||
case DispatchKey::CustomRNGKeyId:
|
||||
return "CustomRNGKeyId";
|
||||
case DispatchKey::MkldnnCPU:
|
||||
return "MkldnnCPU";
|
||||
case DispatchKey::Sparse:
|
||||
return "Sparse";
|
||||
case DispatchKey::SparseCsr:
|
||||
return "SparseCsr";
|
||||
case DispatchKey::NestedTensor:
|
||||
return "NestedTensor";
|
||||
case DispatchKey::BackendSelect:
|
||||
return "BackendSelect";
|
||||
case DispatchKey::Python:
|
||||
return "Python";
|
||||
case DispatchKey::Fake:
|
||||
return "Fake";
|
||||
case DispatchKey::FuncTorchDynamicLayerBackMode:
|
||||
return "FuncTorchDynamicLayerBackMode";
|
||||
case DispatchKey::Functionalize:
|
||||
return "Functionalize";
|
||||
case DispatchKey::Named:
|
||||
return "Named";
|
||||
case DispatchKey::Conjugate:
|
||||
return "Conjugate";
|
||||
case DispatchKey::Negative:
|
||||
return "Negative";
|
||||
case DispatchKey::ZeroTensor:
|
||||
return "ZeroTensor";
|
||||
case DispatchKey::ADInplaceOrView:
|
||||
return "ADInplaceOrView";
|
||||
case DispatchKey::AutogradOther:
|
||||
return "AutogradOther";
|
||||
case DispatchKey::AutogradFunctionality:
|
||||
return "AutogradFunctionality";
|
||||
case DispatchKey::AutogradNestedTensor:
|
||||
return "AutogradNestedTensor";
|
||||
case DispatchKey::Tracer:
|
||||
return "Tracer";
|
||||
case DispatchKey::AutocastCPU:
|
||||
return "AutocastCPU";
|
||||
case DispatchKey::AutocastMTIA:
|
||||
return "AutocastMTIA";
|
||||
case DispatchKey::AutocastMAIA:
|
||||
return "AutocastMAIA";
|
||||
case DispatchKey::AutocastXPU:
|
||||
return "AutocastXPU";
|
||||
case DispatchKey::AutocastIPU:
|
||||
return "AutocastIPU";
|
||||
case DispatchKey::AutocastHPU:
|
||||
return "AutocastHPU";
|
||||
case DispatchKey::AutocastXLA:
|
||||
return "AutocastXLA";
|
||||
case DispatchKey::AutocastMPS:
|
||||
return "AutocastMPS";
|
||||
case DispatchKey::AutocastCUDA:
|
||||
return "AutocastCUDA";
|
||||
case DispatchKey::AutocastPrivateUse1:
|
||||
return "AutocastPrivateUse1";
|
||||
case DispatchKey::FuncTorchBatched:
|
||||
return "FuncTorchBatched";
|
||||
case DispatchKey::BatchedNestedTensor:
|
||||
return "BatchedNestedTensor";
|
||||
case DispatchKey::FuncTorchVmapMode:
|
||||
return "FuncTorchVmapMode";
|
||||
case DispatchKey::Batched:
|
||||
return "Batched";
|
||||
case DispatchKey::VmapMode:
|
||||
return "VmapMode";
|
||||
case DispatchKey::FuncTorchGradWrapper:
|
||||
return "FuncTorchGradWrapper";
|
||||
case DispatchKey::DeferredInit:
|
||||
return "DeferredInit";
|
||||
case DispatchKey::PythonTLSSnapshot:
|
||||
return "PythonTLSSnapshot";
|
||||
case DispatchKey::FuncTorchDynamicLayerFrontMode:
|
||||
return "FuncTorchDynamicLayerFrontMode";
|
||||
case DispatchKey::TESTING_ONLY_GenericWrapper:
|
||||
return "TESTING_ONLY_GenericWrapper";
|
||||
case DispatchKey::TESTING_ONLY_GenericMode:
|
||||
return "TESTING_ONLY_GenericMode";
|
||||
case DispatchKey::PreDispatch:
|
||||
return "PreDispatch";
|
||||
case DispatchKey::PythonDispatcher:
|
||||
return "PythonDispatcher";
|
||||
case DispatchKey::Autograd:
|
||||
return "Autograd";
|
||||
case DispatchKey::CompositeImplicitAutograd:
|
||||
return "CompositeImplicitAutograd";
|
||||
case DispatchKey::FuncTorchBatchedDecomposition:
|
||||
return "FuncTorchBatchedDecomposition";
|
||||
case DispatchKey::CompositeImplicitAutogradNestedTensor:
|
||||
return "CompositeImplicitAutogradNestedTensor";
|
||||
case DispatchKey::CompositeExplicitAutograd:
|
||||
return "CompositeExplicitAutograd";
|
||||
case DispatchKey::CompositeExplicitAutogradNonFunctional:
|
||||
return "CompositeExplicitAutogradNonFunctional";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
inline const char* toString(BackendComponent t) {
|
||||
switch (t) {
|
||||
case BackendComponent::CPUBit:
|
||||
return "CPUBit";
|
||||
case BackendComponent::CUDABit:
|
||||
return "CUDABit";
|
||||
case BackendComponent::HIPBit:
|
||||
return "HIPBit";
|
||||
case BackendComponent::XLABit:
|
||||
return "XLABit";
|
||||
case BackendComponent::MPSBit:
|
||||
return "MPSBit";
|
||||
case BackendComponent::IPUBit:
|
||||
return "IPUBit";
|
||||
case BackendComponent::XPUBit:
|
||||
return "XPUBit";
|
||||
case BackendComponent::HPUBit:
|
||||
return "HPUBit";
|
||||
case BackendComponent::VEBit:
|
||||
return "VEBit";
|
||||
case BackendComponent::LazyBit:
|
||||
return "LazyBit";
|
||||
case BackendComponent::MTIABit:
|
||||
return "MTIABit";
|
||||
case BackendComponent::MAIABit:
|
||||
return "MAIABit";
|
||||
case BackendComponent::PrivateUse1Bit:
|
||||
return "PrivateUse1Bit";
|
||||
case BackendComponent::PrivateUse2Bit:
|
||||
return "PrivateUse2Bit";
|
||||
case BackendComponent::PrivateUse3Bit:
|
||||
return "PrivateUse3Bit";
|
||||
case BackendComponent::MetaBit:
|
||||
return "MetaBit";
|
||||
default:
|
||||
return "InvalidBit";
|
||||
}
|
||||
}
|
||||
|
||||
// operator<< implementations
|
||||
inline std::ostream& operator<<(std::ostream& str, DispatchKey rhs) {
|
||||
return str << toString(rhs);
|
||||
}
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& str, BackendComponent rhs) {
|
||||
return str << toString(rhs);
|
||||
}
|
||||
|
||||
// getAutogradKeyFromBackend implementation
|
||||
inline DispatchKey getAutogradKeyFromBackend(BackendComponent k) {
|
||||
switch (k) {
|
||||
case BackendComponent::CPUBit:
|
||||
return DispatchKey::AutogradCPU;
|
||||
case BackendComponent::CUDABit:
|
||||
return DispatchKey::AutogradCUDA;
|
||||
case BackendComponent::XPUBit:
|
||||
return DispatchKey::AutogradXPU;
|
||||
case BackendComponent::IPUBit:
|
||||
return DispatchKey::AutogradIPU;
|
||||
case BackendComponent::HPUBit:
|
||||
return DispatchKey::AutogradHPU;
|
||||
case BackendComponent::LazyBit:
|
||||
return DispatchKey::AutogradLazy;
|
||||
case BackendComponent::MetaBit:
|
||||
return DispatchKey::AutogradMeta;
|
||||
case BackendComponent::MPSBit:
|
||||
return DispatchKey::AutogradMPS;
|
||||
case BackendComponent::PrivateUse1Bit:
|
||||
return DispatchKey::AutogradPrivateUse1;
|
||||
case BackendComponent::PrivateUse2Bit:
|
||||
return DispatchKey::AutogradPrivateUse2;
|
||||
case BackendComponent::PrivateUse3Bit:
|
||||
return DispatchKey::AutogradPrivateUse3;
|
||||
default:
|
||||
return DispatchKey::AutogradOther;
|
||||
}
|
||||
}
|
||||
|
||||
// parseDispatchKey implementation
|
||||
inline c10::DispatchKey parseDispatchKey(const std::string& k) {
|
||||
if (k == "Undefined") return DispatchKey::Undefined;
|
||||
if (k == "Dense") return DispatchKey::Dense;
|
||||
if (k == "FPGA") return DispatchKey::FPGA;
|
||||
if (k == "Vulkan") return DispatchKey::Vulkan;
|
||||
if (k == "Metal") return DispatchKey::Metal;
|
||||
if (k == "Quantized") return DispatchKey::Quantized;
|
||||
if (k == "Sparse") return DispatchKey::Sparse;
|
||||
if (k == "SparseCsr") return DispatchKey::SparseCsr;
|
||||
if (k == "NestedTensor") return DispatchKey::NestedTensor;
|
||||
if (k == "BackendSelect") return DispatchKey::BackendSelect;
|
||||
if (k == "Python") return DispatchKey::Python;
|
||||
if (k == "Fake") return DispatchKey::Fake;
|
||||
if (k == "Functionalize") return DispatchKey::Functionalize;
|
||||
if (k == "Named") return DispatchKey::Named;
|
||||
if (k == "Conjugate") return DispatchKey::Conjugate;
|
||||
if (k == "Negative") return DispatchKey::Negative;
|
||||
if (k == "ZeroTensor") return DispatchKey::ZeroTensor;
|
||||
if (k == "ADInplaceOrView") return DispatchKey::ADInplaceOrView;
|
||||
if (k == "AutogradOther") return DispatchKey::AutogradOther;
|
||||
if (k == "AutogradFunctionality") return DispatchKey::AutogradFunctionality;
|
||||
if (k == "AutogradNestedTensor") return DispatchKey::AutogradNestedTensor;
|
||||
if (k == "Tracer") return DispatchKey::Tracer;
|
||||
if (k == "AutocastCPU") return DispatchKey::AutocastCPU;
|
||||
if (k == "AutocastCUDA") return DispatchKey::AutocastCUDA;
|
||||
if (k == "Autograd") return DispatchKey::Autograd;
|
||||
if (k == "CompositeImplicitAutograd")
|
||||
return DispatchKey::CompositeImplicitAutograd;
|
||||
if (k == "CompositeExplicitAutograd")
|
||||
return DispatchKey::CompositeExplicitAutograd;
|
||||
return DispatchKey::Undefined;
|
||||
}
|
||||
|
||||
} // namespace c10
|
||||
|
||||
namespace torch {
|
||||
using c10::kAutograd; // NOLINT
|
||||
} // namespace torch
|
||||
|
||||
namespace std {
|
||||
template <>
|
||||
struct hash<c10::DispatchKey> {
|
||||
typedef size_t result_type;
|
||||
typedef c10::DispatchKey argument_type;
|
||||
|
||||
size_t operator()(c10::DispatchKey x) const { return static_cast<size_t>(x); }
|
||||
};
|
||||
} // namespace std
|
||||
@@ -0,0 +1,735 @@
|
||||
// Copyright (c) 2026 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
#include <c10/core/DispatchKey.h>
|
||||
#include <c10/macros/Macros.h>
|
||||
#include <c10/util/Exception.h>
|
||||
#include <array>
|
||||
#ifdef _MSC_VER
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <initializer_list>
|
||||
#include <iterator>
|
||||
#include <ostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
namespace c10 {
|
||||
|
||||
struct FunctionalityOffsetAndMask {
|
||||
FunctionalityOffsetAndMask() = default;
|
||||
FunctionalityOffsetAndMask(uint16_t offset, uint16_t mask)
|
||||
: offset(offset), mask(mask) {}
|
||||
uint16_t offset{};
|
||||
uint16_t mask{};
|
||||
};
|
||||
static_assert(
|
||||
c10::num_runtime_entries < 65536,
|
||||
"The dispatcher currently only supports up to 2^16 runtime entries");
|
||||
|
||||
std::array<FunctionalityOffsetAndMask, num_functionality_keys>
|
||||
initializeFunctionalityOffsetsAndMasks();
|
||||
|
||||
static const std::array<FunctionalityOffsetAndMask, num_functionality_keys>&
|
||||
offsetsAndMasks() {
|
||||
static auto offsets_and_masks_ = initializeFunctionalityOffsetsAndMasks();
|
||||
return offsets_and_masks_;
|
||||
}
|
||||
|
||||
class DispatchKeySet final {
|
||||
public:
|
||||
enum Full { FULL };
|
||||
enum FullAfter { FULL_AFTER };
|
||||
enum Raw { RAW };
|
||||
|
||||
constexpr DispatchKeySet() = default;
|
||||
|
||||
constexpr DispatchKeySet(Full /*unused*/)
|
||||
: repr_((1ULL << (num_backends + num_functionality_keys - 1)) - 1) {}
|
||||
|
||||
constexpr DispatchKeySet(FullAfter /*unused*/, DispatchKey t)
|
||||
: repr_((1ULL << (num_backends +
|
||||
static_cast<uint8_t>(toFunctionalityKey(t)) - 1)) -
|
||||
1) {
|
||||
*this = add(DispatchKey::PythonDispatcher);
|
||||
}
|
||||
|
||||
constexpr DispatchKeySet(Raw /*unused*/, uint64_t x) : repr_(x) {}
|
||||
|
||||
constexpr explicit DispatchKeySet(BackendComponent k) {
|
||||
if (k == BackendComponent::InvalidBit) {
|
||||
repr_ = 0;
|
||||
} else {
|
||||
repr_ = 1ULL << (static_cast<uint8_t>(k) - 1);
|
||||
}
|
||||
}
|
||||
|
||||
constexpr explicit DispatchKeySet(DispatchKey k) { // NOLINT
|
||||
if (k == DispatchKey::Undefined) {
|
||||
repr_ = 0;
|
||||
} else if (k <= DispatchKey::EndOfFunctionalityKeys) {
|
||||
uint64_t functionality_val =
|
||||
1ULL << (num_backends + static_cast<uint8_t>(k) - 1);
|
||||
repr_ = functionality_val;
|
||||
} else if (k <= DispatchKey::EndOfRuntimeBackendKeys) {
|
||||
auto functionality_k = toFunctionalityKey(k);
|
||||
uint64_t functionality_val =
|
||||
1ULL << (num_backends + static_cast<uint8_t>(functionality_k) - 1);
|
||||
|
||||
auto backend_k = toBackendComponent(k);
|
||||
uint64_t backend_val = backend_k == BackendComponent::InvalidBit
|
||||
? 0
|
||||
: 1ULL
|
||||
<< (static_cast<uint8_t>(backend_k) - 1);
|
||||
repr_ = functionality_val + backend_val;
|
||||
} else {
|
||||
repr_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr uint64_t keys_to_repr(std::initializer_list<DispatchKey> ks) {
|
||||
uint64_t repr = 0;
|
||||
for (auto k : ks) {
|
||||
repr |= DispatchKeySet(k).repr_;
|
||||
}
|
||||
return repr;
|
||||
}
|
||||
|
||||
constexpr uint64_t backend_bits_to_repr(
|
||||
std::initializer_list<BackendComponent> ks) {
|
||||
uint64_t repr = 0;
|
||||
for (auto k : ks) {
|
||||
repr |= DispatchKeySet(k).repr_;
|
||||
}
|
||||
return repr;
|
||||
}
|
||||
|
||||
explicit constexpr DispatchKeySet(std::initializer_list<DispatchKey> ks)
|
||||
: repr_(keys_to_repr(ks)) {}
|
||||
|
||||
explicit constexpr DispatchKeySet(std::initializer_list<BackendComponent> ks)
|
||||
: repr_(backend_bits_to_repr(ks)) {}
|
||||
|
||||
inline bool has(DispatchKey t) const {
|
||||
PD_CHECK(t != DispatchKey::Undefined);
|
||||
return has_all(DispatchKeySet(t));
|
||||
}
|
||||
constexpr bool has_backend(BackendComponent t) const {
|
||||
return has_all(DispatchKeySet(t));
|
||||
}
|
||||
|
||||
constexpr bool has_all(DispatchKeySet ks) const {
|
||||
return static_cast<bool>((repr_ & ks.repr_) == ks.repr_);
|
||||
}
|
||||
|
||||
inline bool has_any(DispatchKeySet ks) const {
|
||||
PD_CHECK(((ks.repr_ & full_backend_mask) == 0) ||
|
||||
((ks & DispatchKeySet({
|
||||
DispatchKey::Dense,
|
||||
DispatchKey::Quantized,
|
||||
DispatchKey::Sparse,
|
||||
DispatchKey::SparseCsr,
|
||||
DispatchKey::AutogradFunctionality,
|
||||
})
|
||||
.repr_) == 0));
|
||||
return static_cast<bool>((repr_ & ks.repr_) != 0);
|
||||
}
|
||||
bool isSupersetOf(DispatchKeySet ks) const {
|
||||
return (repr_ & ks.repr_) == ks.repr_;
|
||||
}
|
||||
constexpr DispatchKeySet operator|(DispatchKeySet other) const {
|
||||
return DispatchKeySet(repr_ | other.repr_);
|
||||
}
|
||||
constexpr DispatchKeySet operator&(DispatchKeySet other) const {
|
||||
return DispatchKeySet(repr_ & other.repr_);
|
||||
}
|
||||
constexpr DispatchKeySet operator-(DispatchKeySet other) const {
|
||||
return DispatchKeySet(repr_ & (full_backend_mask | ~other.repr_));
|
||||
}
|
||||
|
||||
constexpr DispatchKeySet operator^(DispatchKeySet other) const {
|
||||
return DispatchKeySet(repr_ ^ other.repr_);
|
||||
}
|
||||
bool operator==(DispatchKeySet other) const { return repr_ == other.repr_; }
|
||||
bool operator!=(DispatchKeySet other) const { return repr_ != other.repr_; }
|
||||
[[nodiscard]] constexpr DispatchKeySet add(DispatchKey t) const {
|
||||
return *this | DispatchKeySet(t);
|
||||
}
|
||||
[[nodiscard]] constexpr DispatchKeySet add(DispatchKeySet ks) const {
|
||||
return *this | ks;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr DispatchKeySet remove(DispatchKey t) const {
|
||||
return DispatchKeySet(repr_ &
|
||||
~(DispatchKeySet(t).repr_ & ~full_backend_mask));
|
||||
}
|
||||
constexpr DispatchKeySet remove_backend(BackendComponent b) const {
|
||||
return DispatchKeySet(repr_ & ~(DispatchKeySet(b).repr_));
|
||||
}
|
||||
bool empty() const { return repr_ == 0; }
|
||||
uint64_t raw_repr() const { return repr_; }
|
||||
|
||||
static DispatchKeySet from_raw_repr(uint64_t x) {
|
||||
return DispatchKeySet(RAW, x);
|
||||
}
|
||||
|
||||
DispatchKey highestFunctionalityKey() const {
|
||||
auto functionality_idx = indexOfHighestBit();
|
||||
if (functionality_idx < num_backends) return DispatchKey::Undefined;
|
||||
return static_cast<DispatchKey>(functionality_idx - num_backends);
|
||||
}
|
||||
|
||||
BackendComponent highestBackendKey() const {
|
||||
auto backend_idx =
|
||||
DispatchKeySet(repr_ & full_backend_mask).indexOfHighestBit();
|
||||
if (backend_idx == 0) return BackendComponent::InvalidBit;
|
||||
return static_cast<BackendComponent>(backend_idx);
|
||||
}
|
||||
|
||||
DispatchKey highestPriorityTypeId() const {
|
||||
auto functionality_k = highestFunctionalityKey();
|
||||
if (isPerBackendFunctionalityKey(functionality_k)) {
|
||||
return toRuntimePerBackendFunctionalityKey(functionality_k,
|
||||
highestBackendKey());
|
||||
}
|
||||
return functionality_k;
|
||||
}
|
||||
|
||||
uint8_t indexOfHighestBit() const {
|
||||
// Use compiler built-in instead of llvm::countLeadingZeros.
|
||||
if (repr_ == 0) return 0;
|
||||
#if defined(_MSC_VER)
|
||||
unsigned long index; // NOLINT(runtime/int)
|
||||
_BitScanReverse64(&index, repr_);
|
||||
return static_cast<uint8_t>(index + 1);
|
||||
#else
|
||||
return static_cast<uint8_t>(64 - __builtin_clzll(repr_));
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(C10_MOBILE_TRIM_DISPATCH_KEYS)
|
||||
/**
|
||||
* The method below maps the dispatch key in the enum DispatchKey to an
|
||||
* integer index in the dispatchTable_ array in OperatorEntry. The array
|
||||
* is trimmed for mobile to reduce peak memory usage since it's
|
||||
* unnecessary to reserve additional space for dispatch keys that will
|
||||
* never be used on mobile.
|
||||
*/
|
||||
int getDispatchTableIndexForDispatchKeySet() const {
|
||||
auto dk = highestPriorityTypeId();
|
||||
switch (dk) {
|
||||
case DispatchKey::Undefined:
|
||||
return 0;
|
||||
case DispatchKey::CPU:
|
||||
return 1;
|
||||
case DispatchKey::QuantizedCPU:
|
||||
return 2;
|
||||
case DispatchKey::SparseCPU:
|
||||
return 3;
|
||||
case DispatchKey::BackendSelect:
|
||||
return 4;
|
||||
case DispatchKey::ADInplaceOrView:
|
||||
return 5;
|
||||
case DispatchKey::AutogradOther:
|
||||
return 6;
|
||||
case DispatchKey::AutogradCPU:
|
||||
return 7;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#else
|
||||
int getDispatchTableIndexForDispatchKeySet() const {
|
||||
auto functionality_idx =
|
||||
DispatchKeySet(repr_ >> num_backends).indexOfHighestBit();
|
||||
auto offset_and_mask = offsetsAndMasks()[functionality_idx];
|
||||
auto backend_idx =
|
||||
DispatchKeySet((repr_ & offset_and_mask.mask) >> 1).indexOfHighestBit();
|
||||
return offset_and_mask.offset + backend_idx;
|
||||
}
|
||||
#endif
|
||||
|
||||
uint64_t getBackendIndex() const {
|
||||
return DispatchKeySet((repr_ & full_backend_mask) >> 1).indexOfHighestBit();
|
||||
}
|
||||
|
||||
private:
|
||||
constexpr DispatchKeySet(uint64_t repr) : repr_(repr) {}
|
||||
uint64_t repr_ = 0;
|
||||
|
||||
public:
|
||||
class iterator {
|
||||
public:
|
||||
using self_type = iterator;
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
using value_type = DispatchKey;
|
||||
using difference_type = ptrdiff_t;
|
||||
using reference = value_type&;
|
||||
using pointer = value_type*;
|
||||
static const uint8_t end_iter_mask_val =
|
||||
num_backends + num_functionality_keys;
|
||||
static const uint8_t end_iter_key_val = num_functionality_keys;
|
||||
|
||||
explicit iterator(const uint64_t* data_ptr,
|
||||
uint8_t next_functionality = num_backends,
|
||||
uint8_t next_backend = 0)
|
||||
: data_ptr_(data_ptr),
|
||||
next_functionality_(next_functionality),
|
||||
next_backend_(next_backend),
|
||||
current_dispatchkey_idx_(end_iter_key_val),
|
||||
current_backendcomponent_idx_(end_iter_key_val) {
|
||||
TORCH_INTERNAL_ASSERT(next_functionality_ >= num_backends,
|
||||
"num_backends=",
|
||||
static_cast<uint32_t>(num_backends),
|
||||
"next_functionality_=",
|
||||
static_cast<uint32_t>(next_functionality_));
|
||||
++(*this);
|
||||
}
|
||||
|
||||
self_type& operator++() {
|
||||
while (next_functionality_ < end_iter_mask_val) {
|
||||
if (*data_ptr_ & (1ULL << next_functionality_)) {
|
||||
current_dispatchkey_idx_ =
|
||||
static_cast<uint8_t>(next_functionality_ - num_backends);
|
||||
if (isPerBackendFunctionalityKey(
|
||||
static_cast<DispatchKey>(current_dispatchkey_idx_))) {
|
||||
while (next_backend_ < num_backends) {
|
||||
if (*data_ptr_ & (1ULL << next_backend_)) {
|
||||
// BackendComponent is 1-based (InvalidBit=0, CPUBit=1, ...),
|
||||
// so bit position next_backend_ maps to enum value
|
||||
// next_backend_+1.
|
||||
current_backendcomponent_idx_ = next_backend_ + 1;
|
||||
++next_backend_;
|
||||
return *this;
|
||||
}
|
||||
++next_backend_;
|
||||
}
|
||||
// No backend bits set for this functionality key; advance.
|
||||
next_backend_ = 0;
|
||||
current_backendcomponent_idx_ = end_iter_key_val;
|
||||
++next_functionality_;
|
||||
continue;
|
||||
}
|
||||
++next_functionality_;
|
||||
return *this;
|
||||
}
|
||||
++next_functionality_;
|
||||
}
|
||||
current_dispatchkey_idx_ = end_iter_key_val;
|
||||
current_backendcomponent_idx_ = end_iter_key_val;
|
||||
return *this;
|
||||
}
|
||||
|
||||
self_type operator++(int) {
|
||||
self_type previous_iterator = *this;
|
||||
++(*this);
|
||||
return previous_iterator;
|
||||
}
|
||||
|
||||
bool operator==(const self_type& rhs) const {
|
||||
return next_functionality_ == rhs.next_functionality_ &&
|
||||
current_dispatchkey_idx_ == rhs.current_dispatchkey_idx_ &&
|
||||
next_backend_ == rhs.next_backend_ &&
|
||||
current_backendcomponent_idx_ == rhs.current_backendcomponent_idx_;
|
||||
}
|
||||
bool operator!=(const self_type& rhs) const {
|
||||
return next_functionality_ != rhs.next_functionality_ ||
|
||||
current_dispatchkey_idx_ != rhs.current_dispatchkey_idx_ ||
|
||||
next_backend_ != rhs.next_backend_ ||
|
||||
current_backendcomponent_idx_ != rhs.current_backendcomponent_idx_;
|
||||
}
|
||||
DispatchKey operator*() const {
|
||||
auto functionality_key =
|
||||
static_cast<DispatchKey>(current_dispatchkey_idx_);
|
||||
if (isPerBackendFunctionalityKey(functionality_key)) {
|
||||
auto next_key = toRuntimePerBackendFunctionalityKey(
|
||||
functionality_key,
|
||||
static_cast<BackendComponent>(current_backendcomponent_idx_));
|
||||
TORCH_INTERNAL_ASSERT(
|
||||
toBackendComponent(next_key) ==
|
||||
static_cast<BackendComponent>(current_backendcomponent_idx_),
|
||||
"Tried to map functionality key ",
|
||||
toString(functionality_key),
|
||||
" and backend bit ",
|
||||
toString(
|
||||
static_cast<BackendComponent>(current_backendcomponent_idx_)),
|
||||
" to a runtime key, but ended up with ",
|
||||
toString(next_key),
|
||||
". This can happen if the order of the backend dispatch keys in "
|
||||
"DispatchKey.h isn't consistent.",
|
||||
" Please double check that enum for inconsistencies.");
|
||||
return next_key;
|
||||
} else {
|
||||
return functionality_key;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
const uint64_t* data_ptr_;
|
||||
uint8_t next_functionality_;
|
||||
uint8_t next_backend_;
|
||||
uint8_t current_dispatchkey_idx_;
|
||||
uint8_t current_backendcomponent_idx_;
|
||||
};
|
||||
|
||||
public:
|
||||
iterator begin() const { return iterator(&repr_); }
|
||||
|
||||
iterator end() const { return iterator(&repr_, iterator::end_iter_mask_val); }
|
||||
};
|
||||
|
||||
std::string toString(DispatchKeySet /*ts*/);
|
||||
std::ostream& operator<<(std::ostream& /*os*/, DispatchKeySet /*ts*/);
|
||||
|
||||
inline int getDispatchTableIndexForDispatchKey(DispatchKey k) {
|
||||
return DispatchKeySet(k).getDispatchTableIndexForDispatchKeySet();
|
||||
}
|
||||
|
||||
constexpr DispatchKeySet autograd_dispatch_keyset = DispatchKeySet({
|
||||
DispatchKey::AutogradFunctionality,
|
||||
DispatchKey::AutogradOther,
|
||||
DispatchKey::AutogradNestedTensor,
|
||||
});
|
||||
|
||||
constexpr DispatchKeySet autocast_dispatch_keyset = DispatchKeySet({
|
||||
DispatchKey::AutocastCPU,
|
||||
DispatchKey::AutocastMPS,
|
||||
DispatchKey::AutocastCUDA,
|
||||
DispatchKey::AutocastXPU,
|
||||
DispatchKey::AutocastIPU,
|
||||
DispatchKey::AutocastHPU,
|
||||
DispatchKey::AutocastXLA,
|
||||
DispatchKey::AutocastPrivateUse1,
|
||||
DispatchKey::AutocastMTIA,
|
||||
DispatchKey::AutocastMAIA,
|
||||
});
|
||||
|
||||
constexpr DispatchKeySet default_included_set = DispatchKeySet({
|
||||
DispatchKey::BackendSelect,
|
||||
DispatchKey::ADInplaceOrView,
|
||||
});
|
||||
|
||||
constexpr DispatchKeySet default_excluded_set = DispatchKeySet({
|
||||
DispatchKey::AutocastCPU,
|
||||
DispatchKey::AutocastMPS,
|
||||
DispatchKey::AutocastCUDA,
|
||||
DispatchKey::AutocastXPU,
|
||||
DispatchKey::AutocastIPU,
|
||||
DispatchKey::AutocastHPU,
|
||||
DispatchKey::AutocastXLA,
|
||||
DispatchKey::AutocastPrivateUse1,
|
||||
DispatchKey::AutocastMTIA,
|
||||
DispatchKey::AutocastMAIA,
|
||||
});
|
||||
|
||||
constexpr DispatchKeySet autograd_dispatch_keyset_with_ADInplaceOrView =
|
||||
autograd_dispatch_keyset | DispatchKeySet(DispatchKey::ADInplaceOrView);
|
||||
|
||||
constexpr DispatchKeySet python_ks = DispatchKeySet({
|
||||
DispatchKey::Python,
|
||||
DispatchKey::PythonTLSSnapshot,
|
||||
});
|
||||
|
||||
constexpr DispatchKeySet sparse_ks = DispatchKeySet(DispatchKey::Sparse);
|
||||
|
||||
constexpr DispatchKeySet sparse_csr_ks = DispatchKeySet(DispatchKey::SparseCsr);
|
||||
|
||||
constexpr DispatchKeySet mkldnn_ks = DispatchKeySet(DispatchKey::MkldnnCPU);
|
||||
|
||||
constexpr DispatchKeySet autogradother_backends =
|
||||
DispatchKeySet({DispatchKey::FPGA,
|
||||
DispatchKey::Vulkan,
|
||||
DispatchKey::Metal,
|
||||
DispatchKey::CustomRNGKeyId,
|
||||
DispatchKey::MkldnnCPU,
|
||||
DispatchKey::Sparse,
|
||||
DispatchKey::SparseCsr,
|
||||
DispatchKey::Quantized}) |
|
||||
DispatchKeySet(DispatchKeySet::RAW, full_backend_mask);
|
||||
|
||||
constexpr DispatchKeySet after_autograd_keyset =
|
||||
DispatchKeySet(DispatchKeySet::FULL_AFTER, c10::DispatchKey::AutogradOther);
|
||||
|
||||
constexpr DispatchKeySet after_ADInplaceOrView_keyset = DispatchKeySet(
|
||||
DispatchKeySet::FULL_AFTER, c10::DispatchKey::ADInplaceOrView);
|
||||
|
||||
constexpr DispatchKeySet after_func_keyset =
|
||||
DispatchKeySet(DispatchKeySet::FULL_AFTER, c10::DispatchKey::Functionalize)
|
||||
.remove(c10::DispatchKey::ADInplaceOrView);
|
||||
|
||||
constexpr DispatchKeySet backend_bitset_mask =
|
||||
DispatchKeySet(DispatchKeySet::RAW, (1ULL << num_backends) - 1);
|
||||
|
||||
constexpr auto inplace_or_view_ks =
|
||||
DispatchKeySet(DispatchKey::ADInplaceOrView);
|
||||
constexpr auto autograd_cpu_ks = DispatchKeySet(DispatchKey::AutogradCPU);
|
||||
constexpr auto autograd_ipu_ks = DispatchKeySet(DispatchKey::AutogradIPU);
|
||||
constexpr auto autograd_mtia_ks = DispatchKeySet(DispatchKey::AutogradMTIA);
|
||||
constexpr auto autograd_maia_ks = DispatchKeySet(DispatchKey::AutogradMAIA);
|
||||
constexpr auto autograd_xpu_ks = DispatchKeySet(DispatchKey::AutogradXPU);
|
||||
constexpr auto autograd_cuda_ks = DispatchKeySet(DispatchKey::AutogradCUDA);
|
||||
constexpr auto autograd_xla_ks = DispatchKeySet(DispatchKey::AutogradXLA);
|
||||
constexpr auto autograd_lazy_ks = DispatchKeySet(DispatchKey::AutogradLazy);
|
||||
constexpr auto autograd_meta_ks = DispatchKeySet(DispatchKey::AutogradMeta);
|
||||
constexpr auto autograd_mps_ks = DispatchKeySet(DispatchKey::AutogradMPS);
|
||||
constexpr auto autograd_hpu_ks = DispatchKeySet(DispatchKey::AutogradHPU);
|
||||
constexpr auto autograd_privateuse1_ks =
|
||||
DispatchKeySet(DispatchKey::AutogradPrivateUse1);
|
||||
constexpr auto autograd_privateuse2_ks =
|
||||
DispatchKeySet(DispatchKey::AutogradPrivateUse2);
|
||||
constexpr auto autograd_privateuse3_ks =
|
||||
DispatchKeySet(DispatchKey::AutogradPrivateUse3);
|
||||
constexpr auto autograd_other_ks = DispatchKeySet(DispatchKey::AutogradOther);
|
||||
constexpr auto autograd_nested =
|
||||
DispatchKeySet(DispatchKey::AutogradNestedTensor);
|
||||
constexpr auto functorch_transforms_ks =
|
||||
DispatchKeySet({DispatchKey::FuncTorchBatched,
|
||||
DispatchKey::FuncTorchVmapMode,
|
||||
DispatchKey::Batched,
|
||||
DispatchKey::VmapMode,
|
||||
DispatchKey::FuncTorchGradWrapper});
|
||||
|
||||
constexpr auto functorch_batched_ks =
|
||||
DispatchKeySet({DispatchKey::FuncTorchBatched});
|
||||
|
||||
constexpr DispatchKeySet backend_functionality_keys =
|
||||
DispatchKeySet({
|
||||
DispatchKey::Dense,
|
||||
DispatchKey::Quantized,
|
||||
DispatchKey::Sparse,
|
||||
DispatchKey::SparseCsr,
|
||||
}) |
|
||||
DispatchKeySet(DispatchKeySet::RAW, full_backend_mask);
|
||||
|
||||
struct OpTableOffsetAndMask {
|
||||
uint16_t offset;
|
||||
uint16_t backend_mask;
|
||||
};
|
||||
|
||||
static_assert(num_backends <= 16,
|
||||
"Right now we expect the number of backends not to exceed 16. In "
|
||||
"the (unlikely) event"
|
||||
" that this changes, the size of "
|
||||
"OpTableOffsetAndMask::backend_mask needs to be increased too.");
|
||||
|
||||
bool isBackendDispatchKey(DispatchKey t);
|
||||
|
||||
DispatchKeySet getRuntimeDispatchKeySet(DispatchKey t);
|
||||
|
||||
bool runtimeDispatchKeySetHas(DispatchKey t, DispatchKey k);
|
||||
|
||||
DispatchKeySet getBackendKeySetFromAutograd(DispatchKey t);
|
||||
|
||||
inline DispatchKeySet getAutogradRelatedKeySetFromBackend(BackendComponent t) {
|
||||
switch (t) {
|
||||
case BackendComponent::CPUBit:
|
||||
return inplace_or_view_ks | autograd_cpu_ks;
|
||||
case BackendComponent::IPUBit:
|
||||
return inplace_or_view_ks | autograd_ipu_ks;
|
||||
case BackendComponent::MTIABit:
|
||||
return inplace_or_view_ks | autograd_mtia_ks;
|
||||
case BackendComponent::MAIABit:
|
||||
return inplace_or_view_ks | autograd_maia_ks;
|
||||
case BackendComponent::XPUBit:
|
||||
return inplace_or_view_ks | autograd_xpu_ks;
|
||||
case BackendComponent::CUDABit:
|
||||
return inplace_or_view_ks | autograd_cuda_ks;
|
||||
case BackendComponent::XLABit:
|
||||
return inplace_or_view_ks | autograd_xla_ks;
|
||||
case BackendComponent::LazyBit:
|
||||
return inplace_or_view_ks | autograd_lazy_ks;
|
||||
case BackendComponent::MetaBit:
|
||||
return inplace_or_view_ks | autograd_meta_ks;
|
||||
case BackendComponent::MPSBit:
|
||||
return inplace_or_view_ks | autograd_mps_ks;
|
||||
case BackendComponent::HPUBit:
|
||||
return inplace_or_view_ks | autograd_hpu_ks;
|
||||
case BackendComponent::PrivateUse1Bit:
|
||||
return inplace_or_view_ks | autograd_privateuse1_ks;
|
||||
case BackendComponent::PrivateUse2Bit:
|
||||
return inplace_or_view_ks | autograd_privateuse2_ks;
|
||||
case BackendComponent::PrivateUse3Bit:
|
||||
return inplace_or_view_ks | autograd_privateuse3_ks;
|
||||
default:
|
||||
return inplace_or_view_ks | autograd_other_ks;
|
||||
}
|
||||
}
|
||||
|
||||
inline DispatchKeySet getAutocastRelatedKeySetFromBackend(BackendComponent t) {
|
||||
constexpr auto autocast_cpu_ks = DispatchKeySet(DispatchKey::AutocastCPU);
|
||||
constexpr auto autocast_mtia_ks = DispatchKeySet(DispatchKey::AutocastMTIA);
|
||||
constexpr auto autocast_maia_ks = DispatchKeySet(DispatchKey::AutocastMAIA);
|
||||
constexpr auto autocast_xpu_ks = DispatchKeySet(DispatchKey::AutocastXPU);
|
||||
constexpr auto autocast_ipu_ks = DispatchKeySet(DispatchKey::AutocastIPU);
|
||||
constexpr auto autocast_hpu_ks = DispatchKeySet(DispatchKey::AutocastHPU);
|
||||
constexpr auto autocast_cuda_ks = DispatchKeySet(DispatchKey::AutocastCUDA);
|
||||
constexpr auto autocast_xla_ks = DispatchKeySet(DispatchKey::AutocastXLA);
|
||||
constexpr auto autocast_privateuse1_ks =
|
||||
DispatchKeySet(DispatchKey::AutocastPrivateUse1);
|
||||
constexpr auto autocast_mps_ks = DispatchKeySet(DispatchKey::AutocastMPS);
|
||||
switch (t) {
|
||||
case BackendComponent::CPUBit:
|
||||
return autocast_cpu_ks;
|
||||
case BackendComponent::MTIABit:
|
||||
return autocast_mtia_ks;
|
||||
case BackendComponent::MAIABit:
|
||||
return autocast_maia_ks;
|
||||
case BackendComponent::XPUBit:
|
||||
return autocast_xpu_ks;
|
||||
case BackendComponent::IPUBit:
|
||||
return autocast_ipu_ks;
|
||||
case BackendComponent::HPUBit:
|
||||
return autocast_hpu_ks;
|
||||
case BackendComponent::CUDABit:
|
||||
return autocast_cuda_ks;
|
||||
case BackendComponent::XLABit:
|
||||
return autocast_xla_ks;
|
||||
case BackendComponent::PrivateUse1Bit:
|
||||
return autocast_privateuse1_ks;
|
||||
case BackendComponent::MPSBit:
|
||||
return autocast_mps_ks;
|
||||
default:
|
||||
return DispatchKeySet();
|
||||
}
|
||||
}
|
||||
|
||||
inline DispatchKey highestPriorityBackendTypeId(DispatchKeySet ks) {
|
||||
return (ks & backend_functionality_keys).highestPriorityTypeId();
|
||||
}
|
||||
|
||||
bool isIncludedInAlias(DispatchKey k, DispatchKey alias);
|
||||
|
||||
inline DispatchKey legacyExtractDispatchKey(DispatchKeySet s) {
|
||||
return (s - autograd_dispatch_keyset_with_ADInplaceOrView -
|
||||
autocast_dispatch_keyset -
|
||||
DispatchKeySet({DispatchKey::Functionalize,
|
||||
DispatchKey::PythonTLSSnapshot,
|
||||
DispatchKey::FuncTorchGradWrapper,
|
||||
DispatchKey::FuncTorchVmapMode,
|
||||
DispatchKey::FuncTorchBatched,
|
||||
DispatchKey::Python}))
|
||||
.highestPriorityTypeId();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
using is_not_DispatchKeySet = std::negation<std::is_same<DispatchKeySet, T>>;
|
||||
|
||||
// NOTE: remove_DispatchKeySet_arg_from_func is omitted because the
|
||||
// c10::guts type-list utilities are not yet ported. The template is
|
||||
// only used by the PyTorch dispatcher internals, which are not part
|
||||
// of this compatibility layer.
|
||||
|
||||
inline std::string toString(DispatchKeySet ts) {
|
||||
std::ostringstream oss;
|
||||
oss << ts;
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& os, DispatchKeySet ts) {
|
||||
os << "DispatchKeySet(";
|
||||
bool first = true;
|
||||
for (auto k : ts) {
|
||||
if (!first) os << ", ";
|
||||
os << toString(k);
|
||||
first = false;
|
||||
}
|
||||
os << ")";
|
||||
return os;
|
||||
}
|
||||
|
||||
inline bool isBackendDispatchKey(DispatchKey t) {
|
||||
return t >= DispatchKey::StartOfDenseBackends &&
|
||||
t <= DispatchKey::EndOfRuntimeBackendKeys;
|
||||
}
|
||||
|
||||
inline DispatchKeySet getRuntimeDispatchKeySet(DispatchKey t) {
|
||||
if (isPerBackendFunctionalityKey(t)) {
|
||||
DispatchKeySet result;
|
||||
for (uint8_t backend = 1; backend <= num_backends; ++backend) {
|
||||
result = result.add(toRuntimePerBackendFunctionalityKey(
|
||||
t, static_cast<BackendComponent>(backend)));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return DispatchKeySet(t);
|
||||
}
|
||||
|
||||
inline bool runtimeDispatchKeySetHas(DispatchKey t, DispatchKey k) {
|
||||
return getRuntimeDispatchKeySet(t).has(k);
|
||||
}
|
||||
|
||||
inline DispatchKeySet getBackendKeySetFromAutograd(DispatchKey t) {
|
||||
if (t == DispatchKey::AutogradCPU) {
|
||||
return DispatchKeySet(DispatchKey::CPU);
|
||||
} else if (t == DispatchKey::AutogradCUDA) {
|
||||
return DispatchKeySet(DispatchKey::CUDA);
|
||||
} else if (t == DispatchKey::AutogradXPU) {
|
||||
return DispatchKeySet(DispatchKey::XPU);
|
||||
} else if (t == DispatchKey::AutogradIPU) {
|
||||
return DispatchKeySet(DispatchKey::IPU);
|
||||
} else if (t == DispatchKey::AutogradHPU) {
|
||||
return DispatchKeySet(DispatchKey::HPU);
|
||||
} else if (t == DispatchKey::AutogradLazy) {
|
||||
return DispatchKeySet(DispatchKey::Lazy);
|
||||
} else if (t == DispatchKey::AutogradMeta) {
|
||||
return DispatchKeySet(DispatchKey::Meta);
|
||||
} else if (t == DispatchKey::AutogradMPS) {
|
||||
return DispatchKeySet(DispatchKey::MPS);
|
||||
} else if (t == DispatchKey::AutogradPrivateUse1) {
|
||||
return DispatchKeySet(DispatchKey::PrivateUse1);
|
||||
} else if (t == DispatchKey::AutogradPrivateUse2) {
|
||||
return DispatchKeySet(DispatchKey::PrivateUse2);
|
||||
} else if (t == DispatchKey::AutogradPrivateUse3) {
|
||||
return DispatchKeySet(DispatchKey::PrivateUse3);
|
||||
} else if (t == DispatchKey::AutogradNestedTensor) {
|
||||
return DispatchKeySet(DispatchKey::NestedTensor);
|
||||
} else if (t == DispatchKey::AutogradOther) {
|
||||
return autogradother_backends;
|
||||
}
|
||||
return DispatchKeySet();
|
||||
}
|
||||
|
||||
inline bool isIncludedInAlias(DispatchKey k, DispatchKey alias) {
|
||||
if (alias == DispatchKey::Autograd) {
|
||||
return autograd_dispatch_keyset.has(k);
|
||||
} else if (alias == DispatchKey::CompositeImplicitAutograd) {
|
||||
return true;
|
||||
} else if (alias == DispatchKey::CompositeExplicitAutograd) {
|
||||
return k != DispatchKey::Autograd && !autograd_dispatch_keyset.has(k);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline std::array<FunctionalityOffsetAndMask, num_functionality_keys>
|
||||
initializeFunctionalityOffsetsAndMasks() {
|
||||
std::array<FunctionalityOffsetAndMask, num_functionality_keys> result{};
|
||||
uint16_t offset = 0;
|
||||
for (uint8_t i = 0; i < num_functionality_keys; ++i) {
|
||||
DispatchKey key = static_cast<DispatchKey>(i);
|
||||
if (isPerBackendFunctionalityKey(key)) {
|
||||
result[i] = FunctionalityOffsetAndMask(offset, full_backend_mask);
|
||||
offset += num_backends;
|
||||
} else {
|
||||
result[i] = FunctionalityOffsetAndMask(offset, 0);
|
||||
offset += 1;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace c10
|
||||
@@ -0,0 +1,339 @@
|
||||
// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <c10/core/Device.h>
|
||||
#include <c10/core/DeviceType.h>
|
||||
#include <c10/core/Stream.h>
|
||||
|
||||
#include <utility>
|
||||
|
||||
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
|
||||
#include <c10/cuda/CUDAGuard.h>
|
||||
#include <c10/cuda/CUDAStream.h>
|
||||
#endif
|
||||
|
||||
namespace c10 {
|
||||
|
||||
enum class EventFlag { PYTORCH_DEFAULT, BACKEND_DEFAULT, INVALID };
|
||||
|
||||
struct Event final {
|
||||
public:
|
||||
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
|
||||
#ifdef PADDLE_WITH_HIP
|
||||
using BackendEvent = hipEvent_t;
|
||||
using BackendStream = hipStream_t;
|
||||
#else
|
||||
using BackendEvent = cudaEvent_t;
|
||||
using BackendStream = cudaStream_t;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
Event() = delete;
|
||||
Event(const DeviceType device_type,
|
||||
const EventFlag flag = EventFlag::PYTORCH_DEFAULT)
|
||||
: device_type_(device_type), flag_(flag) {}
|
||||
|
||||
Event(const Event&) = delete;
|
||||
Event& operator=(const Event&) = delete;
|
||||
|
||||
Event(Event&& other) noexcept { MoveFrom(std::move(other)); }
|
||||
Event& operator=(Event&& other) noexcept {
|
||||
if (this != &other) {
|
||||
DestroyBackendEvent();
|
||||
MoveFrom(std::move(other));
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
~Event() { DestroyBackendEvent(); }
|
||||
|
||||
Device device() const noexcept { return Device(device_type_, device_index_); }
|
||||
DeviceType device_type() const noexcept { return device_type_; }
|
||||
DeviceIndex device_index() const noexcept { return device_index_; }
|
||||
EventFlag flag() const noexcept { return flag_; }
|
||||
bool was_marked_for_recording() const noexcept {
|
||||
return was_marked_for_recording_;
|
||||
}
|
||||
|
||||
void recordOnce(const Stream& stream) {
|
||||
if (!was_marked_for_recording_) {
|
||||
record(stream);
|
||||
}
|
||||
}
|
||||
|
||||
void record(const Stream& stream) {
|
||||
TORCH_CHECK(stream.device_type() == device_type_,
|
||||
"Event device type ",
|
||||
device_type_,
|
||||
" does not match recording stream's device type ",
|
||||
stream.device_type(),
|
||||
".");
|
||||
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
|
||||
if (device_type_ == DeviceType::CUDA) {
|
||||
RecordBackendEvent(static_cast<BackendStream>(stream.native_handle()),
|
||||
stream.device_index());
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
TORCH_CHECK(false, "Backend doesn't support events.");
|
||||
}
|
||||
|
||||
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
|
||||
void record(const c10::cuda::CUDAStream& stream) { record(stream.unwrap()); }
|
||||
#endif
|
||||
|
||||
void block(const Stream& stream) const {
|
||||
if (!was_marked_for_recording_) {
|
||||
return;
|
||||
}
|
||||
TORCH_CHECK(stream.device_type() == device_type_,
|
||||
"Event device type ",
|
||||
device_type_,
|
||||
" does not match blocking stream's device type ",
|
||||
stream.device_type(),
|
||||
".");
|
||||
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
|
||||
if (device_type_ == DeviceType::CUDA && backend_event_) {
|
||||
TORCH_CHECK(device_index_ == stream.device_index(),
|
||||
"Event device index ",
|
||||
static_cast<int>(device_index_),
|
||||
" does not match blocking stream's device index ",
|
||||
static_cast<int>(stream.device_index()),
|
||||
".");
|
||||
c10::cuda::CUDAGuard guard(device_index_);
|
||||
#ifdef PADDLE_WITH_HIP
|
||||
PADDLE_ENFORCE_GPU_SUCCESS(
|
||||
hipStreamWaitEvent(static_cast<BackendStream>(stream.native_handle()),
|
||||
backend_event_,
|
||||
0));
|
||||
#else
|
||||
C10_CUDA_CHECK(cudaStreamWaitEvent(
|
||||
static_cast<BackendStream>(stream.native_handle()),
|
||||
backend_event_,
|
||||
0));
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
TORCH_CHECK(false, "Backend doesn't support events.");
|
||||
}
|
||||
|
||||
bool query() const {
|
||||
if (!was_marked_for_recording_) {
|
||||
return true;
|
||||
}
|
||||
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
|
||||
if (device_type_ == DeviceType::CUDA && backend_event_) {
|
||||
#ifdef PADDLE_WITH_HIP
|
||||
const auto err = hipEventQuery(backend_event_);
|
||||
if (err == hipSuccess) {
|
||||
return true;
|
||||
}
|
||||
if (err != hipErrorNotReady) {
|
||||
PADDLE_ENFORCE_GPU_SUCCESS(err);
|
||||
} else {
|
||||
(void)hipGetLastError();
|
||||
}
|
||||
#else
|
||||
const auto err = cudaEventQuery(backend_event_);
|
||||
if (err == cudaSuccess) {
|
||||
return true;
|
||||
}
|
||||
if (err != cudaErrorNotReady) {
|
||||
C10_CUDA_CHECK(err);
|
||||
} else {
|
||||
(void)cudaGetLastError();
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
TORCH_CHECK(false, "Backend doesn't support events.");
|
||||
return true;
|
||||
}
|
||||
|
||||
double elapsedTime(const Event& event) const {
|
||||
TORCH_CHECK(event.device_type() == device_type_,
|
||||
"Event device type ",
|
||||
device_type_,
|
||||
" does not match other's device type ",
|
||||
event.device_type(),
|
||||
".");
|
||||
TORCH_CHECK(
|
||||
flag_ == EventFlag::BACKEND_DEFAULT &&
|
||||
event.flag_ == EventFlag::BACKEND_DEFAULT,
|
||||
"Both events must be created with argument 'enable_timing=True'.");
|
||||
TORCH_CHECK(
|
||||
was_marked_for_recording_ && event.was_marked_for_recording_,
|
||||
"Both events must be recorded before calculating elapsed time.");
|
||||
TORCH_CHECK(
|
||||
query() && event.query(),
|
||||
"Both events must be completed before calculating elapsed time.");
|
||||
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
|
||||
if (device_type_ == DeviceType::CUDA && backend_event_ &&
|
||||
event.backend_event_) {
|
||||
TORCH_CHECK(device_index_ == event.device_index_,
|
||||
"Event device index ",
|
||||
static_cast<int>(device_index_),
|
||||
" does not match other's device index ",
|
||||
static_cast<int>(event.device_index_),
|
||||
".");
|
||||
c10::cuda::CUDAGuard guard(device_index_);
|
||||
float time_ms = 0.0f;
|
||||
#ifdef PADDLE_WITH_HIP
|
||||
PADDLE_ENFORCE_GPU_SUCCESS(
|
||||
hipEventElapsedTime(&time_ms, backend_event_, event.backend_event_));
|
||||
#else
|
||||
C10_CUDA_CHECK(
|
||||
cudaEventElapsedTime(&time_ms, backend_event_, event.backend_event_));
|
||||
#endif
|
||||
return static_cast<double>(time_ms);
|
||||
}
|
||||
#endif
|
||||
TORCH_CHECK(false, "Backend doesn't support event elapsedTime.");
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
void* eventId() const {
|
||||
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
|
||||
return backend_event_;
|
||||
#else
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
void synchronize() const {
|
||||
if (!was_marked_for_recording_) {
|
||||
return;
|
||||
}
|
||||
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
|
||||
if (device_type_ == DeviceType::CUDA && backend_event_) {
|
||||
#ifdef PADDLE_WITH_HIP
|
||||
PADDLE_ENFORCE_GPU_SUCCESS(hipEventSynchronize(backend_event_));
|
||||
#else
|
||||
C10_CUDA_CHECK(cudaEventSynchronize(backend_event_));
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
TORCH_CHECK(false, "Backend doesn't support events.");
|
||||
}
|
||||
|
||||
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
|
||||
#ifdef PADDLE_WITH_HIP
|
||||
hipEvent_t cuda_event() const { return backend_event_; }
|
||||
#else
|
||||
cudaEvent_t cuda_event() const { return backend_event_; }
|
||||
#endif
|
||||
#endif
|
||||
|
||||
private:
|
||||
DeviceType device_type_;
|
||||
DeviceIndex device_index_ = -1;
|
||||
EventFlag flag_ = EventFlag::PYTORCH_DEFAULT;
|
||||
bool was_marked_for_recording_ = false;
|
||||
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
|
||||
BackendEvent backend_event_ = nullptr;
|
||||
|
||||
static unsigned int BackendEventCreateFlags(EventFlag flag) {
|
||||
switch (flag) {
|
||||
case EventFlag::PYTORCH_DEFAULT:
|
||||
#ifdef PADDLE_WITH_HIP
|
||||
return hipEventDisableTiming;
|
||||
#else
|
||||
return cudaEventDisableTiming;
|
||||
#endif
|
||||
case EventFlag::BACKEND_DEFAULT:
|
||||
#ifdef PADDLE_WITH_HIP
|
||||
return hipEventDefault;
|
||||
#else
|
||||
return cudaEventDefault;
|
||||
#endif
|
||||
default:
|
||||
TORCH_CHECK(false, "CUDA event received unknown flag");
|
||||
}
|
||||
}
|
||||
|
||||
void EnsureBackendEventCreated(DeviceIndex stream_device_index) {
|
||||
if (backend_event_) {
|
||||
return;
|
||||
}
|
||||
c10::cuda::CUDAGuard guard(stream_device_index);
|
||||
#ifdef PADDLE_WITH_HIP
|
||||
PADDLE_ENFORCE_GPU_SUCCESS(hipEventCreateWithFlags(
|
||||
&backend_event_, BackendEventCreateFlags(flag_)));
|
||||
#else
|
||||
C10_CUDA_CHECK(cudaEventCreateWithFlags(&backend_event_,
|
||||
BackendEventCreateFlags(flag_)));
|
||||
#endif
|
||||
}
|
||||
|
||||
void RecordBackendEvent(BackendStream stream,
|
||||
DeviceIndex stream_device_index) {
|
||||
TORCH_CHECK(device_index_ == -1 || device_index_ == stream_device_index,
|
||||
"Event device index ",
|
||||
static_cast<int>(device_index_),
|
||||
" does not match recording stream's device index ",
|
||||
static_cast<int>(stream_device_index),
|
||||
".");
|
||||
EnsureBackendEventCreated(stream_device_index);
|
||||
c10::cuda::CUDAGuard guard(stream_device_index);
|
||||
#ifdef PADDLE_WITH_HIP
|
||||
PADDLE_ENFORCE_GPU_SUCCESS(hipEventRecord(backend_event_, stream));
|
||||
#else
|
||||
C10_CUDA_CHECK(cudaEventRecord(backend_event_, stream));
|
||||
#endif
|
||||
device_index_ = stream_device_index;
|
||||
was_marked_for_recording_ = true;
|
||||
}
|
||||
|
||||
void DestroyBackendEvent() noexcept {
|
||||
if (!backend_event_) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
c10::cuda::CUDAGuard guard(device_index_);
|
||||
#ifdef PADDLE_WITH_HIP
|
||||
PADDLE_ENFORCE_GPU_SUCCESS(hipEventDestroy(backend_event_));
|
||||
#else
|
||||
C10_CUDA_CHECK(cudaEventDestroy(backend_event_));
|
||||
#endif
|
||||
} catch (...) {
|
||||
}
|
||||
backend_event_ = nullptr;
|
||||
}
|
||||
#else
|
||||
void DestroyBackendEvent() noexcept {}
|
||||
#endif
|
||||
|
||||
void MoveFrom(Event&& other) noexcept {
|
||||
device_type_ = other.device_type_;
|
||||
device_index_ = other.device_index_;
|
||||
flag_ = other.flag_;
|
||||
was_marked_for_recording_ = other.was_marked_for_recording_;
|
||||
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
|
||||
backend_event_ = std::exchange(other.backend_event_, nullptr);
|
||||
#endif
|
||||
other.device_index_ = -1;
|
||||
other.was_marked_for_recording_ = false;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace c10
|
||||
|
||||
namespace torch {
|
||||
using c10::Event;
|
||||
} // namespace torch
|
||||
@@ -0,0 +1,147 @@
|
||||
// Copyright (c) 2026 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// The file has been adapted from pytorch project
|
||||
// Licensed under BSD-style license -
|
||||
// https://github.com/pytorch/pytorch/blob/main/LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <c10/core/Device.h>
|
||||
#include <c10/core/DispatchKeySet.h>
|
||||
#include <c10/util/Exception.h>
|
||||
#include <c10/util/intrusive_ptr.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <mutex> // NOLINT(build/c++11)
|
||||
#include <utility>
|
||||
|
||||
#include "paddle/phi/core/generator.h"
|
||||
|
||||
// Forward declare PyObject for the pyobj interface.
|
||||
#ifndef PyObject
|
||||
struct _object;
|
||||
using PyObject = _object;
|
||||
#endif
|
||||
|
||||
namespace c10 {
|
||||
|
||||
/**
|
||||
* GeneratorImpl — base implementation class for at::Generator.
|
||||
*
|
||||
* Wraps a Paddle phi::Generator and exposes the PyTorch-style API
|
||||
* (set_current_seed, seed, offset, device, key_set, etc.).
|
||||
*
|
||||
* Subclasses (e.g., CPUGeneratorImpl, CUDAGeneratorImpl) may extend
|
||||
* this to add backend-specific functionality.
|
||||
*
|
||||
* Note: Inherits from intrusive_ptr_target to support intrusive_ptr.
|
||||
*/
|
||||
class GeneratorImpl : public intrusive_ptr_target {
|
||||
public:
|
||||
// ------- constructors / destructor ----------------------------------------
|
||||
|
||||
/// Construct from an existing Paddle generator and a device.
|
||||
explicit GeneratorImpl(Device device,
|
||||
std::shared_ptr<phi::Generator> gen = nullptr)
|
||||
: device_(device), pyobj_(nullptr) {
|
||||
if (gen) {
|
||||
gen_ = std::move(gen);
|
||||
} else {
|
||||
gen_ = std::make_shared<phi::Generator>();
|
||||
}
|
||||
}
|
||||
|
||||
// Virtual destructor required for polymorphic base class
|
||||
// Note: intrusive_ptr_target destructor is protected, but we need public
|
||||
// destructor for delete to work through base pointer
|
||||
~GeneratorImpl() override = default;
|
||||
|
||||
// Non-copyable / non-movable (mirroring PyTorch semantics).
|
||||
GeneratorImpl(const GeneratorImpl&) = delete;
|
||||
GeneratorImpl& operator=(const GeneratorImpl&) = delete;
|
||||
|
||||
// ------- seed / offset API ------------------------------------------------
|
||||
|
||||
virtual void set_current_seed(uint64_t seed) { gen_->SetCurrentSeed(seed); }
|
||||
|
||||
virtual uint64_t current_seed() const { return gen_->GetCurrentSeed(); }
|
||||
|
||||
/// Generate and set a new random seed; return it.
|
||||
virtual uint64_t seed() { return gen_->Seed(); }
|
||||
|
||||
/// Set the Philox offset (supported in CUDA / MPS generators).
|
||||
virtual void set_offset(uint64_t offset) {
|
||||
// phi::Generator stores offset in its state; we reset it via
|
||||
// IncrementOffset after backing up the current offset.
|
||||
auto state = gen_->GetState();
|
||||
uint64_t cur = state.offset;
|
||||
if (offset > cur) {
|
||||
gen_->IncrementOffset(offset - cur);
|
||||
} else {
|
||||
// To move backwards, we need to reset the state.
|
||||
state.offset = offset;
|
||||
gen_->SetState(state);
|
||||
}
|
||||
}
|
||||
|
||||
virtual uint64_t get_offset() const { return gen_->GetCurrentOffset(); }
|
||||
|
||||
// ------- device / dispatch ------------------------------------------------
|
||||
|
||||
Device device() const { return device_; }
|
||||
|
||||
DispatchKeySet key_set() const {
|
||||
auto dt = device_.type();
|
||||
if (dt == kCPU) {
|
||||
return DispatchKeySet(DispatchKey::CPU);
|
||||
} else if (dt == kCUDA) {
|
||||
return DispatchKeySet(DispatchKey::CUDA);
|
||||
}
|
||||
return DispatchKeySet();
|
||||
}
|
||||
|
||||
// ------- clone ------------------------------------------------------------
|
||||
|
||||
virtual intrusive_ptr<GeneratorImpl> clone() const {
|
||||
auto state = gen_->GetState();
|
||||
auto new_gen = std::make_shared<phi::Generator>(state.seed);
|
||||
new_gen->SetState(state);
|
||||
auto impl = make_intrusive<GeneratorImpl>(device_, new_gen);
|
||||
return impl;
|
||||
}
|
||||
|
||||
// ------- mutex (for thread-safe usage) ------------------------------------
|
||||
|
||||
/// Public mutex for external locking (see PyTorch Note [Acquire lock ...]).
|
||||
std::mutex mutex_;
|
||||
|
||||
// ------- PyObject binding -------------------------------------------------
|
||||
|
||||
void set_pyobj(PyObject* pyobj) noexcept { pyobj_ = pyobj; }
|
||||
PyObject* pyobj() const noexcept { return pyobj_; }
|
||||
|
||||
// ------- internal accessor ------------------------------------------------
|
||||
|
||||
/// Access the underlying Paddle generator.
|
||||
std::shared_ptr<phi::Generator> paddle_generator() const { return gen_; }
|
||||
|
||||
protected:
|
||||
std::shared_ptr<phi::Generator> gen_;
|
||||
Device device_;
|
||||
PyObject* pyobj_;
|
||||
};
|
||||
|
||||
} // namespace c10
|
||||
@@ -0,0 +1,96 @@
|
||||
// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// The file has been adapted from pytorch project
|
||||
// Licensed under BSD-style license -
|
||||
// https://github.com/pytorch/pytorch/blob/main/LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <c10/util/Exception.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <ostream>
|
||||
|
||||
namespace c10 {
|
||||
enum class Layout : int8_t {
|
||||
Strided,
|
||||
Sparse,
|
||||
SparseCsr,
|
||||
Mkldnn,
|
||||
SparseCsc,
|
||||
SparseBsr,
|
||||
SparseBsc,
|
||||
Jagged,
|
||||
NumOptions
|
||||
};
|
||||
|
||||
constexpr auto kStrided = Layout::Strided;
|
||||
constexpr auto kSparse = Layout::Sparse;
|
||||
constexpr auto kSparseCsr = Layout::SparseCsr;
|
||||
constexpr auto kMkldnn = Layout::Mkldnn;
|
||||
constexpr auto kSparseCsc = Layout::SparseCsc;
|
||||
constexpr auto kSparseBsr = Layout::SparseBsr;
|
||||
constexpr auto kSparseBsc = Layout::SparseBsc;
|
||||
constexpr auto kJagged = Layout::Jagged;
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& stream, c10::Layout layout) {
|
||||
switch (layout) {
|
||||
case c10::kStrided:
|
||||
return stream << "Strided";
|
||||
case c10::kSparse:
|
||||
return stream << "Sparse";
|
||||
case c10::kSparseCsr:
|
||||
return stream << "SparseCsr";
|
||||
case c10::kSparseCsc:
|
||||
return stream << "SparseCsc";
|
||||
case c10::kSparseBsr:
|
||||
return stream << "SparseBsr";
|
||||
case c10::kSparseBsc:
|
||||
return stream << "SparseBsc";
|
||||
case c10::kMkldnn:
|
||||
return stream << "Mkldnn";
|
||||
case c10::kJagged:
|
||||
return stream << "Jagged";
|
||||
default:
|
||||
TORCH_CHECK(false, "Unknown layout");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace c10
|
||||
|
||||
namespace at {
|
||||
using c10::kJagged;
|
||||
using c10::kMkldnn;
|
||||
using c10::kSparse;
|
||||
using c10::kSparseBsc;
|
||||
using c10::kSparseBsr;
|
||||
using c10::kSparseCsc;
|
||||
using c10::kSparseCsr;
|
||||
using c10::kStrided;
|
||||
|
||||
using c10::Layout;
|
||||
} // namespace at
|
||||
namespace torch {
|
||||
using c10::kJagged;
|
||||
using c10::kMkldnn;
|
||||
using c10::kSparse;
|
||||
using c10::kSparseBsc;
|
||||
using c10::kSparseBsr;
|
||||
using c10::kSparseCsc;
|
||||
using c10::kSparseCsr;
|
||||
using c10::kStrided;
|
||||
|
||||
using c10::Layout;
|
||||
} // namespace torch
|
||||
@@ -0,0 +1,92 @@
|
||||
// Copyright (c) 2026 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// The file has been adapted from pytorch project
|
||||
// Licensed under BSD-style license -
|
||||
// https://github.com/pytorch/pytorch/blob/main/LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace c10 {
|
||||
|
||||
// c10::List is a type-safe wrapper around std::vector for PyTorch compatibility
|
||||
template <typename T>
|
||||
class List {
|
||||
public:
|
||||
using value_type = T;
|
||||
using size_type = typename std::vector<T>::size_type;
|
||||
using iterator = typename std::vector<T>::iterator;
|
||||
using const_iterator = typename std::vector<T>::const_iterator;
|
||||
using reference = typename std::vector<T>::reference;
|
||||
using const_reference = typename std::vector<T>::const_reference;
|
||||
|
||||
List() = default;
|
||||
List(std::initializer_list<T> init) : vec_(init) {}
|
||||
explicit List(size_type count) : vec_(count) {}
|
||||
List(size_type count, const T& value) : vec_(count, value) {}
|
||||
template <typename InputIt>
|
||||
List(InputIt first, InputIt last) : vec_(first, last) {}
|
||||
List(const std::vector<T>& vec) : vec_(vec) {} // NOLINT
|
||||
List(std::vector<T>&& vec) : vec_(std::move(vec)) {} // NOLINT
|
||||
|
||||
// Conversion to std::vector
|
||||
const std::vector<T>& vec() const { return vec_; }
|
||||
std::vector<T>& vec() { return vec_; }
|
||||
operator const std::vector<T>&() const { return vec_; } // NOLINT
|
||||
operator std::vector<T>&() { return vec_; } // NOLINT
|
||||
|
||||
// Standard vector-like interface
|
||||
size_type size() const { return vec_.size(); }
|
||||
bool empty() const { return vec_.empty(); }
|
||||
void clear() { vec_.clear(); }
|
||||
void reserve(size_type new_cap) { vec_.reserve(new_cap); }
|
||||
size_type capacity() const { return vec_.capacity(); }
|
||||
|
||||
reference operator[](size_type pos) { return vec_[pos]; }
|
||||
const_reference operator[](size_type pos) const { return vec_[pos]; }
|
||||
reference at(size_type pos) { return vec_.at(pos); }
|
||||
const_reference at(size_type pos) const { return vec_.at(pos); }
|
||||
reference front() { return vec_.front(); }
|
||||
const_reference front() const { return vec_.front(); }
|
||||
reference back() { return vec_.back(); }
|
||||
const_reference back() const { return vec_.back(); }
|
||||
|
||||
void push_back(const T& value) { vec_.push_back(value); }
|
||||
void push_back(T&& value) { vec_.push_back(std::move(value)); }
|
||||
template <typename... Args>
|
||||
reference emplace_back(Args&&... args) {
|
||||
return vec_.emplace_back(std::forward<Args>(args)...);
|
||||
}
|
||||
void pop_back() { vec_.pop_back(); }
|
||||
|
||||
iterator begin() { return vec_.begin(); }
|
||||
const_iterator begin() const { return vec_.begin(); }
|
||||
const_iterator cbegin() const { return vec_.cbegin(); }
|
||||
iterator end() { return vec_.end(); }
|
||||
const_iterator end() const { return vec_.end(); }
|
||||
const_iterator cend() const { return vec_.cend(); }
|
||||
|
||||
void resize(size_type count) { vec_.resize(count); }
|
||||
void resize(size_type count, const T& value) { vec_.resize(count, value); }
|
||||
|
||||
bool operator==(const List<T>& other) const { return vec_ == other.vec_; }
|
||||
bool operator!=(const List<T>& other) const { return vec_ != other.vec_; }
|
||||
|
||||
private:
|
||||
std::vector<T> vec_;
|
||||
};
|
||||
|
||||
} // namespace c10
|
||||
@@ -0,0 +1,40 @@
|
||||
// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// The file has been adapted from pytorch project
|
||||
// Licensed under BSD-style license -
|
||||
// https://github.com/pytorch/pytorch/blob/main/LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace c10 {
|
||||
enum class PADDLE_API MemoryFormat : int8_t {
|
||||
Contiguous,
|
||||
Preserve,
|
||||
ChannelsLast,
|
||||
ChannelsLast3d,
|
||||
NumOptions
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace at {
|
||||
using c10::MemoryFormat;
|
||||
} // namespace at
|
||||
|
||||
namespace torch {
|
||||
using c10::MemoryFormat;
|
||||
} // namespace torch
|
||||
@@ -0,0 +1,28 @@
|
||||
// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "paddle/phi/common/scalar.h"
|
||||
|
||||
namespace c10 {
|
||||
using Scalar = paddle::experimental::Scalar;
|
||||
}
|
||||
namespace at {
|
||||
using c10::Scalar;
|
||||
} // namespace at
|
||||
|
||||
namespace torch {
|
||||
using c10::Scalar;
|
||||
} // namespace torch
|
||||
@@ -0,0 +1,267 @@
|
||||
// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// The file has been adapted from pytorch project
|
||||
// Licensed under BSD-style license -
|
||||
// https://github.com/pytorch/pytorch/blob/main/LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
// If you modified ScalarType foundational definitions in this file, please
|
||||
// also sync your changes into torch/headeronly/core/ScalarType.h.
|
||||
#include <torch/headeronly/core/ScalarType.h>
|
||||
|
||||
#include <c10/util/Exception.h>
|
||||
|
||||
#include <limits>
|
||||
#include <sstream>
|
||||
|
||||
namespace c10 {
|
||||
|
||||
#define DEFINE_CONSTANT(_1, _2, name) \
|
||||
constexpr ScalarType k##name = ScalarType::name;
|
||||
|
||||
AT_FORALL_SCALAR_TYPES_WITH_COMPLEX_AND_QINTS(DEFINE_CONSTANT)
|
||||
#undef DEFINE_CONSTANT
|
||||
|
||||
constexpr ScalarType kUndefined = ScalarType::Undefined;
|
||||
|
||||
inline size_t elementSize(ScalarType t) {
|
||||
#define CASE_ELEMENTSIZE_CASE(ctype, _2, name) \
|
||||
case ScalarType::name: \
|
||||
return sizeof(ctype);
|
||||
|
||||
switch (t) {
|
||||
AT_FORALL_SCALAR_TYPES_WITH_COMPLEX_AND_QINTS(CASE_ELEMENTSIZE_CASE)
|
||||
default:
|
||||
TORCH_CHECK(false, "Unknown ScalarType");
|
||||
}
|
||||
#undef CASE_ELEMENTSIZE_CASE
|
||||
}
|
||||
|
||||
inline bool isIntegralType(ScalarType t, bool includeBool) {
|
||||
bool isIntegral = (t == ScalarType::Byte || t == ScalarType::Char ||
|
||||
t == ScalarType::Int || t == ScalarType::Long ||
|
||||
t == ScalarType::Short || t == ScalarType::UInt16 ||
|
||||
t == ScalarType::UInt32 || t == ScalarType::UInt64);
|
||||
|
||||
return isIntegral || (includeBool && t == ScalarType::Bool);
|
||||
}
|
||||
|
||||
inline bool isFloat8Type(ScalarType t) {
|
||||
return t == ScalarType::Float8_e5m2 || t == ScalarType::Float8_e4m3fn ||
|
||||
t == ScalarType::Float8_e5m2fnuz || t == ScalarType::Float8_e4m3fnuz ||
|
||||
t == ScalarType::Float8_e8m0fnu;
|
||||
}
|
||||
|
||||
inline bool isReducedFloatingType(ScalarType t) {
|
||||
return t == ScalarType::Half || t == ScalarType::BFloat16 ||
|
||||
isFloat8Type(t) || t == ScalarType::Float4_e2m1fn_x2;
|
||||
}
|
||||
|
||||
inline bool isFloatingType(ScalarType t) {
|
||||
return t == ScalarType::Double || t == ScalarType::Float ||
|
||||
isReducedFloatingType(t);
|
||||
}
|
||||
|
||||
inline bool isComplexType(ScalarType t) {
|
||||
return (t == ScalarType::ComplexHalf || t == ScalarType::ComplexFloat ||
|
||||
t == ScalarType::ComplexDouble);
|
||||
}
|
||||
|
||||
inline bool isBitsType(ScalarType t) {
|
||||
return t == ScalarType::Bits1x8 || t == ScalarType::Bits2x4 ||
|
||||
t == ScalarType::Bits4x2 || t == ScalarType::Bits8 ||
|
||||
t == ScalarType::Bits16;
|
||||
}
|
||||
|
||||
inline bool isBarebonesUnsignedType(ScalarType t) {
|
||||
return t == ScalarType::UInt1 || t == ScalarType::UInt2 ||
|
||||
t == ScalarType::UInt3 || t == ScalarType::UInt4 ||
|
||||
t == ScalarType::UInt5 || t == ScalarType::UInt6 ||
|
||||
t == ScalarType::UInt7 || t == ScalarType::UInt16 ||
|
||||
t == ScalarType::UInt32 || t == ScalarType::UInt64;
|
||||
}
|
||||
|
||||
inline ScalarType toQIntType(ScalarType t) {
|
||||
switch (t) {
|
||||
case ScalarType::Byte:
|
||||
return ScalarType::QUInt8;
|
||||
case ScalarType::Char:
|
||||
return ScalarType::QInt8;
|
||||
case ScalarType::Int:
|
||||
return ScalarType::QInt32;
|
||||
default:
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool isSignedType(ScalarType t) {
|
||||
#define CASE_ISSIGNED(name) \
|
||||
case ScalarType::name: \
|
||||
return std::numeric_limits< \
|
||||
::c10::impl::ScalarTypeToCPPTypeT<ScalarType::name>>::is_signed;
|
||||
|
||||
switch (t) {
|
||||
// Signed integer types (using numeric_limits)
|
||||
CASE_ISSIGNED(Char); // int8_t
|
||||
CASE_ISSIGNED(Short); // int16_t
|
||||
CASE_ISSIGNED(Int); // int32_t
|
||||
CASE_ISSIGNED(Long); // int64_t
|
||||
|
||||
// Signed integer types (dummy types, explicitly return true)
|
||||
case ScalarType::Int1:
|
||||
case ScalarType::Int2:
|
||||
case ScalarType::Int3:
|
||||
case ScalarType::Int4:
|
||||
case ScalarType::Int5:
|
||||
case ScalarType::Int6:
|
||||
case ScalarType::Int7:
|
||||
return true;
|
||||
|
||||
// Signed floating point types (using numeric_limits)
|
||||
CASE_ISSIGNED(Half); // float16
|
||||
CASE_ISSIGNED(Float); // float32
|
||||
CASE_ISSIGNED(Double); // float64
|
||||
CASE_ISSIGNED(BFloat16);
|
||||
CASE_ISSIGNED(Float8_e5m2);
|
||||
CASE_ISSIGNED(Float8_e4m3fn);
|
||||
|
||||
// Complex types (treated as signed)
|
||||
case ScalarType::ComplexHalf:
|
||||
case ScalarType::ComplexFloat:
|
||||
case ScalarType::ComplexDouble:
|
||||
return true;
|
||||
|
||||
// Signed quantized types (explicitly return true)
|
||||
case ScalarType::QInt8:
|
||||
case ScalarType::QInt32:
|
||||
return true;
|
||||
|
||||
// Unsigned integer types (using numeric_limits)
|
||||
CASE_ISSIGNED(Byte); // uint8_t
|
||||
|
||||
// Unsigned integer types (explicitly return false)
|
||||
case ScalarType::UInt16:
|
||||
case ScalarType::UInt32:
|
||||
case ScalarType::UInt64:
|
||||
case ScalarType::UInt1:
|
||||
case ScalarType::UInt2:
|
||||
case ScalarType::UInt3:
|
||||
case ScalarType::UInt4:
|
||||
case ScalarType::UInt5:
|
||||
case ScalarType::UInt6:
|
||||
case ScalarType::UInt7:
|
||||
return false;
|
||||
|
||||
// Unsigned quantized types (explicitly return false)
|
||||
case ScalarType::QUInt8:
|
||||
case ScalarType::QUInt4x2:
|
||||
case ScalarType::QUInt2x4:
|
||||
case ScalarType::Bits1x8:
|
||||
case ScalarType::Bits2x4:
|
||||
case ScalarType::Bits4x2:
|
||||
case ScalarType::Bits8:
|
||||
case ScalarType::Bits16:
|
||||
return false;
|
||||
|
||||
// Bool is unsigned (using numeric_limits)
|
||||
CASE_ISSIGNED(Bool);
|
||||
|
||||
case ScalarType::Float8_e5m2fnuz:
|
||||
case ScalarType::Float8_e4m3fnuz:
|
||||
case ScalarType::Float8_e8m0fnu:
|
||||
case ScalarType::Float4_e2m1fn_x2:
|
||||
return true;
|
||||
|
||||
// Invalid/undefined types - should not happen in normal usage
|
||||
// If this is hit, it indicates a programming error or unsupported type
|
||||
case ScalarType::Undefined:
|
||||
case ScalarType::NumOptions: {
|
||||
std::ostringstream oss;
|
||||
oss << "isSignedType: Invalid or unsupported ScalarType value: "
|
||||
<< toString(t) << " (" << static_cast<int>(t) << ")";
|
||||
PD_THROW(oss.str());
|
||||
return false; // Unreachable, but satisfies compiler
|
||||
}
|
||||
|
||||
// Note: If a new ScalarType is added to the enum but not handled here,
|
||||
// the compiler will warn about missing case. This ensures all types are
|
||||
// explicitly handled.
|
||||
}
|
||||
#undef CASE_ISSIGNED
|
||||
return false; // Unreachable, but satisfies compiler
|
||||
}
|
||||
|
||||
inline bool isUnderlying(ScalarType type, ScalarType qtype) {
|
||||
return type == toUnderlying(qtype);
|
||||
}
|
||||
|
||||
inline ScalarType toRealValueType(ScalarType t) {
|
||||
switch (t) {
|
||||
case ScalarType::ComplexHalf:
|
||||
return ScalarType::Half;
|
||||
case ScalarType::ComplexFloat:
|
||||
return ScalarType::Float;
|
||||
case ScalarType::ComplexDouble:
|
||||
return ScalarType::Double;
|
||||
default:
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
||||
inline ScalarType toComplexType(ScalarType t) {
|
||||
switch (t) {
|
||||
case ScalarType::BFloat16:
|
||||
return ScalarType::ComplexFloat;
|
||||
case ScalarType::Half:
|
||||
return ScalarType::ComplexHalf;
|
||||
case ScalarType::Float:
|
||||
return ScalarType::ComplexFloat;
|
||||
case ScalarType::Double:
|
||||
return ScalarType::ComplexDouble;
|
||||
case ScalarType::ComplexHalf:
|
||||
return ScalarType::ComplexHalf;
|
||||
case ScalarType::ComplexFloat:
|
||||
return ScalarType::ComplexFloat;
|
||||
case ScalarType::ComplexDouble:
|
||||
return ScalarType::ComplexDouble;
|
||||
default:
|
||||
TORCH_CHECK(false, "Unknown Complex ScalarType for ", t);
|
||||
}
|
||||
}
|
||||
|
||||
inline bool canCast(const ScalarType from, const ScalarType to) {
|
||||
if (isComplexType(from) && !isComplexType(to)) {
|
||||
return false;
|
||||
}
|
||||
if (isFloatingType(from) && isIntegralType(to, false)) {
|
||||
return false;
|
||||
}
|
||||
if (from != ScalarType::Bool && to == ScalarType::Bool) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace c10
|
||||
|
||||
namespace at {
|
||||
using c10::CppTypeToScalarType;
|
||||
using c10::ScalarType;
|
||||
} // namespace at
|
||||
namespace torch {
|
||||
using c10::CppTypeToScalarType;
|
||||
using c10::ScalarType;
|
||||
} // namespace torch
|
||||
@@ -0,0 +1,54 @@
|
||||
// Copyright (c) 2026 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// The file has been adapted from pytorch project
|
||||
// Licensed under BSD-style license -
|
||||
// https://github.com/pytorch/pytorch/blob/main/LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <c10/core/ScalarType.h>
|
||||
#include <c10/util/typeid.h>
|
||||
#include <optional>
|
||||
|
||||
namespace c10 {
|
||||
|
||||
/// Convert ScalarType enum values to TypeMeta handles.
|
||||
inline caffe2::TypeMeta scalarTypeToTypeMeta(ScalarType scalar_type) {
|
||||
return caffe2::TypeMeta::fromScalarType(scalar_type);
|
||||
}
|
||||
|
||||
/// Convert TypeMeta handles to ScalarType enum values.
|
||||
inline ScalarType typeMetaToScalarType(caffe2::TypeMeta dtype) {
|
||||
return dtype.toScalarType();
|
||||
}
|
||||
|
||||
/// typeMetaToScalarType(), lifted to optional.
|
||||
inline std::optional<ScalarType> optTypeMetaToScalarType(
|
||||
std::optional<caffe2::TypeMeta> type_meta) {
|
||||
if (!type_meta.has_value()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return type_meta->toScalarType();
|
||||
}
|
||||
|
||||
/// Equality across TypeMeta / ScalarType.
|
||||
inline bool operator==(ScalarType t, caffe2::TypeMeta m) {
|
||||
return m.isScalarType(t);
|
||||
}
|
||||
inline bool operator==(caffe2::TypeMeta m, ScalarType t) { return t == m; }
|
||||
inline bool operator!=(ScalarType t, caffe2::TypeMeta m) { return !(t == m); }
|
||||
inline bool operator!=(caffe2::TypeMeta m, ScalarType t) { return !(t == m); }
|
||||
|
||||
} // namespace c10
|
||||
@@ -0,0 +1,498 @@
|
||||
// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// The file has been adapted from pytorch project
|
||||
// Licensed under BSD-style license -
|
||||
// https://github.com/pytorch/pytorch/blob/main/LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include "paddle/phi/common/place.h"
|
||||
#include "paddle/phi/core/allocator.h"
|
||||
#include "paddle/phi/core/dense_tensor.h"
|
||||
#include "paddle/phi/core/storage_properties.h"
|
||||
|
||||
#include "c10/core/Allocator.h" // For DataPtr
|
||||
|
||||
namespace c10 {
|
||||
|
||||
struct Storage;
|
||||
class StorageHolderView;
|
||||
|
||||
// Check if two storages share the same underlying allocation
|
||||
inline bool isSharedStorageAlias(const Storage& storage0,
|
||||
const Storage& storage1);
|
||||
|
||||
// Shared state for Storage handles. All Storage copies that refer to the
|
||||
// same logical storage share a single StorageImpl, so mutations via
|
||||
// set_data_ptr*(), set_nbytes(), or mutable_data_ptr() are visible to all
|
||||
// handles — matching the observable contract of c10::StorageImpl in PyTorch.
|
||||
struct StorageImpl {
|
||||
std::shared_ptr<phi::Allocation> data_allocation_;
|
||||
phi::Allocator* allocator_ = nullptr;
|
||||
size_t nbytes_ = 0;
|
||||
bool resizable_ = false;
|
||||
phi::Place place_;
|
||||
// DataPtr is stored directly (not in a shared_ptr) because all Storage
|
||||
// copies already share this StorageImpl, so one level of indirection
|
||||
// suffices to propagate mutations.
|
||||
DataPtr data_ptr_;
|
||||
std::weak_ptr<StorageHolderView> tensor_holder_;
|
||||
};
|
||||
|
||||
class StorageHolderView final : public phi::Allocation {
|
||||
public:
|
||||
explicit StorageHolderView(std::shared_ptr<StorageImpl> impl)
|
||||
: impl_(std::move(impl)) {}
|
||||
|
||||
std::shared_ptr<StorageImpl> get_impl() const { return impl_; }
|
||||
|
||||
void* ptr() const noexcept override {
|
||||
if (!impl_) {
|
||||
return nullptr;
|
||||
}
|
||||
if (impl_->data_allocation_) {
|
||||
return impl_->data_allocation_->ptr();
|
||||
}
|
||||
return impl_->data_ptr_.get();
|
||||
}
|
||||
|
||||
size_t size() const noexcept override { return impl_ ? impl_->nbytes_ : 0; }
|
||||
|
||||
const Place& place() const noexcept override {
|
||||
return impl_ ? impl_->place_ : place_;
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<StorageImpl> impl_;
|
||||
Place place_;
|
||||
};
|
||||
|
||||
struct Storage {
|
||||
public:
|
||||
// Tag types for constructor disambiguation (LibTorch compatible)
|
||||
struct use_byte_size_t {};
|
||||
struct unsafe_borrow_t {
|
||||
unsafe_borrow_t() = default;
|
||||
};
|
||||
|
||||
// Default constructor: empty storage, no allocation, no data.
|
||||
Storage() : impl_(std::make_shared<StorageImpl>()) {}
|
||||
|
||||
// Copy constructor: shares the StorageImpl so that mutations made through
|
||||
// either handle are visible through the other.
|
||||
Storage(const Storage& other) : impl_(other.impl_) {}
|
||||
|
||||
// Copy assignment operator
|
||||
Storage& operator=(const Storage& other) {
|
||||
if (this != &other) {
|
||||
impl_ = other.impl_;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Move constructor: transfers ownership of the StorageImpl.
|
||||
// The moved-from object is left in an unspecified (but destructible) state.
|
||||
Storage(Storage&& other) noexcept : impl_(std::move(other.impl_)) {}
|
||||
|
||||
// Move assignment operator
|
||||
Storage& operator=(Storage&& other) noexcept {
|
||||
if (this != &other) {
|
||||
impl_ = std::move(other.impl_);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Constructor with allocation and optional storage properties
|
||||
Storage(std::shared_ptr<phi::Allocation> alloc,
|
||||
std::unique_ptr<phi::StorageProperties> props = nullptr) {
|
||||
impl_ = std::make_shared<StorageImpl>();
|
||||
if (alloc) {
|
||||
syncFromAllocation(std::move(alloc));
|
||||
}
|
||||
}
|
||||
|
||||
// Constructor with size and allocator (LibTorch compatible)
|
||||
explicit Storage(size_t size_bytes, phi::Allocator* allocator = nullptr) {
|
||||
impl_ = std::make_shared<StorageImpl>();
|
||||
if (allocator) {
|
||||
auto alloc =
|
||||
std::shared_ptr<phi::Allocation>(allocator->Allocate(size_bytes));
|
||||
impl_->allocator_ = allocator;
|
||||
syncFromAllocation(std::move(alloc));
|
||||
impl_->nbytes_ = size_bytes;
|
||||
}
|
||||
}
|
||||
|
||||
// LibTorch compatible constructor with use_byte_size_t tag
|
||||
Storage(use_byte_size_t /*use_byte_size*/,
|
||||
size_t size_bytes,
|
||||
phi::Allocator* allocator = nullptr,
|
||||
bool resizable = false) {
|
||||
impl_ = std::make_shared<StorageImpl>();
|
||||
impl_->allocator_ = allocator;
|
||||
impl_->nbytes_ = size_bytes;
|
||||
impl_->resizable_ = resizable;
|
||||
if (allocator) {
|
||||
auto alloc =
|
||||
std::shared_ptr<phi::Allocation>(allocator->Allocate(size_bytes));
|
||||
syncFromAllocation(std::move(alloc));
|
||||
impl_->nbytes_ = size_bytes;
|
||||
}
|
||||
}
|
||||
|
||||
// LibTorch compatible constructor with pre-allocated phi::Allocation
|
||||
Storage(use_byte_size_t /*use_byte_size*/,
|
||||
size_t size_bytes,
|
||||
std::shared_ptr<phi::Allocation> alloc,
|
||||
phi::Allocator* allocator = nullptr,
|
||||
bool resizable = false) {
|
||||
impl_ = std::make_shared<StorageImpl>();
|
||||
impl_->allocator_ = allocator;
|
||||
impl_->nbytes_ = size_bytes;
|
||||
impl_->resizable_ = resizable;
|
||||
syncFromAllocation(std::move(alloc));
|
||||
impl_->nbytes_ = size_bytes;
|
||||
}
|
||||
|
||||
// LibTorch compatible constructor with pre-allocated DataPtr
|
||||
Storage(use_byte_size_t /*use_byte_size*/,
|
||||
size_t size_bytes,
|
||||
DataPtr data_ptr,
|
||||
phi::Allocator* allocator = nullptr,
|
||||
bool resizable = false) {
|
||||
impl_ = std::make_shared<StorageImpl>();
|
||||
impl_->allocator_ = allocator;
|
||||
impl_->nbytes_ = size_bytes;
|
||||
impl_->resizable_ = resizable;
|
||||
syncFromDataPtr(std::move(data_ptr), size_bytes);
|
||||
}
|
||||
|
||||
protected:
|
||||
// Unsafe borrow constructor (for MaybeOwnedTraits): shares the StorageImpl.
|
||||
// With the shared-impl design this is equivalent to a regular copy, but the
|
||||
// tag distinguishes "borrow" intent from ordinary copies at call sites.
|
||||
explicit Storage(unsafe_borrow_t, const Storage& rhs) : impl_(rhs.impl_) {}
|
||||
|
||||
// Forward declare template and make specialization a friend
|
||||
template <typename T>
|
||||
friend struct MaybeOwnedTraits;
|
||||
|
||||
public:
|
||||
// Construct from a pre-existing shared StorageImpl (used by the global
|
||||
// per-tensor storage registry to reuse an existing StorageImpl).
|
||||
explicit Storage(std::shared_ptr<StorageImpl> impl)
|
||||
: impl_(std::move(impl)) {}
|
||||
|
||||
// Returns the underlying shared StorageImpl (used by the global per-tensor
|
||||
// storage registry).
|
||||
std::shared_ptr<StorageImpl> get_impl() const { return impl_; }
|
||||
|
||||
static Storage createTensorStorage(
|
||||
const std::shared_ptr<phi::Allocation>& holder) {
|
||||
if (!holder) {
|
||||
return Storage();
|
||||
}
|
||||
if (auto storage_holder =
|
||||
std::dynamic_pointer_cast<StorageHolderView>(holder)) {
|
||||
return Storage(storage_holder->get_impl());
|
||||
}
|
||||
auto impl = std::make_shared<StorageImpl>();
|
||||
Storage storage(std::move(impl));
|
||||
storage.syncFromAllocation(holder);
|
||||
storage.ensureTensorHolder();
|
||||
return storage;
|
||||
}
|
||||
|
||||
std::shared_ptr<phi::Allocation> ensureTensorHolder() const {
|
||||
if (!impl_) {
|
||||
return nullptr;
|
||||
}
|
||||
auto holder = impl_->tensor_holder_.lock();
|
||||
if (!holder) {
|
||||
holder = std::make_shared<StorageHolderView>(impl_);
|
||||
impl_->tensor_holder_ = holder;
|
||||
}
|
||||
return holder;
|
||||
}
|
||||
|
||||
// Check if storage is valid (has allocation or data)
|
||||
bool valid() const {
|
||||
return impl_ && (static_cast<bool>(impl_->data_allocation_) ||
|
||||
static_cast<bool>(impl_->data_ptr_));
|
||||
}
|
||||
|
||||
// Boolean conversion operator (LibTorch compatible)
|
||||
explicit operator bool() const { return valid(); }
|
||||
|
||||
// Get the number of bytes in the storage
|
||||
size_t nbytes() const { return impl_ ? impl_->nbytes_ : 0; }
|
||||
|
||||
// Set the number of bytes.
|
||||
// For resizable storage with an allocator, reallocates; otherwise updates
|
||||
// the byte count directly so the change is visible to all copies.
|
||||
void set_nbytes(size_t size_bytes) {
|
||||
if (!impl_) return;
|
||||
if (impl_->resizable_ && impl_->allocator_) {
|
||||
syncFromAllocation(std::shared_ptr<phi::Allocation>(
|
||||
impl_->allocator_->Allocate(size_bytes)));
|
||||
impl_->nbytes_ = size_bytes;
|
||||
} else {
|
||||
impl_->nbytes_ = size_bytes;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if storage is resizable
|
||||
bool resizable() const { return impl_ ? impl_->resizable_ : false; }
|
||||
|
||||
// Get mutable data pointer
|
||||
void* mutable_data() const {
|
||||
if (!impl_) {
|
||||
return nullptr;
|
||||
}
|
||||
if (impl_->data_allocation_) {
|
||||
return impl_->data_allocation_->ptr();
|
||||
}
|
||||
return impl_->data_ptr_.get();
|
||||
}
|
||||
|
||||
// Get const data pointer
|
||||
const void* data() const {
|
||||
if (!impl_) {
|
||||
return nullptr;
|
||||
}
|
||||
if (impl_->data_allocation_) {
|
||||
return impl_->data_allocation_->ptr();
|
||||
}
|
||||
return impl_->data_ptr_.get();
|
||||
}
|
||||
|
||||
// Get a const reference to the underlying DataPtr (LibTorch compatible)
|
||||
const DataPtr& data_ptr() const { return impl_->data_ptr_; }
|
||||
|
||||
// Get a mutable reference to the underlying DataPtr (LibTorch compatible).
|
||||
// Because all Storage copies share the same StorageImpl, this reference
|
||||
// reflects and propagates changes to all handles — matching PyTorch's
|
||||
// StorageImpl semantics where mutable_data_ptr() returns the member directly.
|
||||
DataPtr& mutable_data_ptr() const { return impl_->data_ptr_; }
|
||||
|
||||
// Get the underlying phi::Allocation (Paddle-specific)
|
||||
std::shared_ptr<phi::Allocation> allocation() const {
|
||||
return impl_ ? impl_->data_allocation_ : nullptr;
|
||||
}
|
||||
|
||||
// Get the allocator
|
||||
phi::Allocator* allocator() const {
|
||||
return impl_ ? impl_->allocator_ : nullptr;
|
||||
}
|
||||
|
||||
// Get the device/place type
|
||||
phi::AllocationType device_type() const {
|
||||
if (!impl_) return phi::AllocationType::CPU;
|
||||
if (impl_->data_allocation_)
|
||||
return impl_->data_allocation_->place().GetType();
|
||||
if (impl_->data_ptr_)
|
||||
return c10::DeviceTypeToPhi(impl_->data_ptr_.device().type());
|
||||
return phi::AllocationType::CPU;
|
||||
}
|
||||
|
||||
// Get the device/place
|
||||
phi::Place device() const {
|
||||
if (!impl_) return phi::Place();
|
||||
if (impl_->data_allocation_) return impl_->data_allocation_->place();
|
||||
return impl_->place_;
|
||||
}
|
||||
|
||||
// Returns the number of c10::Storage handles currently sharing this
|
||||
// StorageImpl (i.e. impl_.use_count()), matching PyTorch's
|
||||
// c10::Storage::use_count() semantics. Returns 0 for empty / invalid
|
||||
// storage (neither allocation nor data_ptr set).
|
||||
size_t use_count() const {
|
||||
if (!valid()) return 0;
|
||||
size_t count = impl_.use_count();
|
||||
if (!impl_->tensor_holder_.expired() && count > 0) {
|
||||
--count;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
// Check if this storage is unique (use_count == 1)
|
||||
bool unique() const { return use_count() == 1; }
|
||||
|
||||
// Check if this storage is an alias of another
|
||||
bool is_alias_of(const Storage& other) const {
|
||||
if (!valid() || !other.valid()) {
|
||||
return false;
|
||||
}
|
||||
// Fast path: same StorageImpl (e.g. two copies of the same Storage handle)
|
||||
if (impl_ == other.impl_) return true;
|
||||
return isSharedStorageAlias(*this, other);
|
||||
}
|
||||
|
||||
// Set data pointer (swap and return old) - LibTorch compatible DataPtr
|
||||
// version. Clears allocation-backed state since the new DataPtr manages its
|
||||
// own lifecycle. The change is propagated to all Storage copies that share
|
||||
// this StorageImpl. Use set_data_ptr(shared_ptr<phi::Allocation>) for
|
||||
// Paddle paths.
|
||||
DataPtr set_data_ptr(DataPtr&& new_data_ptr) {
|
||||
DataPtr old = std::move(impl_->data_ptr_);
|
||||
syncFromDataPtr(std::move(new_data_ptr), impl_->nbytes_);
|
||||
return old;
|
||||
}
|
||||
DataPtr set_data_ptr(std::nullptr_t) = delete;
|
||||
|
||||
// Set data pointer (no swap) - LibTorch compatible DataPtr version.
|
||||
// Propagated to all Storage copies that share this StorageImpl.
|
||||
void set_data_ptr_noswap(DataPtr&& new_data_ptr) {
|
||||
syncFromDataPtr(std::move(new_data_ptr), impl_->nbytes_);
|
||||
}
|
||||
void set_data_ptr_noswap(std::nullptr_t) = delete;
|
||||
|
||||
// Set data pointer - Paddle-specific shared_ptr<phi::Allocation> version.
|
||||
// Propagated to all Storage copies that share this StorageImpl.
|
||||
std::shared_ptr<phi::Allocation> set_data_ptr(
|
||||
std::shared_ptr<phi::Allocation> new_alloc) {
|
||||
std::shared_ptr<phi::Allocation> old_alloc =
|
||||
std::move(impl_->data_allocation_);
|
||||
syncFromAllocation(std::move(new_alloc));
|
||||
return old_alloc;
|
||||
}
|
||||
|
||||
// Set data pointer (no swap) - Paddle-specific shared_ptr version.
|
||||
// Propagated to all Storage copies that share this StorageImpl.
|
||||
void set_data_ptr_noswap(std::shared_ptr<phi::Allocation> new_alloc) {
|
||||
syncFromAllocation(std::move(new_alloc));
|
||||
}
|
||||
|
||||
private:
|
||||
// Shared implementation state. All Storage copies that were created by
|
||||
// copying this Storage share the same StorageImpl, so writes through any
|
||||
// handle are immediately visible through all other handles.
|
||||
std::shared_ptr<StorageImpl> impl_;
|
||||
|
||||
// Update allocation-backed storage state. The tensor holder stays attached
|
||||
// to the shared StorageImpl, so tensors observe pointer changes without
|
||||
// extra registry state.
|
||||
void syncFromAllocation(std::shared_ptr<phi::Allocation> new_alloc) {
|
||||
impl_->data_allocation_ = std::move(new_alloc);
|
||||
if (impl_->data_allocation_) {
|
||||
impl_->nbytes_ = impl_->data_allocation_->size();
|
||||
impl_->place_ = impl_->data_allocation_->place();
|
||||
} else {
|
||||
impl_->nbytes_ = 0;
|
||||
impl_->place_ = phi::Place();
|
||||
}
|
||||
impl_->data_ptr_ = viewDataPtrFrom(impl_->data_allocation_);
|
||||
}
|
||||
|
||||
void syncFromDataPtr(DataPtr&& new_data_ptr, size_t size_bytes) {
|
||||
impl_->data_allocation_ = nullptr;
|
||||
impl_->nbytes_ = size_bytes;
|
||||
impl_->place_ =
|
||||
new_data_ptr ? new_data_ptr.device()._PD_GetInner() : phi::Place();
|
||||
impl_->data_ptr_ = std::move(new_data_ptr);
|
||||
}
|
||||
|
||||
// Create a non-owning DataPtr view of a phi::Allocation.
|
||||
// The allocation's lifetime is managed by impl_->data_allocation_.
|
||||
// No deleter is installed so the DataPtr holds only a raw pointer.
|
||||
static DataPtr viewDataPtrFrom(
|
||||
const std::shared_ptr<phi::Allocation>& alloc) {
|
||||
if (!alloc) return DataPtr();
|
||||
return DataPtr(alloc->ptr(), c10::Device(alloc->place()));
|
||||
}
|
||||
};
|
||||
|
||||
// Implementation of isSharedStorageAlias
|
||||
inline bool isSharedStorageAlias(const Storage& storage0,
|
||||
const Storage& storage1) {
|
||||
if (!storage0.valid() || !storage1.valid()) {
|
||||
return false;
|
||||
}
|
||||
c10::DeleterFnPtr deleter0 = storage0.data_ptr().get_deleter();
|
||||
c10::DeleterFnPtr deleter1 = storage1.data_ptr().get_deleter();
|
||||
if (deleter0 == nullptr || deleter1 == nullptr || deleter0 != deleter1) {
|
||||
return false;
|
||||
}
|
||||
void* context0 = storage0.data_ptr().get_context();
|
||||
void* context1 = storage1.data_ptr().get_context();
|
||||
return context0 != nullptr && context0 == context1;
|
||||
}
|
||||
|
||||
// Template specialization for MaybeOwnedTraits<c10::Storage>
|
||||
template <typename T>
|
||||
struct MaybeOwnedTraits;
|
||||
|
||||
template <>
|
||||
struct MaybeOwnedTraits<c10::Storage> {
|
||||
using owned_type = c10::Storage;
|
||||
using borrow_type = c10::Storage;
|
||||
|
||||
static borrow_type createBorrow(const owned_type& from) {
|
||||
return borrow_type(borrow_type::unsafe_borrow_t{}, from);
|
||||
}
|
||||
|
||||
static void assignBorrow(borrow_type& lhs, // NOLINT(runtime/references)
|
||||
const borrow_type& rhs) {
|
||||
lhs = borrow_type(borrow_type::unsafe_borrow_t{}, rhs);
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(runtime/references)
|
||||
static void destroyBorrow(borrow_type& toDestroy) { toDestroy = Storage(); }
|
||||
|
||||
static const owned_type& referenceFromBorrow(const borrow_type& borrow) {
|
||||
return borrow;
|
||||
}
|
||||
|
||||
static const owned_type* pointerFromBorrow(const borrow_type& borrow) {
|
||||
return &borrow;
|
||||
}
|
||||
|
||||
static bool debugBorrowIsValid(const borrow_type& /*borrow*/) { return true; }
|
||||
};
|
||||
|
||||
// Template specialization for ExclusivelyOwnedTraits<c10::Storage>
|
||||
template <typename T>
|
||||
struct ExclusivelyOwnedTraits;
|
||||
|
||||
template <>
|
||||
struct ExclusivelyOwnedTraits<c10::Storage> {
|
||||
using repr_type = c10::Storage;
|
||||
using pointer_type = c10::Storage*;
|
||||
using const_pointer_type = const c10::Storage*;
|
||||
|
||||
static repr_type nullRepr() { return c10::Storage(); }
|
||||
|
||||
template <class... Args>
|
||||
static repr_type createInPlace(Args&&... args) {
|
||||
return c10::Storage(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
static repr_type moveToRepr(c10::Storage&& x) { return std::move(x); }
|
||||
|
||||
static c10::Storage take(c10::Storage& x) { // NOLINT(runtime/references)
|
||||
return std::move(x);
|
||||
}
|
||||
|
||||
static pointer_type getImpl(repr_type& x) { // NOLINT(runtime/references)
|
||||
return &x;
|
||||
}
|
||||
|
||||
static const_pointer_type getImpl(const repr_type& x) { return &x; }
|
||||
};
|
||||
|
||||
} // namespace c10
|
||||
@@ -0,0 +1,96 @@
|
||||
// Copyright (c) 2026 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// The file has been adapted from pytorch project
|
||||
// Licensed under BSD-style license -
|
||||
// https://github.com/pytorch/pytorch/blob/main/LICENSE
|
||||
|
||||
#include <c10/core/Stream.h>
|
||||
|
||||
#ifdef PADDLE_WITH_HIP
|
||||
#include <hip/hip_runtime.h>
|
||||
#elif defined(PADDLE_WITH_CUDA)
|
||||
#include <cuda_runtime.h>
|
||||
#endif
|
||||
|
||||
#include "paddle/common/enforce.h"
|
||||
|
||||
namespace c10 {
|
||||
|
||||
// id_ encodes the raw platform stream handle via reinterpret_cast<StreamId>.
|
||||
// A zero id_ corresponds to the null (default) stream on any backend.
|
||||
// native_handle() reverses that cast to expose the underlying platform handle.
|
||||
void* Stream::native_handle() const {
|
||||
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
|
||||
if (device_type() == DeviceType::CUDA) {
|
||||
return reinterpret_cast<void*>(static_cast<intptr_t>(id_));
|
||||
}
|
||||
#endif
|
||||
#if defined(PADDLE_WITH_XPU)
|
||||
if (device_type() == DeviceType::XPU) {
|
||||
return reinterpret_cast<void*>(static_cast<intptr_t>(id_));
|
||||
}
|
||||
#endif
|
||||
#if defined(PADDLE_WITH_CUSTOM_DEVICE)
|
||||
if (device_type() == DeviceType::CUSTOM) {
|
||||
return reinterpret_cast<void*>(static_cast<intptr_t>(id_));
|
||||
}
|
||||
#endif
|
||||
// Match PyTorch error message format for unsupported device types
|
||||
PD_CHECK(false,
|
||||
"native_handle() is not supported for this device type (",
|
||||
static_cast<int>(device_type()),
|
||||
")");
|
||||
}
|
||||
|
||||
bool Stream::query() const {
|
||||
#if defined(PADDLE_WITH_HIP)
|
||||
if (device_type() == DeviceType::CUDA) {
|
||||
hipStream_t s = reinterpret_cast<hipStream_t>(static_cast<intptr_t>(id_));
|
||||
hipError_t err = hipStreamQuery(s);
|
||||
if (err == hipSuccess) return true;
|
||||
if (err == hipErrorNotReady) return false;
|
||||
PADDLE_ENFORCE_GPU_SUCCESS(err);
|
||||
}
|
||||
#elif defined(PADDLE_WITH_CUDA)
|
||||
if (device_type() == DeviceType::CUDA) {
|
||||
cudaStream_t s = reinterpret_cast<cudaStream_t>(static_cast<intptr_t>(id_));
|
||||
cudaError_t err = cudaStreamQuery(s);
|
||||
if (err == cudaSuccess) return true;
|
||||
if (err == cudaErrorNotReady) return false;
|
||||
PADDLE_ENFORCE_GPU_SUCCESS(err);
|
||||
}
|
||||
#endif
|
||||
// CPU streams are always ready.
|
||||
return true;
|
||||
}
|
||||
|
||||
void Stream::synchronize() const {
|
||||
#if defined(PADDLE_WITH_HIP)
|
||||
if (device_type() == DeviceType::CUDA) {
|
||||
hipStream_t s = reinterpret_cast<hipStream_t>(static_cast<intptr_t>(id_));
|
||||
PADDLE_ENFORCE_GPU_SUCCESS(hipStreamSynchronize(s));
|
||||
return;
|
||||
}
|
||||
#elif defined(PADDLE_WITH_CUDA)
|
||||
if (device_type() == DeviceType::CUDA) {
|
||||
cudaStream_t s = reinterpret_cast<cudaStream_t>(static_cast<intptr_t>(id_));
|
||||
PADDLE_ENFORCE_GPU_SUCCESS(cudaStreamSynchronize(s));
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
// CPU streams: nothing to synchronize.
|
||||
}
|
||||
|
||||
} // namespace c10
|
||||
@@ -0,0 +1,113 @@
|
||||
// Copyright (c) 2026 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <c10/core/Device.h>
|
||||
#include <c10/core/DeviceType.h>
|
||||
#include <c10/util/Exception.h>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <ostream>
|
||||
|
||||
#include "paddle/common/macros.h"
|
||||
|
||||
namespace c10 {
|
||||
|
||||
using StreamId = int64_t;
|
||||
|
||||
struct StreamData3 {
|
||||
StreamId stream_id;
|
||||
DeviceIndex device_index;
|
||||
DeviceType device_type;
|
||||
};
|
||||
|
||||
class PADDLE_API Stream final {
|
||||
private:
|
||||
Device device_;
|
||||
StreamId id_;
|
||||
|
||||
public:
|
||||
enum Unsafe { UNSAFE };
|
||||
enum Default { DEFAULT };
|
||||
|
||||
explicit Stream(Unsafe /*unused*/, Device device, StreamId id)
|
||||
: device_(device), id_(id) {}
|
||||
|
||||
explicit Stream(Default /*unused*/, Device device)
|
||||
: device_(device), id_(0) {}
|
||||
|
||||
bool operator==(const Stream& other) const noexcept {
|
||||
return this->device_ == other.device_ && this->id_ == other.id_;
|
||||
}
|
||||
bool operator!=(const Stream& other) const noexcept {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
Device device() const noexcept { return device_; }
|
||||
DeviceType device_type() const noexcept { return device_.type(); }
|
||||
DeviceIndex device_index() const noexcept { return device_.index(); }
|
||||
StreamId id() const noexcept { return id_; }
|
||||
|
||||
void* native_handle() const;
|
||||
|
||||
template <typename T>
|
||||
void wait(const T& event) const {
|
||||
event.block(*this);
|
||||
}
|
||||
|
||||
bool query() const;
|
||||
|
||||
void synchronize() const;
|
||||
|
||||
uint64_t hash() const noexcept {
|
||||
uint64_t bits = static_cast<uint64_t>(device_type()) << 56 |
|
||||
static_cast<uint64_t>(device_index()) << 48 |
|
||||
(static_cast<uint64_t>(id()) & ((1ull << 48) - 1));
|
||||
return bits;
|
||||
}
|
||||
|
||||
struct StreamData3 pack3() const {
|
||||
return {id(), device_index(), device_type()};
|
||||
}
|
||||
|
||||
static Stream unpack3(StreamId stream_id,
|
||||
DeviceIndex device_index,
|
||||
DeviceType device_type) {
|
||||
PD_CHECK(isValidDeviceType(device_type));
|
||||
return Stream(UNSAFE, Device(device_type, device_index), stream_id);
|
||||
}
|
||||
};
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& os, const Stream& s) {
|
||||
// Format: "stream {id} on device {device_type}:{device_index}"
|
||||
os << "stream " << s.id() << " on device " << s.device();
|
||||
return os;
|
||||
}
|
||||
|
||||
} // namespace c10
|
||||
|
||||
namespace std {
|
||||
template <>
|
||||
struct hash<c10::Stream> {
|
||||
size_t operator()(const c10::Stream& s) const noexcept {
|
||||
return std::hash<uint64_t>{}(s.hash());
|
||||
}
|
||||
};
|
||||
} // namespace std
|
||||
|
||||
namespace at {
|
||||
using c10::Stream;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
#include <c10/util/accumulate.h>
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
|
||||
namespace c10 {
|
||||
|
||||
class SymInt {
|
||||
public:
|
||||
SymInt() : data_(0) {}
|
||||
/*implicit*/ SymInt(int64_t d) : data_(d) {} // NOLINT
|
||||
/*implicit*/ operator int64_t() const { return data_; }
|
||||
|
||||
int64_t guard_int(const char* file, int64_t line) const {
|
||||
(void)file;
|
||||
(void)line;
|
||||
return data_;
|
||||
}
|
||||
|
||||
std::optional<int64_t> maybe_as_int() const { return data_; }
|
||||
|
||||
private:
|
||||
int64_t data_;
|
||||
};
|
||||
|
||||
} // namespace c10
|
||||
@@ -0,0 +1,29 @@
|
||||
// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <c10/core/SymInt.h>
|
||||
#include <c10/util/ArrayRef.h>
|
||||
|
||||
namespace c10 {
|
||||
using SymIntArrayRef = ArrayRef<SymInt>;
|
||||
} // namespace c10
|
||||
|
||||
namespace at {
|
||||
using c10::SymIntArrayRef;
|
||||
} // namespace at
|
||||
namespace torch {
|
||||
using c10::SymIntArrayRef;
|
||||
} // namespace torch
|
||||
@@ -0,0 +1,26 @@
|
||||
// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace c10 {
|
||||
using SymFloat = double;
|
||||
} // namespace c10
|
||||
|
||||
namespace at {
|
||||
using c10::SymFloat;
|
||||
} // namespace at
|
||||
namespace torch {
|
||||
using c10::SymFloat;
|
||||
} // namespace torch
|
||||
@@ -0,0 +1,375 @@
|
||||
// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// The file has been adapted from pytorch project
|
||||
// Licensed under BSD-style license -
|
||||
// https://github.com/pytorch/pytorch/blob/main/LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <c10/core/DefaultDtype.h>
|
||||
#include <c10/core/Device.h>
|
||||
#include <c10/core/Layout.h>
|
||||
#include <c10/core/MemoryFormat.h>
|
||||
#include <c10/core/ScalarType.h>
|
||||
#include <c10/core/ScalarTypeToTypeMeta.h>
|
||||
#include <c10/util/typeid.h>
|
||||
#include <optional>
|
||||
|
||||
#include "paddle/common/macros.h"
|
||||
#include "paddle/phi/common/place.h"
|
||||
|
||||
namespace c10 {
|
||||
inline Layout layout_or_default(std::optional<Layout> layout) {
|
||||
return layout.value_or(kStrided);
|
||||
}
|
||||
|
||||
inline Device device_or_default(std::optional<Device> device) {
|
||||
return device.value_or(Device(kCPU));
|
||||
}
|
||||
inline caffe2::TypeMeta dtype_or_default(
|
||||
std::optional<caffe2::TypeMeta> dtype) {
|
||||
return dtype.value_or(get_default_dtype());
|
||||
}
|
||||
|
||||
// legacy overload
|
||||
inline ScalarType dtype_or_default(std::optional<ScalarType> dtype) {
|
||||
return dtype.value_or(get_default_dtype_as_scalartype());
|
||||
}
|
||||
|
||||
inline bool pinned_memory_or_default(std::optional<bool> pinned_memory) {
|
||||
return pinned_memory.value_or(false);
|
||||
}
|
||||
|
||||
struct PADDLE_API TensorOptions {
|
||||
TensorOptions()
|
||||
: requires_grad_(false),
|
||||
pinned_memory_(false),
|
||||
has_device_(false),
|
||||
has_dtype_(false),
|
||||
has_layout_(false),
|
||||
has_requires_grad_(false),
|
||||
has_pinned_memory_(false),
|
||||
has_memory_format_(false) {}
|
||||
|
||||
/* implicit */ explicit TensorOptions(Layout layout) // NOLINT
|
||||
: TensorOptions() {
|
||||
this->set_layout(layout);
|
||||
}
|
||||
|
||||
template <
|
||||
typename T,
|
||||
typename = std::enable_if_t<std::is_same_v<std::decay_t<T>, Device>>>
|
||||
/* implicit */ explicit TensorOptions(T&& device) // NOLINT
|
||||
: TensorOptions() {
|
||||
this->set_device(std::forward<T>(device));
|
||||
}
|
||||
|
||||
template <
|
||||
typename... Args,
|
||||
typename = std::enable_if_t<std::is_constructible_v<Device, Args&&...>>>
|
||||
/* implicit */ TensorOptions(Args&&... args) // NOLINT
|
||||
: TensorOptions(Device(std::forward<Args>(args)...)) {}
|
||||
|
||||
/* implicit */ TensorOptions(caffe2::TypeMeta dtype) // NOLINT
|
||||
: TensorOptions() {
|
||||
this->set_dtype(dtype);
|
||||
}
|
||||
|
||||
// legacy constructor to support ScalarType
|
||||
/* implicit */ TensorOptions(c10::ScalarType dtype) // NOLINT
|
||||
: TensorOptions() {
|
||||
this->set_dtype(dtype);
|
||||
}
|
||||
|
||||
/* implicit */ TensorOptions(MemoryFormat memory_format) // NOLINT
|
||||
: TensorOptions() {
|
||||
set_memory_format(memory_format);
|
||||
}
|
||||
|
||||
[[nodiscard]] TensorOptions device(
|
||||
std::optional<Device> device) const noexcept {
|
||||
TensorOptions r = *this;
|
||||
r.set_device(device);
|
||||
return r;
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
[[nodiscard]] TensorOptions device(Args&&... args) const noexcept {
|
||||
return device(
|
||||
std::optional<Device>(std::in_place, std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
[[nodiscard]] TensorOptions device_index(
|
||||
c10::DeviceIndex device_index) const noexcept {
|
||||
return device(Device(kCUDA, device_index));
|
||||
}
|
||||
|
||||
[[nodiscard]] TensorOptions dtype(
|
||||
std::optional<caffe2::TypeMeta> dtype) const noexcept {
|
||||
TensorOptions r = *this;
|
||||
r.set_dtype(dtype);
|
||||
return r;
|
||||
}
|
||||
|
||||
// legacy overload to support ScalarType
|
||||
[[nodiscard]] TensorOptions dtype(
|
||||
std::optional<ScalarType> dtype) const noexcept {
|
||||
TensorOptions r = *this;
|
||||
r.set_dtype(dtype);
|
||||
return r;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
TensorOptions& dtype() {
|
||||
dtype_ = caffe2::TypeMeta::Make<T>();
|
||||
has_dtype_ = true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]] TensorOptions layout(
|
||||
std::optional<Layout> layout) const noexcept {
|
||||
TensorOptions r = *this;
|
||||
r.set_layout(layout);
|
||||
return r;
|
||||
}
|
||||
|
||||
[[nodiscard]] TensorOptions requires_grad(
|
||||
std::optional<bool> requires_grad) const noexcept {
|
||||
TensorOptions r = *this;
|
||||
r.set_requires_grad(requires_grad);
|
||||
return r;
|
||||
}
|
||||
|
||||
[[nodiscard]] TensorOptions pinned_memory(
|
||||
std::optional<bool> pinned_memory) const noexcept {
|
||||
TensorOptions r = *this;
|
||||
r.set_pinned_memory(pinned_memory);
|
||||
return r;
|
||||
}
|
||||
|
||||
[[nodiscard]] TensorOptions memory_format(
|
||||
std::optional<MemoryFormat> memory_format) const noexcept {
|
||||
TensorOptions r = *this;
|
||||
r.set_memory_format(memory_format);
|
||||
return r;
|
||||
}
|
||||
|
||||
Device device() const noexcept { return device_or_default(device_opt()); }
|
||||
|
||||
bool has_device() const noexcept { return has_device_; }
|
||||
|
||||
std::optional<Device> device_opt() const noexcept {
|
||||
return has_device_ ? std::make_optional(device_) : std::nullopt;
|
||||
}
|
||||
|
||||
c10::DeviceIndex device_index() const noexcept { return device().index(); }
|
||||
|
||||
caffe2::TypeMeta dtype() const noexcept {
|
||||
return dtype_or_default(dtype_opt());
|
||||
}
|
||||
|
||||
bool has_dtype() const noexcept { return has_dtype_; }
|
||||
|
||||
std::optional<caffe2::TypeMeta> dtype_opt() const noexcept {
|
||||
return has_dtype_ ? std::make_optional(dtype_) : std::nullopt;
|
||||
}
|
||||
|
||||
Layout layout() const noexcept { return layout_or_default(layout_opt()); }
|
||||
|
||||
bool has_layout() const noexcept { return has_layout_; }
|
||||
|
||||
std::optional<Layout> layout_opt() const noexcept {
|
||||
return has_layout_ ? std::make_optional(layout_) : std::nullopt;
|
||||
}
|
||||
|
||||
bool requires_grad() const noexcept {
|
||||
return has_requires_grad_ ? requires_grad_ : false;
|
||||
}
|
||||
|
||||
bool has_requires_grad() const noexcept { return has_requires_grad_; }
|
||||
|
||||
std::optional<bool> requires_grad_opt() const noexcept {
|
||||
return has_requires_grad_ ? std::make_optional(requires_grad_)
|
||||
: std::nullopt;
|
||||
}
|
||||
|
||||
bool pinned_memory() const noexcept {
|
||||
return pinned_memory_or_default(pinned_memory_opt());
|
||||
}
|
||||
|
||||
bool has_pinned_memory() const noexcept { return has_pinned_memory_; }
|
||||
|
||||
bool is_sparse() const { return layout_ == c10::Layout::Sparse; }
|
||||
|
||||
bool is_sparse_csr() const { return layout_ == c10::Layout::SparseCsr; }
|
||||
|
||||
bool is_sparse_compressed() const {
|
||||
return layout_ == c10::Layout::SparseCsr ||
|
||||
layout_ == c10::Layout::SparseCsc ||
|
||||
layout_ == c10::Layout::SparseBsr ||
|
||||
layout_ == c10::Layout::SparseBsc;
|
||||
}
|
||||
|
||||
std::optional<bool> pinned_memory_opt() const noexcept {
|
||||
return has_pinned_memory_ ? std::make_optional(pinned_memory_)
|
||||
: std::nullopt;
|
||||
}
|
||||
|
||||
bool has_memory_format() const noexcept { return has_memory_format_; }
|
||||
|
||||
std::optional<MemoryFormat> memory_format_opt() const noexcept {
|
||||
return has_memory_format_ ? std::make_optional(memory_format_)
|
||||
: std::nullopt;
|
||||
}
|
||||
|
||||
TensorOptions merge_memory_format(
|
||||
std::optional<MemoryFormat> optional_memory_format) const noexcept {
|
||||
TensorOptions merged = *this;
|
||||
if (optional_memory_format.has_value()) {
|
||||
merged.set_memory_format(optional_memory_format);
|
||||
}
|
||||
return merged;
|
||||
}
|
||||
|
||||
::phi::Place _PD_GetPlace() const { return device_._PD_GetInner(); }
|
||||
|
||||
private:
|
||||
void set_device(std::optional<Device> device) & noexcept {
|
||||
if (device) {
|
||||
device_ = *device;
|
||||
has_device_ = true;
|
||||
} else {
|
||||
has_device_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
void set_dtype(std::optional<caffe2::TypeMeta> dtype) & noexcept {
|
||||
if (dtype) {
|
||||
dtype_ = *dtype;
|
||||
has_dtype_ = true;
|
||||
} else {
|
||||
has_dtype_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
// legacy overload to support ScalarType
|
||||
void set_dtype(std::optional<ScalarType> dtype) & noexcept {
|
||||
if (dtype) {
|
||||
dtype_ = scalarTypeToTypeMeta(*dtype);
|
||||
has_dtype_ = true;
|
||||
} else {
|
||||
has_dtype_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
void set_layout(std::optional<Layout> layout) & noexcept {
|
||||
if (layout) {
|
||||
layout_ = *layout;
|
||||
has_layout_ = true;
|
||||
} else {
|
||||
has_layout_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
void set_requires_grad(std::optional<bool> requires_grad) & noexcept {
|
||||
if (requires_grad) {
|
||||
requires_grad_ = *requires_grad;
|
||||
has_requires_grad_ = true;
|
||||
} else {
|
||||
has_requires_grad_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
void set_pinned_memory(std::optional<bool> pinned_memory) & noexcept {
|
||||
if (pinned_memory) {
|
||||
pinned_memory_ = *pinned_memory;
|
||||
has_pinned_memory_ = true;
|
||||
} else {
|
||||
has_pinned_memory_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
void set_memory_format(std::optional<MemoryFormat> memory_format) & noexcept {
|
||||
if (memory_format) {
|
||||
memory_format_ = *memory_format;
|
||||
has_memory_format_ = true;
|
||||
} else {
|
||||
has_memory_format_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
Device device_ = c10::kCPU;
|
||||
caffe2::TypeMeta dtype_ = caffe2::TypeMeta::Make<float>(); // 16-bit
|
||||
Layout layout_ = at::kStrided; // 8-bit
|
||||
MemoryFormat memory_format_ = MemoryFormat::Contiguous; // 8-bit
|
||||
|
||||
bool requires_grad_ : 1;
|
||||
bool pinned_memory_ : 1;
|
||||
|
||||
bool has_device_ : 1;
|
||||
bool has_dtype_ : 1;
|
||||
bool has_layout_ : 1;
|
||||
bool has_requires_grad_ : 1;
|
||||
bool has_pinned_memory_ : 1;
|
||||
bool has_memory_format_ : 1;
|
||||
};
|
||||
|
||||
inline TensorOptions dtype(caffe2::TypeMeta dtype) {
|
||||
return TensorOptions().dtype(dtype);
|
||||
}
|
||||
|
||||
// legacy overload
|
||||
inline TensorOptions dtype(ScalarType dtype) {
|
||||
return TensorOptions().dtype(scalarTypeToTypeMeta(dtype));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline TensorOptions dtype() {
|
||||
return dtype(caffe2::TypeMeta::Make<T>());
|
||||
}
|
||||
|
||||
inline TensorOptions layout(Layout layout) {
|
||||
return TensorOptions().layout(layout);
|
||||
}
|
||||
|
||||
inline TensorOptions device(Device device) {
|
||||
return TensorOptions().device(device);
|
||||
}
|
||||
|
||||
inline TensorOptions device_index(c10::DeviceIndex device_index) {
|
||||
return TensorOptions().device_index(device_index);
|
||||
}
|
||||
|
||||
inline TensorOptions requires_grad(bool requires_grad = true) {
|
||||
return TensorOptions().requires_grad(requires_grad);
|
||||
}
|
||||
|
||||
inline TensorOptions memory_format(MemoryFormat memory_format) {
|
||||
return TensorOptions().memory_format(memory_format);
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& stream, const TensorOptions& options);
|
||||
|
||||
inline std::string toString(const TensorOptions& options) {
|
||||
std::ostringstream stream;
|
||||
stream << options;
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
} // namespace c10
|
||||
|
||||
namespace at {
|
||||
using namespace c10; // NOLINT
|
||||
} // namespace at
|
||||
@@ -0,0 +1,61 @@
|
||||
// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <exception>
|
||||
#include <string>
|
||||
|
||||
#if defined(PADDLE_WITH_HIP)
|
||||
#include <hip/hip_runtime.h>
|
||||
#elif defined(PADDLE_WITH_CUDA)
|
||||
#include <cuda_runtime.h>
|
||||
#endif
|
||||
|
||||
class CompatException : public std::exception {
|
||||
private:
|
||||
std::string message = {};
|
||||
|
||||
public:
|
||||
explicit CompatException(const char* name,
|
||||
const char* file,
|
||||
const int line,
|
||||
const std::string& error) {
|
||||
message = std::string("Failed: ") + name + " error " + file + ":" +
|
||||
std::to_string(line) + " '" + error + "'";
|
||||
}
|
||||
|
||||
const char* what() const noexcept override { return message.c_str(); }
|
||||
};
|
||||
|
||||
#ifndef C10_CUDA_CHECK
|
||||
#if defined(PADDLE_WITH_HIP)
|
||||
#define C10_CUDA_CHECK(cmd) \
|
||||
do { \
|
||||
hipError_t e = (cmd); \
|
||||
if (e != hipSuccess) { \
|
||||
throw CompatException("HIP", __FILE__, __LINE__, hipGetErrorString(e)); \
|
||||
} \
|
||||
} while (0)
|
||||
#elif defined(PADDLE_WITH_CUDA)
|
||||
#define C10_CUDA_CHECK(cmd) \
|
||||
do { \
|
||||
cudaError_t e = (cmd); \
|
||||
if (e != cudaSuccess) { \
|
||||
throw CompatException( \
|
||||
"CUDA", __FILE__, __LINE__, cudaGetErrorString(e)); \
|
||||
} \
|
||||
} while (0)
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,48 @@
|
||||
// Copyright (c) 2026 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// The file has been adapted from pytorch project
|
||||
// Licensed under BSD-style license -
|
||||
// https://github.com/pytorch/pytorch/blob/main/LICENSE
|
||||
|
||||
#include <c10/cuda/CUDAFunctions.h>
|
||||
|
||||
namespace c10::cuda {
|
||||
|
||||
c10::DeviceIndex device_count() {
|
||||
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
|
||||
return phi::backends::gpu::GetGPUDeviceCount();
|
||||
#else
|
||||
// Return 0 instead of throwing to match PyTorch API semantics
|
||||
// at::cuda::is_available() relies on this returning 0/false
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void device_synchronize() {
|
||||
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
|
||||
int curr_device_id = paddle::platform::GetCurrentDeviceId();
|
||||
paddle::platform::SetDeviceId(curr_device_id);
|
||||
#ifdef PADDLE_WITH_HIP
|
||||
PADDLE_ENFORCE_GPU_SUCCESS(hipDeviceSynchronize());
|
||||
#else
|
||||
PADDLE_ENFORCE_GPU_SUCCESS(cudaDeviceSynchronize());
|
||||
#endif
|
||||
#else
|
||||
PADDLE_THROW(common::errors::Unavailable(
|
||||
"Paddle is not compiled with CUDA. Cannot visit device synchronize."));
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace c10::cuda
|
||||
@@ -0,0 +1,38 @@
|
||||
// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <c10/core/Device.h>
|
||||
|
||||
namespace c10::cuda {
|
||||
|
||||
PADDLE_API c10::DeviceIndex device_count();
|
||||
|
||||
PADDLE_API void device_synchronize();
|
||||
|
||||
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
|
||||
void __inline__ stream_synchronize(gpuStream_t stream) {
|
||||
phi::backends::gpu::GpuStreamSync(stream);
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace c10::cuda
|
||||
|
||||
namespace at::cuda {
|
||||
using c10::cuda::device_synchronize;
|
||||
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
|
||||
using c10::cuda::stream_synchronize;
|
||||
#endif
|
||||
} // namespace at::cuda
|
||||
@@ -0,0 +1,169 @@
|
||||
// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// The file has been adapted from pytorch project
|
||||
// Licensed under BSD-style license -
|
||||
// https://github.com/pytorch/pytorch/blob/main/LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <c10/core/Device.h>
|
||||
#include <c10/util/Exception.h>
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include "paddle/phi/backends/gpu/gpu_info.h"
|
||||
|
||||
namespace c10::cuda {
|
||||
|
||||
namespace detail {
|
||||
|
||||
inline Device current_cuda_device() {
|
||||
return Device(kCUDA, phi::backends::gpu::GetCurrentDeviceId());
|
||||
}
|
||||
|
||||
inline Device normalize_cuda_device(Device device) {
|
||||
TORCH_CHECK(device.is_cuda(), "Expected a CUDA device, but got ", device);
|
||||
return device.has_index() ? Device(kCUDA, device.index())
|
||||
: current_cuda_device();
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
struct CUDAGuard {
|
||||
explicit CUDAGuard() = delete; // NOLINT
|
||||
|
||||
explicit CUDAGuard(DeviceIndex device_index)
|
||||
: original_device_(detail::current_cuda_device()),
|
||||
current_device_(original_device_) {
|
||||
set_index(device_index);
|
||||
}
|
||||
|
||||
explicit CUDAGuard(Device device)
|
||||
: original_device_(detail::current_cuda_device()),
|
||||
current_device_(original_device_) {
|
||||
set_device(device);
|
||||
}
|
||||
|
||||
CUDAGuard(const CUDAGuard&) = delete;
|
||||
CUDAGuard& operator=(const CUDAGuard&) = delete;
|
||||
|
||||
CUDAGuard(CUDAGuard&& other) = delete;
|
||||
CUDAGuard& operator=(CUDAGuard&& other) = delete;
|
||||
~CUDAGuard() {
|
||||
// Always restore to original_device_ to handle cases where the device
|
||||
// was changed outside of this guard, matching PyTorch semantics.
|
||||
phi::backends::gpu::SetDeviceId(static_cast<int>(original_device_.index()));
|
||||
}
|
||||
|
||||
void set_device(Device device) {
|
||||
const Device normalized = detail::normalize_cuda_device(device);
|
||||
if (normalized.index() != current_device_.index()) {
|
||||
phi::backends::gpu::SetDeviceId(static_cast<int>(normalized.index()));
|
||||
current_device_ = normalized;
|
||||
}
|
||||
}
|
||||
|
||||
void reset_device(Device device) { set_device(device); }
|
||||
|
||||
void set_index(DeviceIndex device_index) {
|
||||
if (current_device_.index() != device_index) {
|
||||
phi::backends::gpu::SetDeviceId(static_cast<int>(device_index));
|
||||
current_device_ = Device(kCUDA, device_index);
|
||||
}
|
||||
}
|
||||
|
||||
Device original_device() const { return original_device_; }
|
||||
|
||||
Device current_device() const { return current_device_; }
|
||||
|
||||
private:
|
||||
Device original_device_;
|
||||
Device current_device_;
|
||||
};
|
||||
|
||||
struct OptionalCUDAGuard {
|
||||
OptionalCUDAGuard() = default;
|
||||
|
||||
explicit OptionalCUDAGuard(std::optional<Device> device_opt) {
|
||||
if (device_opt.has_value()) {
|
||||
set_device(device_opt.value());
|
||||
}
|
||||
}
|
||||
|
||||
explicit OptionalCUDAGuard(std::optional<DeviceIndex> device_index_opt) {
|
||||
if (device_index_opt.has_value()) {
|
||||
set_index(device_index_opt.value());
|
||||
}
|
||||
}
|
||||
|
||||
OptionalCUDAGuard(const OptionalCUDAGuard&) = delete;
|
||||
OptionalCUDAGuard& operator=(const OptionalCUDAGuard&) = delete;
|
||||
|
||||
OptionalCUDAGuard(OptionalCUDAGuard&& other) = delete;
|
||||
OptionalCUDAGuard& operator=(OptionalCUDAGuard&& other) = delete;
|
||||
~OptionalCUDAGuard() { reset(); }
|
||||
|
||||
void set_device(Device device) {
|
||||
const Device normalized = detail::normalize_cuda_device(device);
|
||||
init_if_needed();
|
||||
if (normalized.index() != current_device_->index()) {
|
||||
phi::backends::gpu::SetDeviceId(static_cast<int>(normalized.index()));
|
||||
}
|
||||
current_device_ = normalized;
|
||||
}
|
||||
|
||||
void reset_device(Device device) { set_device(device); }
|
||||
|
||||
void set_index(DeviceIndex device_index) {
|
||||
init_if_needed();
|
||||
if (device_index != current_device_->index()) {
|
||||
phi::backends::gpu::SetDeviceId(static_cast<int>(device_index));
|
||||
}
|
||||
current_device_ = Device(kCUDA, device_index);
|
||||
}
|
||||
|
||||
std::optional<Device> original_device() const { return original_device_; }
|
||||
|
||||
std::optional<Device> current_device() const { return current_device_; }
|
||||
|
||||
void reset() {
|
||||
if (original_device_.has_value()) {
|
||||
// Always restore to original_device_ to handle external device changes.
|
||||
// This matches PyTorch OptionalDeviceGuard semantics.
|
||||
phi::backends::gpu::SetDeviceId(
|
||||
static_cast<int>(original_device_->index()));
|
||||
}
|
||||
original_device_.reset();
|
||||
current_device_.reset();
|
||||
}
|
||||
|
||||
private:
|
||||
void init_if_needed() {
|
||||
if (!original_device_.has_value()) {
|
||||
original_device_ = detail::current_cuda_device();
|
||||
current_device_ = original_device_;
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<Device> original_device_;
|
||||
std::optional<Device> current_device_;
|
||||
};
|
||||
|
||||
} // namespace c10::cuda
|
||||
|
||||
namespace at::cuda {
|
||||
using c10::cuda::CUDAGuard;
|
||||
using c10::cuda::OptionalCUDAGuard;
|
||||
} // namespace at::cuda
|
||||
@@ -0,0 +1,239 @@
|
||||
// Copyright (c) 2026 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// 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.
|
||||
|
||||
#include <c10/cuda/CUDAStream.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
#include "paddle/phi/api/include/context_pool.h"
|
||||
#include "paddle/phi/backends/gpu/gpu_context.h"
|
||||
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
|
||||
#include "paddle/phi/backends/gpu/gpu_info.h"
|
||||
#endif
|
||||
|
||||
namespace c10::cuda {
|
||||
|
||||
namespace {
|
||||
|
||||
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
|
||||
|
||||
constexpr int kStreamsPerPool = 32;
|
||||
|
||||
std::once_flag g_init_once;
|
||||
c10::DeviceIndex g_num_gpus = -1;
|
||||
|
||||
struct DevicePools {
|
||||
#ifdef PADDLE_WITH_HIP
|
||||
std::vector<hipStream_t> low_priority;
|
||||
std::vector<hipStream_t> high_priority;
|
||||
#else
|
||||
std::vector<cudaStream_t> low_priority;
|
||||
std::vector<cudaStream_t> high_priority;
|
||||
#endif
|
||||
std::atomic<uint32_t> lp_counter{0};
|
||||
std::atomic<uint32_t> hp_counter{0};
|
||||
std::once_flag init_flag;
|
||||
};
|
||||
|
||||
std::vector<std::unique_ptr<DevicePools>> g_pools;
|
||||
|
||||
void initGlobalState() {
|
||||
std::call_once(g_init_once, []() {
|
||||
g_num_gpus =
|
||||
static_cast<c10::DeviceIndex>(phi::backends::gpu::GetGPUDeviceCount());
|
||||
g_pools.resize(g_num_gpus);
|
||||
for (auto& ptr : g_pools) {
|
||||
ptr = std::make_unique<DevicePools>();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void initDevicePools(c10::DeviceIndex device_index) {
|
||||
phi::backends::gpu::GPUDeviceGuard guard(device_index);
|
||||
int lo_pri = 0, hi_pri = 0;
|
||||
#ifdef PADDLE_WITH_HIP
|
||||
C10_CUDA_CHECK(hipDeviceGetStreamPriorityRange(&lo_pri, &hi_pri));
|
||||
#else
|
||||
C10_CUDA_CHECK(cudaDeviceGetStreamPriorityRange(&lo_pri, &hi_pri));
|
||||
#endif
|
||||
|
||||
auto& pool = *g_pools[device_index];
|
||||
pool.low_priority.resize(kStreamsPerPool);
|
||||
pool.high_priority.resize(kStreamsPerPool);
|
||||
|
||||
for (int i = 0; i < kStreamsPerPool; ++i) {
|
||||
#ifdef PADDLE_WITH_HIP
|
||||
C10_CUDA_CHECK(hipStreamCreateWithPriority(
|
||||
&pool.low_priority[i], hipStreamNonBlocking, lo_pri));
|
||||
C10_CUDA_CHECK(hipStreamCreateWithPriority(
|
||||
&pool.high_priority[i], hipStreamNonBlocking, hi_pri));
|
||||
#else
|
||||
C10_CUDA_CHECK(cudaStreamCreateWithPriority(
|
||||
&pool.low_priority[i], cudaStreamNonBlocking, lo_pri));
|
||||
C10_CUDA_CHECK(cudaStreamCreateWithPriority(
|
||||
&pool.high_priority[i], cudaStreamNonBlocking, hi_pri));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
inline void check_gpu(c10::DeviceIndex device_index) {
|
||||
TORCH_CHECK(device_index >= 0 && device_index < g_num_gpus,
|
||||
"Device index value ",
|
||||
static_cast<int>(device_index),
|
||||
" is out of index range [0, ",
|
||||
static_cast<int>(g_num_gpus),
|
||||
")");
|
||||
}
|
||||
|
||||
inline phi::GPUContext* getMutableGPUContext(c10::DeviceIndex device_index) {
|
||||
return static_cast<phi::GPUContext*>(
|
||||
paddle::experimental::DeviceContextPool::Instance().GetMutable(
|
||||
phi::GPUPlace(device_index)));
|
||||
}
|
||||
|
||||
#ifdef PADDLE_WITH_HIP
|
||||
inline hipStream_t getPaddleCurrentStream(c10::DeviceIndex device_index) {
|
||||
auto* current_stream =
|
||||
paddle::GetCurrentCUDAStream(phi::GPUPlace(device_index));
|
||||
return current_stream == nullptr ? nullptr : current_stream->raw_stream();
|
||||
}
|
||||
#else
|
||||
inline cudaStream_t getPaddleCurrentStream(c10::DeviceIndex device_index) {
|
||||
auto* current_stream =
|
||||
paddle::GetCurrentCUDAStream(phi::GPUPlace(device_index));
|
||||
return current_stream == nullptr ? nullptr : current_stream->raw_stream();
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
|
||||
|
||||
} // namespace
|
||||
|
||||
#ifdef PADDLE_WITH_HIP
|
||||
inline CUDAStream make_cuda_stream(hipStream_t raw,
|
||||
c10::DeviceIndex device_index) {
|
||||
#else
|
||||
inline CUDAStream make_cuda_stream(cudaStream_t raw,
|
||||
c10::DeviceIndex device_index) {
|
||||
#endif
|
||||
c10::StreamId sid =
|
||||
static_cast<c10::StreamId>(reinterpret_cast<intptr_t>(raw));
|
||||
return CUDAStream(
|
||||
c10::Stream(c10::Stream::UNSAFE,
|
||||
c10::Device(c10::DeviceType::CUDA, device_index),
|
||||
sid));
|
||||
}
|
||||
|
||||
CUDAStream getStreamFromPool(const int priority,
|
||||
c10::DeviceIndex device_index) {
|
||||
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
|
||||
initGlobalState();
|
||||
if (device_index == -1) {
|
||||
device_index =
|
||||
static_cast<c10::DeviceIndex>(phi::backends::gpu::GetCurrentDeviceId());
|
||||
}
|
||||
check_gpu(device_index);
|
||||
|
||||
std::call_once(
|
||||
g_pools[device_index]->init_flag, initDevicePools, device_index);
|
||||
|
||||
const uint32_t idx = (priority < 0 ? g_pools[device_index]->hp_counter++
|
||||
: g_pools[device_index]->lp_counter++) %
|
||||
kStreamsPerPool;
|
||||
#ifdef PADDLE_WITH_HIP
|
||||
hipStream_t raw = (priority < 0 ? g_pools[device_index]->high_priority[idx]
|
||||
: g_pools[device_index]->low_priority[idx]);
|
||||
#else
|
||||
cudaStream_t raw = (priority < 0 ? g_pools[device_index]->high_priority[idx]
|
||||
: g_pools[device_index]->low_priority[idx]);
|
||||
#endif
|
||||
|
||||
return make_cuda_stream(raw, device_index);
|
||||
#else
|
||||
TORCH_CHECK(false, "getStreamFromPool is not supported without CUDA/HIP");
|
||||
return getDefaultCUDAStream(device_index);
|
||||
#endif
|
||||
}
|
||||
|
||||
CUDAStream getStreamFromPool(const bool isHighPriority,
|
||||
c10::DeviceIndex device_index) {
|
||||
return getStreamFromPool(isHighPriority ? -1 : 0, device_index);
|
||||
}
|
||||
|
||||
#ifdef PADDLE_WITH_HIP
|
||||
CUDAStream getStreamFromExternal(hipStream_t ext_stream,
|
||||
c10::DeviceIndex device_index) {
|
||||
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
|
||||
initGlobalState();
|
||||
check_gpu(device_index);
|
||||
#endif
|
||||
return make_cuda_stream(ext_stream, device_index);
|
||||
}
|
||||
#else
|
||||
CUDAStream getStreamFromExternal(cudaStream_t ext_stream,
|
||||
c10::DeviceIndex device_index) {
|
||||
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
|
||||
initGlobalState();
|
||||
check_gpu(device_index);
|
||||
#endif
|
||||
return make_cuda_stream(ext_stream, device_index);
|
||||
}
|
||||
#endif
|
||||
|
||||
CUDAStream getDefaultCUDAStream(c10::DeviceIndex device_index) {
|
||||
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
|
||||
initGlobalState();
|
||||
if (device_index == -1) {
|
||||
device_index =
|
||||
static_cast<c10::DeviceIndex>(phi::backends::gpu::GetCurrentDeviceId());
|
||||
}
|
||||
check_gpu(device_index);
|
||||
#endif
|
||||
return CUDAStream(c10::Stream(
|
||||
c10::Stream::DEFAULT, c10::Device(c10::DeviceType::CUDA, device_index)));
|
||||
}
|
||||
|
||||
CUDAStream getCurrentCUDAStream(c10::DeviceIndex device_index) {
|
||||
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
|
||||
initGlobalState();
|
||||
if (device_index == -1) {
|
||||
device_index =
|
||||
static_cast<c10::DeviceIndex>(phi::backends::gpu::GetCurrentDeviceId());
|
||||
}
|
||||
check_gpu(device_index);
|
||||
auto raw = getPaddleCurrentStream(device_index);
|
||||
if (raw == nullptr) {
|
||||
return getDefaultCUDAStream(device_index);
|
||||
}
|
||||
return make_cuda_stream(raw, device_index);
|
||||
#else
|
||||
return getDefaultCUDAStream(device_index);
|
||||
#endif
|
||||
}
|
||||
|
||||
void setCurrentCUDAStream(CUDAStream stream) {
|
||||
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
|
||||
initGlobalState();
|
||||
c10::DeviceIndex idx = stream.unwrap().device_index();
|
||||
check_gpu(idx);
|
||||
getMutableGPUContext(idx)->SetStream(stream.stream());
|
||||
#else
|
||||
(void)stream;
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace c10::cuda
|
||||
@@ -0,0 +1,198 @@
|
||||
// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// The file has been adapted from pytorch project
|
||||
// Licensed under BSD-style license -
|
||||
// https://github.com/pytorch/pytorch/blob/main/LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <c10/core/Device.h>
|
||||
#include <c10/core/Stream.h>
|
||||
#include <c10/cuda/CUDAException.h>
|
||||
|
||||
#include <ostream>
|
||||
|
||||
#include "paddle/common/macros.h"
|
||||
#include "paddle/phi/backends/gpu/gpu_info.h"
|
||||
#include "paddle/phi/common/place.h"
|
||||
|
||||
namespace c10::cuda {
|
||||
|
||||
using StreamId = int64_t;
|
||||
|
||||
static constexpr int max_compile_time_stream_priorities = 4;
|
||||
|
||||
class CUDAStream {
|
||||
public:
|
||||
enum Unchecked { UNCHECKED };
|
||||
|
||||
CUDAStream() = delete;
|
||||
|
||||
explicit CUDAStream(Stream stream) : stream_(stream) {
|
||||
TORCH_CHECK(stream_.device_type() == DeviceType::CUDA);
|
||||
}
|
||||
|
||||
explicit CUDAStream(Unchecked /*unused*/, Stream stream) : stream_(stream) {}
|
||||
|
||||
bool operator==(const CUDAStream& other) const noexcept {
|
||||
return unwrap() == other.unwrap();
|
||||
}
|
||||
|
||||
bool operator!=(const CUDAStream& other) const noexcept {
|
||||
return unwrap() != other.unwrap();
|
||||
}
|
||||
|
||||
StreamId id() const { return stream_.id(); }
|
||||
|
||||
#ifdef PADDLE_WITH_HIP
|
||||
operator hipStream_t() const { return stream(); }
|
||||
#else
|
||||
operator cudaStream_t() const { return stream(); }
|
||||
#endif
|
||||
|
||||
operator Stream() const { return unwrap(); }
|
||||
|
||||
bool query() const { return unwrap().query(); }
|
||||
|
||||
void synchronize() const { unwrap().synchronize(); }
|
||||
|
||||
int priority() const {
|
||||
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
|
||||
phi::backends::gpu::GPUDeviceGuard guard(device_index());
|
||||
int priority = 0;
|
||||
#ifdef PADDLE_WITH_HIP
|
||||
C10_CUDA_CHECK(hipStreamGetPriority(stream(), &priority));
|
||||
#else
|
||||
C10_CUDA_CHECK(cudaStreamGetPriority(stream(), &priority));
|
||||
#endif
|
||||
return priority;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef PADDLE_WITH_HIP
|
||||
hipStream_t stream() const {
|
||||
return reinterpret_cast<hipStream_t>(stream_.id());
|
||||
}
|
||||
#else
|
||||
cudaStream_t stream() const {
|
||||
return reinterpret_cast<cudaStream_t>(stream_.id());
|
||||
}
|
||||
#endif
|
||||
|
||||
Stream unwrap() const { return stream_; }
|
||||
|
||||
DeviceType device_type() const { return DeviceType::CUDA; }
|
||||
|
||||
DeviceIndex device_index() const { return stream_.device_index(); }
|
||||
|
||||
Device device() const { return Device(DeviceType::CUDA, device_index()); }
|
||||
|
||||
struct c10::StreamData3 pack3() const {
|
||||
return stream_.pack3();
|
||||
}
|
||||
|
||||
static CUDAStream unpack3(StreamId stream_id,
|
||||
DeviceIndex device_index,
|
||||
DeviceType device_type) {
|
||||
return CUDAStream(Stream::unpack3(stream_id, device_index, device_type));
|
||||
}
|
||||
|
||||
static std::tuple<int, int> priority_range() {
|
||||
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
|
||||
int least_priority = 0;
|
||||
int greatest_priority = 0;
|
||||
#ifdef PADDLE_WITH_HIP
|
||||
C10_CUDA_CHECK(
|
||||
hipDeviceGetStreamPriorityRange(&least_priority, &greatest_priority));
|
||||
#else
|
||||
C10_CUDA_CHECK(
|
||||
cudaDeviceGetStreamPriorityRange(&least_priority, &greatest_priority));
|
||||
#endif
|
||||
greatest_priority =
|
||||
std::max(-max_compile_time_stream_priorities + 1, greatest_priority);
|
||||
return std::make_tuple(least_priority, greatest_priority);
|
||||
#else
|
||||
return std::make_tuple(0, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
Stream stream_;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the current CUDA stream for the passed CUDA device, or for the
|
||||
* current device if no device index is passed.
|
||||
*/
|
||||
PADDLE_API CUDAStream getCurrentCUDAStream(c10::DeviceIndex device_index = -1);
|
||||
|
||||
/**
|
||||
* Get a new stream from the CUDA stream pool.
|
||||
* Priority -1 is high priority, 0 is default/low priority.
|
||||
* Matches PyTorch behavior where negative priority = high priority.
|
||||
*/
|
||||
PADDLE_API CUDAStream getStreamFromPool(const int priority = 0,
|
||||
c10::DeviceIndex device_index = -1);
|
||||
|
||||
/**
|
||||
* Get a new stream from the CUDA stream pool.
|
||||
* Bool overload: true = high priority (-1), false = default priority (0).
|
||||
*/
|
||||
PADDLE_API CUDAStream getStreamFromPool(const bool isHighPriority,
|
||||
c10::DeviceIndex device_index = -1);
|
||||
|
||||
#ifdef PADDLE_WITH_HIP
|
||||
PADDLE_API CUDAStream getStreamFromExternal(hipStream_t ext_stream,
|
||||
c10::DeviceIndex device_index);
|
||||
#else
|
||||
PADDLE_API CUDAStream getStreamFromExternal(cudaStream_t ext_stream,
|
||||
c10::DeviceIndex device_index);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Set the current CUDA stream for the device of the given stream.
|
||||
*
|
||||
* Keeps the compat c10 stream state aligned with Paddle's GPUContext so
|
||||
* Paddle stream guards and c10 callers observe the same current stream.
|
||||
*/
|
||||
PADDLE_API void setCurrentCUDAStream(CUDAStream stream);
|
||||
|
||||
PADDLE_API CUDAStream getDefaultCUDAStream(c10::DeviceIndex device_index = -1);
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& stream, const CUDAStream& s) {
|
||||
return stream << s.unwrap();
|
||||
}
|
||||
|
||||
} // namespace c10::cuda
|
||||
|
||||
namespace std {
|
||||
template <>
|
||||
struct hash<c10::cuda::CUDAStream> {
|
||||
size_t operator()(c10::cuda::CUDAStream s) const noexcept {
|
||||
return std::hash<c10::Stream>{}(s.unwrap());
|
||||
}
|
||||
};
|
||||
} // namespace std
|
||||
|
||||
namespace at::cuda {
|
||||
using c10::cuda::CUDAStream;
|
||||
using c10::cuda::getCurrentCUDAStream;
|
||||
using c10::cuda::getDefaultCUDAStream;
|
||||
using c10::cuda::getStreamFromExternal;
|
||||
using c10::cuda::getStreamFromPool;
|
||||
using c10::cuda::setCurrentCUDAStream;
|
||||
} // namespace at::cuda
|
||||
@@ -0,0 +1,20 @@
|
||||
// Copyright (c) 2026 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
// Placeholder header to satisfy PyTorch compatibility checks.
|
||||
// Paddle does not use the same CUDA cmake macros as PyTorch,
|
||||
// but the presence of this file allows downstream code to use
|
||||
// __has_include(<c10/cuda/impl/cuda_cmake_macros.h>) for feature detection.
|
||||
@@ -0,0 +1,46 @@
|
||||
// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// The file has been adapted from pytorch project
|
||||
// Licensed under BSD-style license -
|
||||
// https://github.com/pytorch/pytorch/blob/main/LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#define C10_CONCATENATE_IMPL(s1, s2) s1##s2
|
||||
#define C10_CONCATENATE(s1, s2) C10_CONCATENATE_IMPL(s1, s2)
|
||||
|
||||
#define C10_MACRO_EXPAND(args) args
|
||||
|
||||
#define C10_STRINGIZE_IMPL(x) #x
|
||||
#define C10_STRINGIZE(x) C10_STRINGIZE_IMPL(x)
|
||||
|
||||
#ifdef __COUNTER__
|
||||
#define C10_UID __COUNTER__
|
||||
#define C10_ANONYMOUS_VARIABLE(str) C10_CONCATENATE(str, __COUNTER__)
|
||||
#else
|
||||
#define C10_UID __LINE__
|
||||
#define C10_ANONYMOUS_VARIABLE(str) C10_CONCATENATE(str, __LINE__)
|
||||
#endif
|
||||
|
||||
#if defined(__CUDACC__) || defined(__HIPCC__)
|
||||
// Designates functions callable from the host (CPU) and the device (GPU)
|
||||
#define C10_HOST_DEVICE __host__ __device__
|
||||
#define C10_DEVICE __device__
|
||||
#define C10_HOST __host__
|
||||
#else
|
||||
#define C10_HOST_DEVICE
|
||||
#define C10_HOST
|
||||
#define C10_DEVICE
|
||||
#endif
|
||||
@@ -0,0 +1,213 @@
|
||||
// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// The file has been adapted from pytorch project
|
||||
// Licensed under BSD-style license -
|
||||
// https://github.com/pytorch/pytorch/blob/main/LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <c10/util/Exception.h>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
#include <vector>
|
||||
|
||||
#include "paddle/phi/common/int_array.h"
|
||||
|
||||
namespace c10 {
|
||||
|
||||
#define TORCH_CHECK_CONSTEXPR(COND, MSG) \
|
||||
((COND) ? void(0) : throw std::runtime_error(MSG))
|
||||
|
||||
template <typename T>
|
||||
class ArrayRef {
|
||||
private:
|
||||
/// The start of the array, in an external buffer.
|
||||
const T* Data;
|
||||
|
||||
/// The number of elements.
|
||||
size_t Length;
|
||||
|
||||
public:
|
||||
using iterator = const T*;
|
||||
using const_iterator = const T*;
|
||||
using size_type = size_t;
|
||||
using value_type = T;
|
||||
|
||||
using reverse_iterator = std::reverse_iterator<iterator>;
|
||||
|
||||
/* implicit */ constexpr ArrayRef() : Data(nullptr), Length(0) {}
|
||||
|
||||
constexpr ArrayRef(const T& OneElt) : Data(&OneElt), Length(1) {} // NOLINT
|
||||
|
||||
constexpr ArrayRef(const T* data, size_t length)
|
||||
: Data(data), Length(length) {}
|
||||
|
||||
constexpr ArrayRef(const T* begin, const T* end)
|
||||
: Data(begin), Length(end - begin) {}
|
||||
|
||||
template <typename Container,
|
||||
typename U = decltype(std::declval<Container>().data()),
|
||||
typename = std::enable_if_t<(std::is_same_v<U, T*> ||
|
||||
std::is_same_v<U, T const*>)>>
|
||||
/* implicit */ ArrayRef(const Container& container) // NOLINT
|
||||
: Data(container.data()), Length(container.size()) {}
|
||||
|
||||
template <typename A>
|
||||
/* implicit */ ArrayRef(const std::vector<T, A>& Vec) // NOLINT
|
||||
: Data(Vec.data()), Length(Vec.size()) {
|
||||
static_assert(!std::is_same_v<T, bool>,
|
||||
"ArrayRef<bool> cannot be constructed from a "
|
||||
"std::vector<bool> bitfield.");
|
||||
}
|
||||
|
||||
template <size_t N>
|
||||
/* implicit */ constexpr ArrayRef(const std::array<T, N>& Arr) // NOLINT
|
||||
: Data(Arr.data()), Length(N) {}
|
||||
|
||||
template <size_t N>
|
||||
/* implicit */ constexpr ArrayRef(const T (&Arr)[N]) // NOLINT
|
||||
: Data(Arr), Length(N) {}
|
||||
|
||||
/* implicit */ constexpr ArrayRef(const std::initializer_list<T>& Vec)
|
||||
: Data(std::begin(Vec) == std::end(Vec) ? static_cast<T*>(nullptr)
|
||||
: std::begin(Vec)),
|
||||
Length(Vec.size()) {}
|
||||
|
||||
constexpr iterator begin() const { return Data; }
|
||||
constexpr iterator end() const { return Data + Length; }
|
||||
|
||||
constexpr const_iterator cbegin() const { return Data; }
|
||||
constexpr const_iterator cend() const { return Data + Length; }
|
||||
|
||||
constexpr reverse_iterator rbegin() const { return reverse_iterator(end()); }
|
||||
constexpr reverse_iterator rend() const { return reverse_iterator(begin()); }
|
||||
|
||||
constexpr bool allMatch(const std::function<bool(const T&)>& pred) const {
|
||||
return std::all_of(cbegin(), cend(), pred);
|
||||
}
|
||||
|
||||
constexpr bool empty() const { return Length == 0; }
|
||||
|
||||
constexpr const T* data() const { return Data; }
|
||||
|
||||
constexpr size_t size() const { return Length; }
|
||||
|
||||
constexpr const T& front() const {
|
||||
TORCH_CHECK_CONSTEXPR(
|
||||
!empty(), "ArrayRef: attempted to access front() of empty list");
|
||||
return Data[0];
|
||||
}
|
||||
|
||||
constexpr const T& back() const {
|
||||
TORCH_CHECK_CONSTEXPR(!empty(),
|
||||
"ArrayRef: attempted to access back() of empty list");
|
||||
return Data[Length - 1];
|
||||
}
|
||||
|
||||
constexpr bool equals(ArrayRef RHS) const {
|
||||
return Length == RHS.Length && std::equal(begin(), end(), RHS.begin());
|
||||
}
|
||||
|
||||
/// slice(n, m) - Take M elements of the array starting at element N
|
||||
constexpr ArrayRef<T> slice(size_t N, size_t M) const {
|
||||
TORCH_CHECK_CONSTEXPR(N + M <= size(), "ArrayRef: invalid slice");
|
||||
return ArrayRef<T>(data() + N, M);
|
||||
}
|
||||
|
||||
/// slice(n) - Chop off the first N elements of the array.
|
||||
constexpr ArrayRef<T> slice(size_t N) const {
|
||||
TORCH_CHECK_CONSTEXPR(N <= size(), "ArrayRef: invalid slice");
|
||||
return slice(N, size() - N);
|
||||
}
|
||||
|
||||
constexpr const T& operator[](size_t Index) const { return Data[Index]; }
|
||||
|
||||
/// Vector compatibility
|
||||
constexpr const T& at(size_t Index) const {
|
||||
TORCH_CHECK_CONSTEXPR(Index < Length, "ArrayRef: invalid index");
|
||||
return Data[Index];
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
std::enable_if_t<std::is_same_v<U, T>, ArrayRef<T>>& operator=(
|
||||
U&& Temporary) = delete;
|
||||
|
||||
template <typename U>
|
||||
std::enable_if_t<std::is_same_v<U, T>, ArrayRef<T>>& operator=(
|
||||
std::initializer_list<U>) = delete;
|
||||
|
||||
std::vector<T> vec() const { return std::vector<T>(Data, Data + Length); }
|
||||
|
||||
const paddle::experimental::IntArray _PD_ToPaddleIntArray() const {
|
||||
return paddle::experimental::IntArray(
|
||||
reinterpret_cast<const int64_t*>(Data), Length);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
std::ostream& operator<<(std::ostream& out, ArrayRef<T> list) {
|
||||
int i = 0;
|
||||
out << "[";
|
||||
for (const auto& e : list) {
|
||||
if (i++ > 0) out << ", ";
|
||||
out << e;
|
||||
}
|
||||
out << "]";
|
||||
return out;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool operator==(c10::ArrayRef<T> a1, c10::ArrayRef<T> a2) {
|
||||
return a1.equals(a2);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool operator!=(c10::ArrayRef<T> a1, c10::ArrayRef<T> a2) {
|
||||
return !a1.equals(a2);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool operator==(const std::vector<T>& a1, c10::ArrayRef<T> a2) {
|
||||
return c10::ArrayRef<T>(a1).equals(a2);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool operator!=(const std::vector<T>& a1, c10::ArrayRef<T> a2) {
|
||||
return !c10::ArrayRef<T>(a1).equals(a2);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool operator==(c10::ArrayRef<T> a1, const std::vector<T>& a2) {
|
||||
return a1.equals(c10::ArrayRef<T>(a2));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool operator!=(c10::ArrayRef<T> a1, const std::vector<T>& a2) {
|
||||
return !a1.equals(c10::ArrayRef<T>(a2));
|
||||
}
|
||||
using IntArrayRef = ArrayRef<int64_t>;
|
||||
|
||||
} // namespace c10
|
||||
|
||||
namespace at {
|
||||
using c10::ArrayRef;
|
||||
using c10::IntArrayRef;
|
||||
} // namespace at
|
||||
|
||||
namespace torch {
|
||||
using c10::ArrayRef;
|
||||
using c10::IntArrayRef;
|
||||
} // namespace torch
|
||||
@@ -0,0 +1,29 @@
|
||||
// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "paddle/phi/common/bfloat16.h"
|
||||
|
||||
namespace c10 {
|
||||
using BFloat16 = ::phi::dtype::bfloat16;
|
||||
} // namespace c10
|
||||
|
||||
namespace at {
|
||||
using c10::BFloat16;
|
||||
} // namespace at
|
||||
|
||||
namespace torch {
|
||||
using c10::BFloat16;
|
||||
} // namespace torch
|
||||
@@ -0,0 +1,170 @@
|
||||
// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// The file has been adapted from pytorch project
|
||||
// Licensed under BSD-style license -
|
||||
// https://github.com/pytorch/pytorch/blob/main/LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <c10/macros/Macros.h>
|
||||
#include <torch/headeronly/util/Exception.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <exception>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
#include "paddle/common/enforce.h"
|
||||
#include "paddle/common/errors.h"
|
||||
#include "paddle/common/exception.h"
|
||||
#include "paddle/common/macros.h"
|
||||
|
||||
namespace c10 {
|
||||
#define TORCH_CHECK(COND, ...) PD_CHECK(COND, ##__VA_ARGS__);
|
||||
#define TORCH_INTERNAL_ASSERT(COND, ...) PD_CHECK(COND, ##__VA_ARGS__);
|
||||
#define TORCH_CHECK_OP(val1, val2, op) \
|
||||
do { \
|
||||
auto&& _val1 = (val1); \
|
||||
auto&& _val2 = (val2); \
|
||||
if (!(_val1 op _val2)) { \
|
||||
std::ostringstream _result; \
|
||||
_result << "Check failed: " #val1 " " #op " " #val2 " (" << _val1 \
|
||||
<< " vs. " << _val2 << "). "; \
|
||||
PD_THROW(_result.str()); \
|
||||
} \
|
||||
} while (false);
|
||||
|
||||
// Check for a given boolean condition.
|
||||
#ifndef CHECK
|
||||
#define CHECK(condition) PD_CHECK(condition, "CHECK failed : ", #condition)
|
||||
#endif
|
||||
|
||||
// TORCH_CHECK_OP macro definitions
|
||||
#define TORCH_CHECK_EQ(val1, val2) TORCH_CHECK_OP(val1, val2, ==)
|
||||
#define TORCH_CHECK_NE(val1, val2) TORCH_CHECK_OP(val1, val2, !=)
|
||||
#define TORCH_CHECK_LE(val1, val2) TORCH_CHECK_OP(val1, val2, <=)
|
||||
#define TORCH_CHECK_LT(val1, val2) TORCH_CHECK_OP(val1, val2, <)
|
||||
#define TORCH_CHECK_GE(val1, val2) TORCH_CHECK_OP(val1, val2, >=)
|
||||
#define TORCH_CHECK_GT(val1, val2) TORCH_CHECK_OP(val1, val2, >)
|
||||
} // namespace c10
|
||||
|
||||
enum class C10ErrorType {
|
||||
NotImplementedError,
|
||||
Error,
|
||||
};
|
||||
|
||||
constexpr auto NotImplementedError = C10ErrorType::NotImplementedError;
|
||||
constexpr auto Error = C10ErrorType::Error;
|
||||
|
||||
inline void C10ThrowImpl(C10ErrorType err_type, const std::string& msg) {
|
||||
switch (err_type) {
|
||||
case C10ErrorType::NotImplementedError:
|
||||
PADDLE_THROW(common::errors::Unimplemented(msg));
|
||||
break;
|
||||
case C10ErrorType::Error:
|
||||
PADDLE_THROW(common::errors::InvalidArgument(msg));
|
||||
break;
|
||||
default:
|
||||
PADDLE_THROW(common::errors::Fatal("Unknown error type: " + msg));
|
||||
}
|
||||
}
|
||||
|
||||
#define C10_THROW_ERROR(err_type, msg) C10ThrowImpl(err_type, msg)
|
||||
|
||||
// Warning support - simplified implementation compatible with PyTorch API
|
||||
namespace c10 {
|
||||
|
||||
// Warning types
|
||||
struct UserWarning {};
|
||||
struct DeprecationWarning {};
|
||||
|
||||
// Simple Warning class
|
||||
class Warning {
|
||||
public:
|
||||
template <typename WarningType, typename... Args>
|
||||
Warning(WarningType type,
|
||||
const std::tuple<const char*, const char*, uint32_t>& location,
|
||||
const std::string& msg,
|
||||
bool verbatim)
|
||||
: msg_(msg), verbatim_(verbatim) {
|
||||
(void)type;
|
||||
(void)location;
|
||||
(void)verbatim;
|
||||
}
|
||||
|
||||
const std::string& msg() const { return msg_; }
|
||||
|
||||
private:
|
||||
std::string msg_;
|
||||
bool verbatim_;
|
||||
};
|
||||
|
||||
// Warning handler - prints to stderr
|
||||
inline void warn(const Warning& warning) {
|
||||
std::cerr << "Warning: " << warning.msg() << std::endl;
|
||||
}
|
||||
|
||||
// Helper to concatenate message arguments
|
||||
template <typename... Args>
|
||||
inline std::string torch_warn_msg_impl(const Args&... args) {
|
||||
std::ostringstream oss;
|
||||
(oss << ... << args);
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
inline std::string torch_warn_msg_impl() { return ""; }
|
||||
|
||||
} // namespace c10
|
||||
|
||||
// TORCH_WARN macros
|
||||
#ifdef DISABLE_WARN
|
||||
#define _TORCH_WARN_WITH(...) ((void)0)
|
||||
#else
|
||||
#define _TORCH_WARN_WITH(warning_t, ...) \
|
||||
do { \
|
||||
::c10::warn(::c10::Warning( \
|
||||
warning_t{}, \
|
||||
std::make_tuple(__func__, __FILE__, static_cast<uint32_t>(__LINE__)), \
|
||||
::c10::torch_warn_msg_impl(__VA_ARGS__), \
|
||||
false)); \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#define TORCH_WARN(...) _TORCH_WARN_WITH(::c10::UserWarning, __VA_ARGS__)
|
||||
|
||||
#define TORCH_WARN_DEPRECATION(...) \
|
||||
_TORCH_WARN_WITH(::c10::DeprecationWarning, __VA_ARGS__)
|
||||
|
||||
// TORCH_WARN_ONCE - only warns once per call site
|
||||
#ifdef DISABLE_WARN
|
||||
#define TORCH_WARN_ONCE(...) ((void)0)
|
||||
#else
|
||||
#define TORCH_WARN_ONCE(...) \
|
||||
do { \
|
||||
static bool C10_ANONYMOUS_VARIABLE(torch_warn_once_) = [] { \
|
||||
TORCH_WARN(__VA_ARGS__); \
|
||||
return true; \
|
||||
}(); \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
// Deprecated attribute macro
|
||||
#define C10_DEPRECATED_MESSAGE(msg) [[deprecated(msg)]]
|
||||
@@ -0,0 +1,65 @@
|
||||
// Copyright (c) 2026 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// The file has been adapted from pytorch project
|
||||
// Licensed under BSD-style license -
|
||||
// https://github.com/pytorch/pytorch/blob/main/LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace c10 {
|
||||
|
||||
/// Defines the Float4_e2m1fn_x2 type (4-bit floating-point, two elements packed
|
||||
/// into one byte). This is the FP4 dtype from the OCP MX format spec
|
||||
/// (https://www.opencompute.org/documents/ocp-microscaling-formats-mx-v1-0-spec-final-pdf,
|
||||
/// Section 5.3.3)
|
||||
///
|
||||
/// Given two high precision values val0 and val1, here is the
|
||||
/// binary configuration of their packed representation, from MSB to LSB:
|
||||
///
|
||||
/// original value | val1 : val0
|
||||
/// ========================================
|
||||
/// bit index (MSB==7, LSB==0) | 7654 : 3210
|
||||
/// sign/exponent/mantissa | seem : seem
|
||||
|
||||
struct alignas(1) Float4_e2m1fn_x2 {
|
||||
uint8_t val_;
|
||||
Float4_e2m1fn_x2() = default;
|
||||
explicit constexpr Float4_e2m1fn_x2(uint8_t val) : val_(val) {}
|
||||
};
|
||||
|
||||
/// Comparison operators
|
||||
inline bool operator==(const Float4_e2m1fn_x2& a, const Float4_e2m1fn_x2& b) {
|
||||
return a.val_ == b.val_;
|
||||
}
|
||||
|
||||
inline bool operator!=(const Float4_e2m1fn_x2& a, const Float4_e2m1fn_x2& b) {
|
||||
return a.val_ != b.val_;
|
||||
}
|
||||
|
||||
} // namespace c10
|
||||
|
||||
namespace at {
|
||||
using c10::Float4_e2m1fn_x2;
|
||||
using c10::operator!=;
|
||||
using c10::operator==;
|
||||
} // namespace at
|
||||
|
||||
namespace torch {
|
||||
using c10::Float4_e2m1fn_x2;
|
||||
using c10::operator!=;
|
||||
using c10::operator==;
|
||||
} // namespace torch
|
||||
@@ -0,0 +1,27 @@
|
||||
// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "paddle/phi/common/float8_e4m3fn.h"
|
||||
|
||||
namespace c10 {
|
||||
using Float8_e4m3fn = ::phi::dtype::float8_e4m3fn;
|
||||
} // namespace c10
|
||||
namespace at {
|
||||
using c10::Float8_e4m3fn;
|
||||
} // namespace at
|
||||
namespace torch {
|
||||
using c10::Float8_e4m3fn;
|
||||
} // namespace torch
|
||||
@@ -0,0 +1,40 @@
|
||||
// Copyright (c) 2026 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// The file has been adapted from pytorch project
|
||||
// Licensed under BSD-style license -
|
||||
// https://github.com/pytorch/pytorch/blob/main/LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace c10 {
|
||||
|
||||
struct Float8_e4m3fnuz {
|
||||
constexpr Float8_e4m3fnuz() = default;
|
||||
explicit constexpr Float8_e4m3fnuz(uint8_t value) : x(value) {}
|
||||
|
||||
uint8_t x{0};
|
||||
};
|
||||
|
||||
} // namespace c10
|
||||
|
||||
namespace at {
|
||||
using c10::Float8_e4m3fnuz;
|
||||
} // namespace at
|
||||
|
||||
namespace torch {
|
||||
using c10::Float8_e4m3fnuz;
|
||||
} // namespace torch
|
||||
@@ -0,0 +1,28 @@
|
||||
// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "paddle/phi/common/float8_e5m2.h"
|
||||
|
||||
namespace c10 {
|
||||
using Float8_e5m2 = ::phi::dtype::float8_e5m2;
|
||||
} // namespace c10
|
||||
|
||||
namespace at {
|
||||
using c10::Float8_e5m2;
|
||||
} // namespace at
|
||||
namespace torch {
|
||||
using c10::Float8_e5m2;
|
||||
} // namespace torch
|
||||
@@ -0,0 +1,40 @@
|
||||
// Copyright (c) 2026 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// The file has been adapted from pytorch project
|
||||
// Licensed under BSD-style license -
|
||||
// https://github.com/pytorch/pytorch/blob/main/LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace c10 {
|
||||
|
||||
struct Float8_e5m2fnuz {
|
||||
constexpr Float8_e5m2fnuz() = default;
|
||||
explicit constexpr Float8_e5m2fnuz(uint8_t value) : x(value) {}
|
||||
|
||||
uint8_t x{0};
|
||||
};
|
||||
|
||||
} // namespace c10
|
||||
|
||||
namespace at {
|
||||
using c10::Float8_e5m2fnuz;
|
||||
} // namespace at
|
||||
|
||||
namespace torch {
|
||||
using c10::Float8_e5m2fnuz;
|
||||
} // namespace torch
|
||||
@@ -0,0 +1,40 @@
|
||||
// Copyright (c) 2026 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// The file has been adapted from pytorch project
|
||||
// Licensed under BSD-style license -
|
||||
// https://github.com/pytorch/pytorch/blob/main/LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace c10 {
|
||||
|
||||
struct Float8_e8m0fnu {
|
||||
constexpr Float8_e8m0fnu() = default;
|
||||
explicit constexpr Float8_e8m0fnu(uint8_t value) : x(value) {}
|
||||
|
||||
uint8_t x{0};
|
||||
};
|
||||
|
||||
} // namespace c10
|
||||
|
||||
namespace at {
|
||||
using c10::Float8_e8m0fnu;
|
||||
} // namespace at
|
||||
|
||||
namespace torch {
|
||||
using c10::Float8_e8m0fnu;
|
||||
} // namespace torch
|
||||
@@ -0,0 +1,29 @@
|
||||
// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "paddle/phi/common/float16.h"
|
||||
|
||||
namespace c10 {
|
||||
using Half = ::phi::dtype::float16;
|
||||
} // namespace c10
|
||||
|
||||
namespace at {
|
||||
using c10::Half;
|
||||
} // namespace at
|
||||
|
||||
namespace torch {
|
||||
using c10::Half;
|
||||
} // namespace torch
|
||||
@@ -0,0 +1,26 @@
|
||||
// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
|
||||
namespace c10 {
|
||||
// Aliases from C++17 std::optional
|
||||
using std::bad_optional_access;
|
||||
using std::make_optional;
|
||||
using std::nullopt;
|
||||
using std::nullopt_t;
|
||||
using std::optional;
|
||||
} // namespace c10
|
||||
@@ -0,0 +1,234 @@
|
||||
// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// The file has been adapted from pytorch project
|
||||
// Licensed under BSD-style license -
|
||||
// https://github.com/pytorch/pytorch/blob/main/LICENSE
|
||||
|
||||
#pragma once
|
||||
#include <c10/util/ArrayRef.h>
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
namespace c10 {
|
||||
template <typename T>
|
||||
class OptionalArrayRef final {
|
||||
public:
|
||||
// Constructors
|
||||
|
||||
constexpr OptionalArrayRef() noexcept = default;
|
||||
|
||||
constexpr OptionalArrayRef(std::nullopt_t) noexcept {}
|
||||
|
||||
OptionalArrayRef(const OptionalArrayRef& other) = default;
|
||||
|
||||
OptionalArrayRef(OptionalArrayRef&& other) noexcept = default;
|
||||
|
||||
constexpr OptionalArrayRef(const std::optional<ArrayRef<T>>& other) noexcept
|
||||
: wrapped_opt_array_ref(other) {}
|
||||
|
||||
constexpr OptionalArrayRef(std::optional<ArrayRef<T>>&& other) noexcept
|
||||
: wrapped_opt_array_ref(std::move(other)) {}
|
||||
|
||||
constexpr OptionalArrayRef(const T& value) noexcept
|
||||
: wrapped_opt_array_ref(value) {}
|
||||
|
||||
template <
|
||||
typename U = ArrayRef<T>,
|
||||
std::enable_if_t<!std::is_same_v<std::decay_t<U>, OptionalArrayRef> &&
|
||||
!std::is_same_v<std::decay_t<U>, std::in_place_t> &&
|
||||
std::is_constructible_v<ArrayRef<T>, U&&> &&
|
||||
std::is_convertible_v<U&&, ArrayRef<T>> &&
|
||||
!std::is_convertible_v<U&&, T>,
|
||||
bool> = false>
|
||||
constexpr OptionalArrayRef(U&& value) noexcept(
|
||||
std::is_nothrow_constructible_v<ArrayRef<T>, U&&>)
|
||||
: wrapped_opt_array_ref(std::forward<U>(value)) {}
|
||||
|
||||
template <
|
||||
typename U = ArrayRef<T>,
|
||||
std::enable_if_t<!std::is_same_v<std::decay_t<U>, OptionalArrayRef> &&
|
||||
!std::is_same_v<std::decay_t<U>, std::in_place_t> &&
|
||||
std::is_constructible_v<ArrayRef<T>, U&&> &&
|
||||
!std::is_convertible_v<U&&, ArrayRef<T>>,
|
||||
bool> = false>
|
||||
constexpr explicit OptionalArrayRef(U&& value) noexcept(
|
||||
std::is_nothrow_constructible_v<ArrayRef<T>, U&&>)
|
||||
: wrapped_opt_array_ref(std::forward<U>(value)) {}
|
||||
|
||||
template <typename... Args>
|
||||
constexpr explicit OptionalArrayRef(std::in_place_t ip,
|
||||
Args&&... args) noexcept
|
||||
: wrapped_opt_array_ref(ip, std::forward<Args>(args)...) {}
|
||||
|
||||
template <typename U, typename... Args>
|
||||
constexpr explicit OptionalArrayRef(std::in_place_t ip,
|
||||
std::initializer_list<U> il,
|
||||
Args&&... args)
|
||||
: wrapped_opt_array_ref(ip, il, std::forward<Args>(args)...) {}
|
||||
|
||||
constexpr OptionalArrayRef(const std::initializer_list<T>& Vec)
|
||||
: wrapped_opt_array_ref(ArrayRef<T>(Vec)) {}
|
||||
|
||||
// Destructor
|
||||
|
||||
~OptionalArrayRef() = default;
|
||||
|
||||
// Assignment
|
||||
|
||||
constexpr OptionalArrayRef& operator=(std::nullopt_t) noexcept {
|
||||
wrapped_opt_array_ref = std::nullopt;
|
||||
return *this;
|
||||
}
|
||||
|
||||
OptionalArrayRef& operator=(const OptionalArrayRef& other) = default;
|
||||
|
||||
OptionalArrayRef& operator=(OptionalArrayRef&& other) noexcept = default;
|
||||
|
||||
constexpr OptionalArrayRef& operator=(
|
||||
const std::optional<ArrayRef<T>>& other) noexcept {
|
||||
wrapped_opt_array_ref = other;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr OptionalArrayRef& operator=(
|
||||
std::optional<ArrayRef<T>>&& other) noexcept {
|
||||
wrapped_opt_array_ref = std::move(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename U = ArrayRef<T>,
|
||||
typename = std::enable_if_t<
|
||||
!std::is_same_v<std::decay_t<U>, OptionalArrayRef> &&
|
||||
std::is_constructible_v<ArrayRef<T>, U&&> &&
|
||||
std::is_assignable_v<ArrayRef<T>&, U&&>>>
|
||||
constexpr OptionalArrayRef& operator=(U&& value) noexcept(
|
||||
std::is_nothrow_constructible_v<ArrayRef<T>, U&&>&&
|
||||
std::is_nothrow_assignable_v<ArrayRef<T>&, U&&>) {
|
||||
wrapped_opt_array_ref = std::forward<U>(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Observers
|
||||
|
||||
constexpr ArrayRef<T>* operator->() noexcept {
|
||||
return &wrapped_opt_array_ref.value();
|
||||
}
|
||||
|
||||
constexpr const ArrayRef<T>* operator->() const noexcept {
|
||||
return &wrapped_opt_array_ref.value();
|
||||
}
|
||||
|
||||
constexpr ArrayRef<T>& operator*() & noexcept {
|
||||
return wrapped_opt_array_ref.value();
|
||||
}
|
||||
|
||||
constexpr const ArrayRef<T>& operator*() const& noexcept {
|
||||
return wrapped_opt_array_ref.value();
|
||||
}
|
||||
|
||||
constexpr ArrayRef<T>&& operator*() && noexcept {
|
||||
return std::move(wrapped_opt_array_ref.value());
|
||||
}
|
||||
|
||||
constexpr const ArrayRef<T>&& operator*() const&& noexcept {
|
||||
return std::move(wrapped_opt_array_ref.value());
|
||||
}
|
||||
|
||||
constexpr explicit operator bool() const noexcept {
|
||||
return wrapped_opt_array_ref.has_value();
|
||||
}
|
||||
|
||||
constexpr bool has_value() const noexcept {
|
||||
return wrapped_opt_array_ref.has_value();
|
||||
}
|
||||
|
||||
constexpr ArrayRef<T>& value() & { return wrapped_opt_array_ref.value(); }
|
||||
|
||||
constexpr const ArrayRef<T>& value() const& {
|
||||
return wrapped_opt_array_ref.value();
|
||||
}
|
||||
|
||||
constexpr ArrayRef<T>&& value() && {
|
||||
return std::move(wrapped_opt_array_ref.value());
|
||||
}
|
||||
|
||||
constexpr const ArrayRef<T>&& value() const&& {
|
||||
return std::move(wrapped_opt_array_ref.value());
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
constexpr std::enable_if_t<std::is_convertible_v<U&&, ArrayRef<T>>,
|
||||
ArrayRef<T>>
|
||||
value_or(U&& default_value) const& {
|
||||
return wrapped_opt_array_ref.value_or(std::forward<U>(default_value));
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
constexpr std::enable_if_t<std::is_convertible_v<U&&, ArrayRef<T>>,
|
||||
ArrayRef<T>>
|
||||
value_or(U&& default_value) && {
|
||||
return wrapped_opt_array_ref.value_or(std::forward<U>(default_value));
|
||||
}
|
||||
|
||||
// Modifiers
|
||||
|
||||
constexpr void swap(OptionalArrayRef& other) noexcept {
|
||||
std::swap(wrapped_opt_array_ref, other.wrapped_opt_array_ref);
|
||||
}
|
||||
|
||||
constexpr void reset() noexcept { wrapped_opt_array_ref.reset(); }
|
||||
|
||||
template <typename... Args>
|
||||
constexpr std::enable_if_t<std::is_constructible_v<ArrayRef<T>, Args&&...>,
|
||||
ArrayRef<T>&>
|
||||
emplace(Args&&... args) noexcept(
|
||||
std::is_nothrow_constructible_v<ArrayRef<T>, Args&&...>) {
|
||||
return wrapped_opt_array_ref.emplace(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename U, typename... Args>
|
||||
constexpr ArrayRef<T>& emplace(std::initializer_list<U> il,
|
||||
Args&&... args) noexcept {
|
||||
return wrapped_opt_array_ref.emplace(il, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
private:
|
||||
std::optional<ArrayRef<T>> wrapped_opt_array_ref;
|
||||
};
|
||||
|
||||
using OptionalIntArrayRef = OptionalArrayRef<int64_t>;
|
||||
|
||||
inline bool operator==(const OptionalIntArrayRef& a1,
|
||||
const IntArrayRef& other) {
|
||||
if (!a1.has_value()) {
|
||||
return false;
|
||||
}
|
||||
return a1.value() == other;
|
||||
}
|
||||
|
||||
inline bool operator==(const c10::IntArrayRef& a1,
|
||||
const c10::OptionalIntArrayRef& a2) {
|
||||
return a2 == a1;
|
||||
}
|
||||
|
||||
} // namespace c10
|
||||
namespace at {
|
||||
using c10::OptionalIntArrayRef;
|
||||
} // namespace at
|
||||
|
||||
namespace torch {
|
||||
using c10::OptionalIntArrayRef;
|
||||
} // namespace torch
|
||||
@@ -0,0 +1,95 @@
|
||||
// Copyright (c) 2026 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// The file has been adapted from pytorch project
|
||||
// Licensed under BSD-style license -
|
||||
// https://github.com/pytorch/pytorch/blob/main/LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
|
||||
namespace c10 {
|
||||
namespace util {
|
||||
|
||||
class type_index final {
|
||||
public:
|
||||
constexpr explicit type_index(uint64_t checksum = 0) : checksum_(checksum) {}
|
||||
|
||||
constexpr uint64_t underlyingId() const noexcept { return checksum_; }
|
||||
|
||||
friend constexpr bool operator==(type_index lhs, type_index rhs) noexcept {
|
||||
return lhs.checksum_ == rhs.checksum_;
|
||||
}
|
||||
friend constexpr bool operator!=(type_index lhs, type_index rhs) noexcept {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
friend constexpr bool operator<(type_index lhs, type_index rhs) noexcept {
|
||||
return lhs.checksum_ < rhs.checksum_;
|
||||
}
|
||||
|
||||
private:
|
||||
uint64_t checksum_;
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
constexpr uint64_t kFnvOffsetBasis = 14695981039346656037ULL;
|
||||
constexpr uint64_t kFnvPrime = 1099511628211ULL;
|
||||
|
||||
constexpr uint64_t fnv1a64(const char* data, size_t n) {
|
||||
uint64_t hash = kFnvOffsetBasis;
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
hash ^= static_cast<uint64_t>(static_cast<unsigned char>(data[i]));
|
||||
hash *= kFnvPrime;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr std::string_view type_signature() {
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
constexpr std::string_view sig = __FUNCSIG__;
|
||||
#else
|
||||
constexpr std::string_view sig = __PRETTY_FUNCTION__;
|
||||
#endif
|
||||
return sig;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr uint64_t type_index_impl() {
|
||||
constexpr std::string_view sig = type_signature<T>();
|
||||
return fnv1a64(sig.data(), sig.size());
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <typename T>
|
||||
constexpr type_index get_type_index() {
|
||||
return type_index(detail::type_index_impl<std::decay_t<T>>());
|
||||
}
|
||||
|
||||
} // namespace util
|
||||
} // namespace c10
|
||||
|
||||
namespace std {
|
||||
template <>
|
||||
struct hash<c10::util::type_index> {
|
||||
size_t operator()(c10::util::type_index v) const noexcept {
|
||||
return static_cast<size_t>(v.underlyingId());
|
||||
}
|
||||
};
|
||||
} // namespace std
|
||||
@@ -0,0 +1,139 @@
|
||||
// Copyright (c) 2026 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <c10/macros/Macros.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
namespace c10 {
|
||||
|
||||
using DeleterFnPtr = void (*)(void*);
|
||||
|
||||
namespace detail {
|
||||
|
||||
// Does not delete anything
|
||||
inline void deleteNothing(void* /*unused*/) {}
|
||||
|
||||
// A detail::UniqueVoidPtr is an owning smart pointer like unique_ptr, but
|
||||
// with three major differences:
|
||||
//
|
||||
// 1) It is specialized to void
|
||||
//
|
||||
// 2) It is specialized for a function pointer deleter
|
||||
// void(void* ctx); i.e., the deleter doesn't take a
|
||||
// reference to the data, just to a context pointer
|
||||
// (erased as void*). In fact, internally, this pointer
|
||||
// is implemented as having an owning reference to
|
||||
// context, and a non-owning reference to data; this is why
|
||||
// you release_context(), not release() (the conventional
|
||||
// API for release() wouldn't give you enough information
|
||||
// to properly dispose of the object later.)
|
||||
//
|
||||
// 3) The deleter is guaranteed to be called when the unique
|
||||
// pointer is destructed and the context is non-null; this is different
|
||||
// from std::unique_ptr where the deleter is not called if the
|
||||
// data pointer is null.
|
||||
//
|
||||
// Some of the methods have slightly different types than std::unique_ptr
|
||||
// to reflect this.
|
||||
//
|
||||
class UniqueVoidPtr {
|
||||
private:
|
||||
// Lifetime tied to ctx_
|
||||
void* data_;
|
||||
std::unique_ptr<void, DeleterFnPtr> ctx_;
|
||||
|
||||
public:
|
||||
UniqueVoidPtr() : data_(nullptr), ctx_(nullptr, &deleteNothing) {}
|
||||
explicit UniqueVoidPtr(void* data)
|
||||
: data_(data), ctx_(nullptr, &deleteNothing) {}
|
||||
UniqueVoidPtr(void* data, void* ctx, DeleterFnPtr ctx_deleter)
|
||||
: data_(data), ctx_(ctx, ctx_deleter ? ctx_deleter : &deleteNothing) {}
|
||||
void* operator->() const { return data_; }
|
||||
void clear() {
|
||||
ctx_ = nullptr;
|
||||
data_ = nullptr;
|
||||
}
|
||||
void* get() const { return data_; }
|
||||
|
||||
bool /* success */ unsafe_reset_data_and_ctx(void* new_data_and_ctx) {
|
||||
if (__builtin_expect(
|
||||
static_cast<bool>((ctx_.get_deleter() != &deleteNothing)), 0)) {
|
||||
return false;
|
||||
}
|
||||
// seems quicker than calling the no-op deleter when we reset
|
||||
(void)ctx_.release();
|
||||
ctx_.reset(new_data_and_ctx);
|
||||
data_ = new_data_and_ctx;
|
||||
return true;
|
||||
}
|
||||
|
||||
void* get_context() const { return ctx_.get(); }
|
||||
void* release_context() { return ctx_.release(); }
|
||||
std::unique_ptr<void, DeleterFnPtr>&& move_context() {
|
||||
return std::move(ctx_);
|
||||
}
|
||||
[[nodiscard]] bool compare_exchange_deleter(DeleterFnPtr expected_deleter,
|
||||
DeleterFnPtr new_deleter) {
|
||||
if (get_deleter() != expected_deleter) return false;
|
||||
ctx_ = std::unique_ptr<void, DeleterFnPtr>(ctx_.release(), new_deleter);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T* cast_context(DeleterFnPtr expected_deleter) const {
|
||||
if (get_deleter() != expected_deleter) return nullptr;
|
||||
return static_cast<T*>(get_context());
|
||||
}
|
||||
operator bool() const { return data_ || ctx_; }
|
||||
DeleterFnPtr get_deleter() const { return ctx_.get_deleter(); }
|
||||
};
|
||||
|
||||
// Note [How UniqueVoidPtr is implemented]
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// UniqueVoidPtr solves a common problem for allocators of tensor data, which
|
||||
// is that the data pointer (e.g., float*) which you are interested in, is not
|
||||
// the same as the context pointer (e.g., DLManagedTensor) which you need
|
||||
// to actually deallocate the data. Under a conventional deleter design, you
|
||||
// have to store extra context in the deleter itself so that you can actually
|
||||
// delete the right thing. Implementing this with standard C++ is somewhat
|
||||
// error-prone: if you use a std::unique_ptr to manage tensors, the deleter will
|
||||
// not be called if the data pointer is nullptr, which can cause a leak if the
|
||||
// context pointer is non-null (and the deleter is responsible for freeing both
|
||||
// the data pointer and the context pointer).
|
||||
//
|
||||
// So, in our reimplementation of unique_ptr, which just store the context
|
||||
// directly in the unique pointer, and attach the deleter to the context
|
||||
// pointer itself. In simple cases, the context pointer is just the pointer
|
||||
// itself.
|
||||
|
||||
inline bool operator==(const UniqueVoidPtr& sp, std::nullptr_t) noexcept {
|
||||
return !sp;
|
||||
}
|
||||
inline bool operator==(std::nullptr_t, const UniqueVoidPtr& sp) noexcept {
|
||||
return !sp;
|
||||
}
|
||||
inline bool operator!=(const UniqueVoidPtr& sp, std::nullptr_t) noexcept {
|
||||
return sp;
|
||||
}
|
||||
inline bool operator!=(std::nullptr_t, const UniqueVoidPtr& sp) noexcept {
|
||||
return sp;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace c10
|
||||
@@ -0,0 +1,106 @@
|
||||
// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// The file has been adapted from pytorch project
|
||||
// Licensed under BSD-style license -
|
||||
// https://github.com/pytorch/pytorch/blob/main/LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <c10/util/Exception.h>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
#include <numeric>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace c10 {
|
||||
|
||||
template <typename C,
|
||||
std::enable_if_t<std::is_integral_v<typename C::value_type>, int> = 0>
|
||||
inline int64_t sum_integers(const C& container) {
|
||||
return std::accumulate(
|
||||
container.begin(), container.end(), static_cast<int64_t>(0));
|
||||
}
|
||||
|
||||
template <typename Iter,
|
||||
std::enable_if_t<std::is_integral_v<
|
||||
typename std::iterator_traits<Iter>::value_type>,
|
||||
int> = 0>
|
||||
inline int64_t sum_integers(Iter begin, Iter end) {
|
||||
return std::accumulate(begin, end, static_cast<int64_t>(0));
|
||||
}
|
||||
|
||||
template <typename C,
|
||||
std::enable_if_t<std::is_integral_v<typename C::value_type>, int> = 0>
|
||||
inline int64_t multiply_integers(const C& container) {
|
||||
return std::accumulate(container.begin(),
|
||||
container.end(),
|
||||
static_cast<int64_t>(1),
|
||||
std::multiplies<>());
|
||||
}
|
||||
|
||||
template <typename Iter,
|
||||
std::enable_if_t<std::is_integral_v<
|
||||
typename std::iterator_traits<Iter>::value_type>,
|
||||
int> = 0>
|
||||
inline int64_t multiply_integers(Iter begin, Iter end) {
|
||||
return std::accumulate(
|
||||
begin, end, static_cast<int64_t>(1), std::multiplies<>());
|
||||
}
|
||||
|
||||
template <typename C,
|
||||
std::enable_if_t<std::is_integral_v<typename C::value_type>, int> = 0>
|
||||
inline int64_t numelements_from_dim(const int k, const C& dims) {
|
||||
if (k > static_cast<int>(dims.size())) {
|
||||
return 1;
|
||||
} else {
|
||||
auto cbegin = dims.cbegin();
|
||||
std::advance(cbegin, k);
|
||||
return multiply_integers(cbegin, dims.cend());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename C,
|
||||
std::enable_if_t<std::is_integral_v<typename C::value_type>, int> = 0>
|
||||
inline int64_t numelements_to_dim(const int k, const C& dims) {
|
||||
TORCH_INTERNAL_ASSERT(0 <= k);
|
||||
TORCH_INTERNAL_ASSERT((unsigned)k <= dims.size());
|
||||
|
||||
auto cend = dims.cbegin();
|
||||
std::advance(cend, k);
|
||||
return multiply_integers(dims.cbegin(), cend);
|
||||
}
|
||||
|
||||
template <typename C,
|
||||
std::enable_if_t<std::is_integral_v<typename C::value_type>, int> = 0>
|
||||
inline int64_t numelements_between_dim(int k, int l, const C& dims) {
|
||||
TORCH_INTERNAL_ASSERT(0 <= k);
|
||||
TORCH_INTERNAL_ASSERT(0 <= l);
|
||||
|
||||
if (k > l) {
|
||||
std::swap(k, l);
|
||||
}
|
||||
|
||||
TORCH_INTERNAL_ASSERT((unsigned)l < dims.size());
|
||||
|
||||
auto cbegin = dims.cbegin();
|
||||
auto cend = dims.cbegin();
|
||||
std::advance(cbegin, k);
|
||||
std::advance(cend, l);
|
||||
return multiply_integers(cbegin, cend);
|
||||
}
|
||||
|
||||
} // namespace c10
|
||||
@@ -0,0 +1,76 @@
|
||||
// Copyright (c) 2026 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// The file has been adapted from pytorch project
|
||||
// Licensed under BSD-style license -
|
||||
// https://github.com/pytorch/pytorch/blob/main/LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace c10 {
|
||||
|
||||
struct bits1x8 {
|
||||
constexpr bits1x8() = default;
|
||||
explicit constexpr bits1x8(uint8_t value) : val_(value) {}
|
||||
|
||||
uint8_t val_{0};
|
||||
};
|
||||
|
||||
struct bits2x4 {
|
||||
constexpr bits2x4() = default;
|
||||
explicit constexpr bits2x4(uint8_t value) : val_(value) {}
|
||||
|
||||
uint8_t val_{0};
|
||||
};
|
||||
|
||||
struct bits4x2 {
|
||||
constexpr bits4x2() = default;
|
||||
explicit constexpr bits4x2(uint8_t value) : val_(value) {}
|
||||
|
||||
uint8_t val_{0};
|
||||
};
|
||||
|
||||
struct bits8 {
|
||||
constexpr bits8() = default;
|
||||
explicit constexpr bits8(uint8_t value) : val_(value) {}
|
||||
|
||||
uint8_t val_{0};
|
||||
};
|
||||
|
||||
struct bits16 {
|
||||
constexpr bits16() = default;
|
||||
explicit constexpr bits16(uint16_t value) : val_(value) {}
|
||||
|
||||
uint16_t val_{0};
|
||||
};
|
||||
|
||||
} // namespace c10
|
||||
|
||||
namespace at {
|
||||
using c10::bits16;
|
||||
using c10::bits1x8;
|
||||
using c10::bits2x4;
|
||||
using c10::bits4x2;
|
||||
using c10::bits8;
|
||||
} // namespace at
|
||||
|
||||
namespace torch {
|
||||
using c10::bits16;
|
||||
using c10::bits1x8;
|
||||
using c10::bits2x4;
|
||||
using c10::bits4x2;
|
||||
using c10::bits8;
|
||||
} // namespace torch
|
||||
@@ -0,0 +1,29 @@
|
||||
// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "paddle/phi/common/complex.h"
|
||||
|
||||
namespace c10 {
|
||||
template <typename T>
|
||||
using complex = ::phi::dtype::complex<T>;
|
||||
} // namespace c10
|
||||
|
||||
namespace at {
|
||||
using c10::complex;
|
||||
} // namespace at
|
||||
namespace torch {
|
||||
using c10::complex;
|
||||
} // namespace torch
|
||||
@@ -0,0 +1,442 @@
|
||||
// Copyright (c) 2026 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// The file has been adapted from the PyTorch project.
|
||||
// Licensed under BSD-style license:
|
||||
// https://github.com/pytorch/pytorch/blob/main/LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace c10 {
|
||||
|
||||
// Forward declarations
|
||||
class intrusive_ptr_target;
|
||||
namespace raw {
|
||||
namespace intrusive_ptr {
|
||||
inline void incref(intrusive_ptr_target* self);
|
||||
inline void decref(intrusive_ptr_target* self);
|
||||
} // namespace intrusive_ptr
|
||||
namespace weak_intrusive_ptr {
|
||||
inline void incref(intrusive_ptr_target* self);
|
||||
inline void decref(intrusive_ptr_target* self);
|
||||
} // namespace weak_intrusive_ptr
|
||||
struct DontIncreaseRefcount {};
|
||||
} // namespace raw
|
||||
|
||||
namespace detail {
|
||||
|
||||
constexpr uint64_t kImpracticallyHugeReferenceCount = 0x0FFFFFFF;
|
||||
constexpr uint64_t kImpracticallyHugeWeakReferenceCount =
|
||||
(kImpracticallyHugeReferenceCount << 32);
|
||||
constexpr uint64_t kReferenceCountOne = 1;
|
||||
constexpr uint64_t kWeakReferenceCountOne = (kReferenceCountOne << 32);
|
||||
constexpr uint64_t kUniqueRef = (kReferenceCountOne | kWeakReferenceCountOne);
|
||||
|
||||
inline uint32_t refcount(uint64_t combined_refcount) {
|
||||
return static_cast<uint32_t>(combined_refcount);
|
||||
}
|
||||
|
||||
inline uint32_t weakcount(uint64_t combined_refcount) {
|
||||
// Bit 63 is reserved for kHasPyObject in PyTorch (a flag indicating a live
|
||||
// Python wrapper). This compat layer does not implement the PyObject path,
|
||||
// so the bit will never be set, but we mask it out here to match PyTorch's
|
||||
// extraction logic and remain numerically correct if the bit were ever set.
|
||||
return static_cast<uint32_t>((combined_refcount & ~(uint64_t(1) << 63)) >>
|
||||
32);
|
||||
}
|
||||
|
||||
inline uint64_t atomic_combined_refcount_increment(
|
||||
std::atomic<uint64_t>* combined_refcount, uint64_t inc) {
|
||||
return combined_refcount->fetch_add(inc, std::memory_order_relaxed) + inc;
|
||||
}
|
||||
|
||||
inline uint64_t atomic_combined_refcount_decrement(
|
||||
std::atomic<uint64_t>* combined_refcount, uint64_t dec) {
|
||||
return combined_refcount->fetch_sub(dec, std::memory_order_acq_rel) - dec;
|
||||
}
|
||||
|
||||
inline uint32_t atomic_weakcount_increment(
|
||||
std::atomic<uint64_t>* combined_refcount) {
|
||||
return weakcount(atomic_combined_refcount_increment(combined_refcount,
|
||||
kWeakReferenceCountOne));
|
||||
}
|
||||
|
||||
inline uint32_t atomic_weakcount_decrement(
|
||||
std::atomic<uint64_t>* combined_refcount) {
|
||||
return weakcount(atomic_combined_refcount_decrement(combined_refcount,
|
||||
kWeakReferenceCountOne));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
struct intrusive_target_default_null_type final {
|
||||
static constexpr T* singleton() noexcept { return nullptr; }
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
class intrusive_ptr_target {
|
||||
public:
|
||||
intrusive_ptr_target() noexcept : combined_refcount_(0) {}
|
||||
|
||||
intrusive_ptr_target(intrusive_ptr_target&& /*other*/) noexcept
|
||||
: intrusive_ptr_target() {}
|
||||
|
||||
intrusive_ptr_target& operator=(intrusive_ptr_target&& /*other*/) noexcept {
|
||||
return *this;
|
||||
}
|
||||
|
||||
intrusive_ptr_target(const intrusive_ptr_target& /*other*/) noexcept
|
||||
: intrusive_ptr_target() {}
|
||||
|
||||
intrusive_ptr_target& operator=(
|
||||
const intrusive_ptr_target& /*other*/) noexcept {
|
||||
return *this;
|
||||
}
|
||||
|
||||
uint32_t refcount() const {
|
||||
return detail::refcount(combined_refcount_.load(std::memory_order_relaxed));
|
||||
}
|
||||
|
||||
uint32_t weakcount() const {
|
||||
return detail::weakcount(
|
||||
combined_refcount_.load(std::memory_order_relaxed));
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual ~intrusive_ptr_target() = default;
|
||||
|
||||
private:
|
||||
mutable std::atomic<uint64_t> combined_refcount_;
|
||||
|
||||
template <typename T, typename NullType>
|
||||
friend class intrusive_ptr;
|
||||
template <typename T, typename NullType>
|
||||
friend class weak_intrusive_ptr;
|
||||
friend inline void raw::intrusive_ptr::incref(intrusive_ptr_target* self);
|
||||
friend inline void raw::intrusive_ptr::decref(intrusive_ptr_target* self);
|
||||
friend inline void raw::weak_intrusive_ptr::incref(
|
||||
intrusive_ptr_target* self);
|
||||
friend inline void raw::weak_intrusive_ptr::decref(
|
||||
intrusive_ptr_target* self);
|
||||
};
|
||||
|
||||
namespace raw {
|
||||
namespace intrusive_ptr {
|
||||
inline void incref(intrusive_ptr_target* self) {
|
||||
if (self) {
|
||||
detail::atomic_combined_refcount_increment(&self->combined_refcount_,
|
||||
detail::kReferenceCountOne);
|
||||
}
|
||||
}
|
||||
inline void decref(intrusive_ptr_target* self) {
|
||||
if (self) {
|
||||
uint64_t new_count = detail::atomic_combined_refcount_decrement(
|
||||
&self->combined_refcount_, detail::kReferenceCountOne);
|
||||
if (detail::refcount(new_count) == 0) {
|
||||
// All strong references gone; release the implicit weak reference
|
||||
// (strong refs count as +1 to weakcount per the kUniqueRef invariant).
|
||||
if (detail::atomic_weakcount_decrement(&self->combined_refcount_) == 0) {
|
||||
delete self;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace intrusive_ptr
|
||||
namespace weak_intrusive_ptr {
|
||||
inline void incref(intrusive_ptr_target* self) {
|
||||
if (self) {
|
||||
detail::atomic_weakcount_increment(&self->combined_refcount_);
|
||||
}
|
||||
}
|
||||
inline void decref(intrusive_ptr_target* self) {
|
||||
if (self) {
|
||||
if (detail::atomic_weakcount_decrement(&self->combined_refcount_) == 0) {
|
||||
delete self;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace weak_intrusive_ptr
|
||||
} // namespace raw
|
||||
|
||||
template <class TTarget, class NullType>
|
||||
class weak_intrusive_ptr;
|
||||
|
||||
template <class TTarget,
|
||||
class NullType = detail::intrusive_target_default_null_type<TTarget>>
|
||||
class intrusive_ptr final {
|
||||
private:
|
||||
static_assert(
|
||||
std::is_base_of_v<TTarget,
|
||||
std::remove_pointer_t<decltype(NullType::singleton())>>,
|
||||
"NullType::singleton() must return a element_type* pointer");
|
||||
|
||||
TTarget* target_;
|
||||
|
||||
template <class TTarget2, class NullType2>
|
||||
friend class intrusive_ptr;
|
||||
friend class weak_intrusive_ptr<TTarget, NullType>;
|
||||
|
||||
void retain_() noexcept {
|
||||
if (target_ != NullType::singleton()) {
|
||||
detail::atomic_combined_refcount_increment(&target_->combined_refcount_,
|
||||
detail::kReferenceCountOne);
|
||||
}
|
||||
}
|
||||
|
||||
void reset_() noexcept {
|
||||
if (target_ != NullType::singleton()) {
|
||||
uint64_t new_count = detail::atomic_combined_refcount_decrement(
|
||||
&target_->combined_refcount_, detail::kReferenceCountOne);
|
||||
if (detail::refcount(new_count) == 0) {
|
||||
// All strong references gone; release the implicit weak reference
|
||||
// (strong refs count as +1 to weakcount per the kUniqueRef invariant).
|
||||
if (detail::atomic_weakcount_decrement(&target_->combined_refcount_) ==
|
||||
0) {
|
||||
delete target_;
|
||||
}
|
||||
}
|
||||
target_ = NullType::singleton();
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
using element_type = TTarget;
|
||||
using pointer = TTarget*;
|
||||
|
||||
intrusive_ptr() noexcept : target_(NullType::singleton()) {}
|
||||
|
||||
intrusive_ptr(std::nullptr_t) noexcept : target_(NullType::singleton()) {}
|
||||
|
||||
explicit intrusive_ptr(TTarget* raw) : target_(raw) {
|
||||
if (target_ != NullType::singleton()) {
|
||||
target_->combined_refcount_.store(detail::kUniqueRef,
|
||||
std::memory_order_relaxed);
|
||||
}
|
||||
}
|
||||
|
||||
intrusive_ptr(const intrusive_ptr& rhs) : target_(rhs.target_) { retain_(); }
|
||||
|
||||
intrusive_ptr(intrusive_ptr&& rhs) noexcept : target_(rhs.target_) {
|
||||
rhs.target_ = NullType::singleton();
|
||||
}
|
||||
|
||||
template <typename From, typename FromNullType>
|
||||
/* implicit */ intrusive_ptr(
|
||||
const intrusive_ptr<From, FromNullType>& rhs) noexcept
|
||||
: target_(rhs.target_) {
|
||||
static_assert(std::is_convertible_v<From*, TTarget*>,
|
||||
"Source type must be convertible to target type");
|
||||
retain_();
|
||||
}
|
||||
|
||||
template <typename From, typename FromNullType>
|
||||
/* implicit */ intrusive_ptr(intrusive_ptr<From, FromNullType>&& rhs) noexcept
|
||||
: target_(rhs.target_) {
|
||||
static_assert(std::is_convertible_v<From*, TTarget*>,
|
||||
"Source type must be convertible to target type");
|
||||
rhs.target_ = FromNullType::singleton();
|
||||
}
|
||||
|
||||
~intrusive_ptr() { reset_(); }
|
||||
|
||||
intrusive_ptr& operator=(const intrusive_ptr& rhs) {
|
||||
if (this != &rhs) {
|
||||
reset_();
|
||||
target_ = rhs.target_;
|
||||
retain_();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
intrusive_ptr& operator=(intrusive_ptr&& rhs) noexcept {
|
||||
if (this != &rhs) {
|
||||
reset_();
|
||||
target_ = rhs.target_;
|
||||
rhs.target_ = NullType::singleton();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Takes ownership of a raw pointer without incrementing the refcount.
|
||||
static intrusive_ptr reclaim(TTarget* raw_ptr) {
|
||||
intrusive_ptr result;
|
||||
result.target_ = raw_ptr;
|
||||
return result;
|
||||
}
|
||||
|
||||
// unsafe_adopt is a PyTorch API compatibility alias for reclaim().
|
||||
// Both adopt a raw pointer without incrementing the refcount; prefer
|
||||
// reclaim() in new code.
|
||||
static intrusive_ptr unsafe_adopt(TTarget* raw_ptr) {
|
||||
return reclaim(raw_ptr);
|
||||
}
|
||||
|
||||
TTarget* get() const noexcept { return target_; }
|
||||
|
||||
TTarget& operator*() const { return *target_; }
|
||||
|
||||
TTarget* operator->() const { return target_; }
|
||||
|
||||
explicit operator bool() const noexcept {
|
||||
return target_ != NullType::singleton();
|
||||
}
|
||||
|
||||
uint32_t use_count() const noexcept {
|
||||
if (target_ == NullType::singleton()) {
|
||||
return 0;
|
||||
}
|
||||
return target_->refcount();
|
||||
}
|
||||
|
||||
bool defined() const noexcept { return target_ != NullType::singleton(); }
|
||||
|
||||
bool unique() const noexcept { return use_count() == 1; }
|
||||
|
||||
void reset() noexcept { reset_(); }
|
||||
|
||||
void swap(intrusive_ptr& other) noexcept {
|
||||
using std::swap;
|
||||
swap(target_, other.target_);
|
||||
}
|
||||
|
||||
[[deprecated(
|
||||
"intrusive_ptr::release is unsafe; use reclaim() or explicit ownership "
|
||||
"transfer instead")]] TTarget*
|
||||
release() noexcept {
|
||||
TTarget* result = target_;
|
||||
target_ = NullType::singleton();
|
||||
return result;
|
||||
}
|
||||
|
||||
bool operator==(const intrusive_ptr& rhs) const noexcept {
|
||||
return target_ == rhs.target_;
|
||||
}
|
||||
bool operator!=(const intrusive_ptr& rhs) const noexcept {
|
||||
return target_ != rhs.target_;
|
||||
}
|
||||
bool operator==(std::nullptr_t) const noexcept {
|
||||
return target_ == NullType::singleton();
|
||||
}
|
||||
bool operator!=(std::nullptr_t) const noexcept {
|
||||
return target_ != NullType::singleton();
|
||||
}
|
||||
};
|
||||
|
||||
template <class TTarget,
|
||||
class NullType = detail::intrusive_target_default_null_type<TTarget>>
|
||||
class weak_intrusive_ptr final {
|
||||
private:
|
||||
TTarget* target_;
|
||||
|
||||
template <class TTarget2, class NullType2>
|
||||
friend class weak_intrusive_ptr;
|
||||
friend class intrusive_ptr<TTarget, NullType>;
|
||||
|
||||
void retain_() {
|
||||
if (target_ != NullType::singleton()) {
|
||||
detail::atomic_weakcount_increment(&target_->combined_refcount_);
|
||||
}
|
||||
}
|
||||
|
||||
void reset_() noexcept {
|
||||
if (target_ != NullType::singleton()) {
|
||||
if (detail::atomic_weakcount_decrement(&target_->combined_refcount_) ==
|
||||
0) {
|
||||
delete target_;
|
||||
}
|
||||
target_ = NullType::singleton();
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
using element_type = TTarget;
|
||||
|
||||
weak_intrusive_ptr() noexcept : target_(NullType::singleton()) {}
|
||||
|
||||
weak_intrusive_ptr(const intrusive_ptr<TTarget, NullType>& p)
|
||||
: target_(p.target_) {
|
||||
retain_();
|
||||
}
|
||||
|
||||
weak_intrusive_ptr(const weak_intrusive_ptr& rhs) : target_(rhs.target_) {
|
||||
retain_();
|
||||
}
|
||||
|
||||
weak_intrusive_ptr(weak_intrusive_ptr&& rhs) noexcept : target_(rhs.target_) {
|
||||
rhs.target_ = NullType::singleton();
|
||||
}
|
||||
|
||||
~weak_intrusive_ptr() { reset_(); }
|
||||
|
||||
weak_intrusive_ptr& operator=(const weak_intrusive_ptr& rhs) {
|
||||
if (this != &rhs) {
|
||||
reset_();
|
||||
target_ = rhs.target_;
|
||||
retain_();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
weak_intrusive_ptr& operator=(weak_intrusive_ptr&& rhs) {
|
||||
if (this != &rhs) {
|
||||
reset_();
|
||||
target_ = rhs.target_;
|
||||
rhs.target_ = NullType::singleton();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
intrusive_ptr<TTarget, NullType> lock() const {
|
||||
if (target_ == NullType::singleton()) {
|
||||
return intrusive_ptr<TTarget, NullType>();
|
||||
}
|
||||
auto& atomic = target_->combined_refcount_;
|
||||
uint64_t count = atomic.load(std::memory_order_relaxed);
|
||||
while (true) {
|
||||
if (detail::refcount(count) == 0) {
|
||||
return intrusive_ptr<TTarget, NullType>();
|
||||
}
|
||||
if (atomic.compare_exchange_weak(count,
|
||||
count + detail::kReferenceCountOne,
|
||||
std::memory_order_acq_rel,
|
||||
std::memory_order_relaxed)) {
|
||||
return intrusive_ptr<TTarget, NullType>::unsafe_adopt(target_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t use_count() const {
|
||||
if (target_ == NullType::singleton()) {
|
||||
return 0;
|
||||
}
|
||||
return target_->refcount();
|
||||
}
|
||||
|
||||
bool expired() const { return use_count() == 0; }
|
||||
|
||||
void reset() { reset_(); }
|
||||
};
|
||||
|
||||
// Creates a new T with an initial strong refcount of 1.
|
||||
template <typename T, typename... Args>
|
||||
intrusive_ptr<T> make_intrusive(Args&&... args) {
|
||||
return intrusive_ptr<T>(new T(std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
} // namespace c10
|
||||
@@ -0,0 +1,43 @@
|
||||
// Copyright (c) 2026 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// The file has been adapted from pytorch project
|
||||
// Licensed under BSD-style license -
|
||||
// https://github.com/pytorch/pytorch/blob/main/LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace c10 {
|
||||
|
||||
/**
|
||||
* qint32 is for signed 32 bit quantized Tensors
|
||||
*/
|
||||
struct alignas(4) qint32 {
|
||||
using underlying = int32_t;
|
||||
int32_t val_;
|
||||
qint32() = default;
|
||||
explicit constexpr qint32(int32_t val) : val_(val) {}
|
||||
};
|
||||
|
||||
} // namespace c10
|
||||
|
||||
namespace at {
|
||||
using c10::qint32;
|
||||
} // namespace at
|
||||
|
||||
namespace torch {
|
||||
using c10::qint32;
|
||||
} // namespace torch
|
||||
@@ -0,0 +1,45 @@
|
||||
// Copyright (c) 2026 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// The file has been adapted from pytorch project
|
||||
// Licensed under BSD-style license -
|
||||
// https://github.com/pytorch/pytorch/blob/main/LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace c10 {
|
||||
|
||||
/**
|
||||
* This is the data type for quantized Tensors. Right now we only have
|
||||
* qint8 which is for 8 bit Tensors, and qint32 for 32 bit int Tensors,
|
||||
* we might have 4 bit, 2 bit or 1 bit data types in the future.
|
||||
*/
|
||||
struct alignas(1) qint8 {
|
||||
using underlying = int8_t;
|
||||
int8_t val_;
|
||||
qint8() = default;
|
||||
explicit constexpr qint8(int8_t val) : val_(val) {}
|
||||
};
|
||||
|
||||
} // namespace c10
|
||||
|
||||
namespace at {
|
||||
using c10::qint8;
|
||||
} // namespace at
|
||||
|
||||
namespace torch {
|
||||
using c10::qint8;
|
||||
} // namespace torch
|
||||
@@ -0,0 +1,44 @@
|
||||
// Copyright (c) 2026 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// The file has been adapted from pytorch project
|
||||
// Licensed under BSD-style license -
|
||||
// https://github.com/pytorch/pytorch/blob/main/LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace c10 {
|
||||
|
||||
/**
|
||||
* quint2x4 is for un-signed 2 bit quantized Tensors that are packed to byte
|
||||
* boundary.
|
||||
*/
|
||||
struct alignas(1) quint2x4 {
|
||||
using underlying = uint8_t;
|
||||
uint8_t val_;
|
||||
quint2x4() = default;
|
||||
explicit constexpr quint2x4(uint8_t val) : val_(val) {}
|
||||
};
|
||||
|
||||
} // namespace c10
|
||||
|
||||
namespace at {
|
||||
using c10::quint2x4;
|
||||
} // namespace at
|
||||
|
||||
namespace torch {
|
||||
using c10::quint2x4;
|
||||
} // namespace torch
|
||||
@@ -0,0 +1,44 @@
|
||||
// Copyright (c) 2026 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// The file has been adapted from pytorch project
|
||||
// Licensed under BSD-style license -
|
||||
// https://github.com/pytorch/pytorch/blob/main/LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace c10 {
|
||||
|
||||
/**
|
||||
* quint4x2 is for un-signed 4 bit quantized Tensors that are packed to byte
|
||||
* boundary.
|
||||
*/
|
||||
struct alignas(1) quint4x2 {
|
||||
using underlying = uint8_t;
|
||||
uint8_t val_;
|
||||
quint4x2() = default;
|
||||
explicit constexpr quint4x2(uint8_t val) : val_(val) {}
|
||||
};
|
||||
|
||||
} // namespace c10
|
||||
|
||||
namespace at {
|
||||
using c10::quint4x2;
|
||||
} // namespace at
|
||||
|
||||
namespace torch {
|
||||
using c10::quint4x2;
|
||||
} // namespace torch
|
||||
@@ -0,0 +1,43 @@
|
||||
// Copyright (c) 2026 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// The file has been adapted from pytorch project
|
||||
// Licensed under BSD-style license -
|
||||
// https://github.com/pytorch/pytorch/blob/main/LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace c10 {
|
||||
|
||||
/**
|
||||
* quint8 is for unsigned 8 bit quantized Tensors
|
||||
*/
|
||||
struct alignas(1) quint8 {
|
||||
using underlying = uint8_t;
|
||||
uint8_t val_;
|
||||
quint8() = default;
|
||||
explicit constexpr quint8(uint8_t val) : val_(val) {}
|
||||
};
|
||||
|
||||
} // namespace c10
|
||||
|
||||
namespace at {
|
||||
using c10::quint8;
|
||||
} // namespace at
|
||||
|
||||
namespace torch {
|
||||
using c10::quint8;
|
||||
} // namespace torch
|
||||
@@ -0,0 +1,98 @@
|
||||
// Copyright (c) 2026 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// The file has been adapted from pytorch project
|
||||
// Licensed under BSD-style license -
|
||||
// https://github.com/pytorch/pytorch/blob/main/LICENSE
|
||||
|
||||
#include <c10/util/typeid.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace caffe2 {
|
||||
|
||||
std::mutex& TypeMeta::getTypeMetaDatasLock() {
|
||||
static std::mutex lock;
|
||||
return lock;
|
||||
}
|
||||
|
||||
uint16_t TypeMeta::nextTypeIndex(
|
||||
static_cast<uint16_t>(c10::ScalarType::NumOptions));
|
||||
|
||||
detail::TypeMetaData* TypeMeta::typeMetaDatas() {
|
||||
static detail::TypeMetaData instances[kMaxTypeIndex + 1] = {
|
||||
#define SCALAR_TYPE_META(T, _2, name) \
|
||||
detail::TypeMetaData(sizeof(T), \
|
||||
detail::_PickNew<T>(), \
|
||||
detail::_PickPlacementNew<T>(), \
|
||||
detail::_PickCopy<T>(), \
|
||||
detail::_PickPlacementDelete<T>(), \
|
||||
detail::_PickDelete<T>(), \
|
||||
TypeIdentifier::Get<T>(), \
|
||||
#name),
|
||||
AT_FORALL_SCALAR_TYPES_WITH_COMPLEX_AND_QINTS(SCALAR_TYPE_META)
|
||||
#undef SCALAR_TYPE_META
|
||||
// Remaining entries default-initialize to empty TypeMetaData.
|
||||
};
|
||||
|
||||
static std::once_flag init_once;
|
||||
std::call_once(init_once, [] {
|
||||
instances[static_cast<uint16_t>(c10::ScalarType::Undefined)] =
|
||||
detail::TypeMetaData{0,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
TypeIdentifier::Get<detail::_Uninitialized>(),
|
||||
"Undefined"};
|
||||
});
|
||||
|
||||
return instances;
|
||||
}
|
||||
|
||||
uint16_t TypeMeta::existingMetaDataIndexForType(TypeIdentifier identifier) {
|
||||
auto* meta_datas = typeMetaDatas();
|
||||
const auto end = meta_datas + nextTypeIndex;
|
||||
auto it = std::find_if(meta_datas, end, [identifier](const auto& meta_data) {
|
||||
return meta_data.id_ == identifier;
|
||||
});
|
||||
if (it == end) {
|
||||
return kMaxTypeIndex;
|
||||
}
|
||||
return static_cast<uint16_t>(it - meta_datas);
|
||||
}
|
||||
|
||||
CAFFE_DEFINE_KNOWN_TYPE(std::string, std_string)
|
||||
CAFFE_DEFINE_KNOWN_TYPE(char, char)
|
||||
CAFFE_DEFINE_KNOWN_TYPE(std::unique_ptr<std::mutex>, std_unique_ptr_std_mutex)
|
||||
CAFFE_DEFINE_KNOWN_TYPE(std::unique_ptr<std::atomic<bool>>,
|
||||
std_unique_ptr_std_atomic_bool)
|
||||
CAFFE_DEFINE_KNOWN_TYPE(std::vector<int32_t>, std_vector_int32_t)
|
||||
CAFFE_DEFINE_KNOWN_TYPE(std::vector<int64_t>, std_vector_int64_t)
|
||||
CAFFE_DEFINE_KNOWN_TYPE(std::vector<unsigned long>, // NOLINT(runtime/int)
|
||||
std_vector_unsigned_long)
|
||||
CAFFE_DEFINE_KNOWN_TYPE(bool*, bool_ptr)
|
||||
CAFFE_DEFINE_KNOWN_TYPE(char*, char_ptr)
|
||||
CAFFE_DEFINE_KNOWN_TYPE(int*, int_ptr)
|
||||
CAFFE_DEFINE_KNOWN_TYPE(
|
||||
detail::_guard_long_unique<long>, // NOLINT(runtime/int)
|
||||
detail_guard_long_unique_long)
|
||||
CAFFE_DEFINE_KNOWN_TYPE(
|
||||
detail::_guard_long_unique<std::vector<long>>, // NOLINT(runtime/int)
|
||||
detail_guard_long_unique_std_vector_long)
|
||||
CAFFE_DEFINE_KNOWN_TYPE(float*, float_ptr)
|
||||
CAFFE_DEFINE_KNOWN_TYPE(at::Half*, at_Half)
|
||||
|
||||
} // namespace caffe2
|
||||
@@ -0,0 +1,652 @@
|
||||
// Copyright (c) 2026 PaddlePaddle Authors. All Rights Reserved.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// The file has been adapted from pytorch project
|
||||
// Licensed under BSD-style license -
|
||||
// https://github.com/pytorch/pytorch/blob/main/LICENSE
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <c10/macros/Macros.h>
|
||||
#include <c10/util/BFloat16.h>
|
||||
#include <c10/util/Exception.h>
|
||||
#include <c10/util/Float8_e4m3fn.h>
|
||||
#include <c10/util/Float8_e5m2.h>
|
||||
#include <c10/util/Half.h>
|
||||
#include <c10/util/TypeIndex.h>
|
||||
|
||||
#include <c10/core/ScalarType.h>
|
||||
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#include "paddle/common/enforce.h"
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Auxiliary macros not provided by the compat Macros.h
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#ifndef C10_LIKELY
|
||||
#ifdef _MSC_VER
|
||||
#define C10_LIKELY(val) (val)
|
||||
#else
|
||||
#define C10_LIKELY(val) (__builtin_expect(static_cast<bool>(val), 1))
|
||||
#endif
|
||||
#endif
|
||||
#ifndef C10_UNLIKELY
|
||||
#ifdef _MSC_VER
|
||||
#define C10_UNLIKELY(val) (val)
|
||||
#else
|
||||
#define C10_UNLIKELY(val) (__builtin_expect(static_cast<bool>(val), 0))
|
||||
#endif
|
||||
#endif
|
||||
#ifndef C10_API
|
||||
#define C10_API PADDLE_API
|
||||
#endif
|
||||
#ifndef C10_EXPORT
|
||||
#ifdef _MSC_VER
|
||||
#define C10_EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define C10_EXPORT __attribute__((visibility("default")))
|
||||
#endif
|
||||
#endif
|
||||
#ifndef C10_ALWAYS_INLINE
|
||||
#ifdef _MSC_VER
|
||||
#define C10_ALWAYS_INLINE __forceinline
|
||||
#else
|
||||
#define C10_ALWAYS_INLINE __attribute__((always_inline)) inline
|
||||
#endif
|
||||
#endif
|
||||
#ifndef TORCH_INTERNAL_ASSERT_DEBUG_ONLY
|
||||
#ifdef NDEBUG
|
||||
#define TORCH_INTERNAL_ASSERT_DEBUG_ONLY(...) ((void)0)
|
||||
#else
|
||||
#define TORCH_INTERNAL_ASSERT_DEBUG_ONLY(...) TORCH_INTERNAL_ASSERT(__VA_ARGS__)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// caffe2::TypeIdentifier
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
namespace caffe2 {
|
||||
|
||||
/**
|
||||
* A unique run-time type identifier.
|
||||
*/
|
||||
class C10_API TypeIdentifier final {
|
||||
public:
|
||||
friend std::ostream& operator<<(std::ostream& stream, TypeIdentifier typeId);
|
||||
friend bool operator<(TypeIdentifier lhs, TypeIdentifier rhs) noexcept;
|
||||
|
||||
template <typename T>
|
||||
static constexpr TypeIdentifier Get() noexcept {
|
||||
return TypeIdentifier(c10::util::get_type_index<T>());
|
||||
}
|
||||
|
||||
static constexpr TypeIdentifier uninitialized() noexcept {
|
||||
return TypeIdentifier(c10::util::type_index{0});
|
||||
}
|
||||
|
||||
uint64_t underlyingId() const noexcept { return id_.underlyingId(); }
|
||||
|
||||
bool operator==(TypeIdentifier other) const noexcept {
|
||||
return id_ == other.id_;
|
||||
}
|
||||
bool operator!=(TypeIdentifier other) const noexcept {
|
||||
return id_ != other.id_;
|
||||
}
|
||||
|
||||
private:
|
||||
constexpr explicit TypeIdentifier(c10::util::type_index id) noexcept
|
||||
: id_(id) {}
|
||||
c10::util::type_index id_;
|
||||
};
|
||||
|
||||
inline bool operator<(TypeIdentifier lhs, TypeIdentifier rhs) noexcept {
|
||||
return lhs.id_ < rhs.id_;
|
||||
}
|
||||
inline std::ostream& operator<<(std::ostream& stream, TypeIdentifier typeId) {
|
||||
return stream << typeId.underlyingId();
|
||||
}
|
||||
|
||||
} // namespace caffe2
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// at::DataType alias
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
namespace at {
|
||||
using DataType = caffe2::TypeIdentifier;
|
||||
} // namespace at
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// std::hash specialisation so TypeIdentifier can be used in unordered maps
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
namespace std {
|
||||
template <>
|
||||
struct hash<caffe2::TypeIdentifier> {
|
||||
std::size_t operator()(caffe2::TypeIdentifier id) const noexcept {
|
||||
return id.underlyingId();
|
||||
}
|
||||
};
|
||||
} // namespace std
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// caffe2::detail – TypeMetaData + helper templates
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
namespace caffe2 {
|
||||
namespace detail {
|
||||
|
||||
/**
|
||||
* Per-type metadata record. One instance lives per registered type.
|
||||
*/
|
||||
struct TypeMetaData final {
|
||||
using New = void*();
|
||||
using PlacementNew = void(void*, size_t);
|
||||
using Copy = void(const void*, void*, size_t);
|
||||
using PlacementDelete = void(void*, size_t);
|
||||
using Delete = void(void*);
|
||||
|
||||
constexpr TypeMetaData() noexcept
|
||||
: itemsize_(0),
|
||||
new_(nullptr),
|
||||
placementNew_(nullptr),
|
||||
copy_(nullptr),
|
||||
placementDelete_(nullptr),
|
||||
delete_(nullptr),
|
||||
id_(TypeIdentifier::uninitialized()),
|
||||
name_("nullptr (uninitialized)") {}
|
||||
|
||||
constexpr TypeMetaData(size_t itemsize,
|
||||
New* newFn,
|
||||
PlacementNew* placementNew,
|
||||
Copy* copy,
|
||||
PlacementDelete* placementDelete,
|
||||
Delete* deleteFn,
|
||||
TypeIdentifier id,
|
||||
std::string_view name) noexcept
|
||||
: itemsize_(itemsize),
|
||||
new_(newFn),
|
||||
placementNew_(placementNew),
|
||||
copy_(copy),
|
||||
placementDelete_(placementDelete),
|
||||
delete_(deleteFn),
|
||||
id_(id),
|
||||
name_(name) {}
|
||||
|
||||
size_t itemsize_;
|
||||
New* new_;
|
||||
PlacementNew* placementNew_;
|
||||
Copy* copy_;
|
||||
PlacementDelete* placementDelete_;
|
||||
Delete* delete_;
|
||||
TypeIdentifier id_;
|
||||
std::string_view name_;
|
||||
};
|
||||
|
||||
// Error helper – keeps this header free of heavy includes.
|
||||
[[noreturn]] inline void _ThrowRuntimeTypeLogicError(const std::string& msg) {
|
||||
PADDLE_THROW(common::errors::InvalidArgument(msg));
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Trait: treat reduced-precision scalars as "fundamental" (skip ctor/dtor).
|
||||
// ---------------------------------------------------------------------------
|
||||
template <typename T>
|
||||
struct is_paddle_fundamental : std::is_fundamental<T> {};
|
||||
template <>
|
||||
struct is_paddle_fundamental<at::Half> : std::true_type {};
|
||||
template <>
|
||||
struct is_paddle_fundamental<at::BFloat16> : std::true_type {};
|
||||
template <>
|
||||
struct is_paddle_fundamental<c10::Float8_e4m3fn> : std::true_type {};
|
||||
template <>
|
||||
struct is_paddle_fundamental<c10::Float8_e5m2> : std::true_type {};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// PlacementNew helpers
|
||||
// ---------------------------------------------------------------------------
|
||||
template <typename T>
|
||||
inline void _PlacementNew(void* ptr, size_t n) {
|
||||
T* typed_ptr = static_cast<T*>(ptr);
|
||||
for (size_t i = 0; i < n; ++i) new (typed_ptr + i) T;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void _PlacementNewNotDefault(void* /*ptr*/, size_t /*n*/) {
|
||||
_ThrowRuntimeTypeLogicError(std::string("Type ") + typeid(T).name() +
|
||||
" is not default-constructible.");
|
||||
}
|
||||
|
||||
template <typename T,
|
||||
std::enable_if_t<std::is_default_constructible_v<T>>* = nullptr>
|
||||
inline constexpr TypeMetaData::PlacementNew* _PickPlacementNew() {
|
||||
return (is_paddle_fundamental<T>::value || std::is_pointer_v<T>)
|
||||
? nullptr
|
||||
: &_PlacementNew<T>;
|
||||
}
|
||||
|
||||
template <typename T,
|
||||
std::enable_if_t<!std::is_default_constructible_v<T>>* = nullptr>
|
||||
inline constexpr TypeMetaData::PlacementNew* _PickPlacementNew() {
|
||||
return &_PlacementNewNotDefault<T>;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// New helpers
|
||||
// ---------------------------------------------------------------------------
|
||||
template <typename T>
|
||||
inline void* _New() {
|
||||
return new T;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void* _NewNotDefault() {
|
||||
_ThrowRuntimeTypeLogicError(std::string("Type ") + typeid(T).name() +
|
||||
" is not default-constructible.");
|
||||
}
|
||||
|
||||
template <typename T,
|
||||
std::enable_if_t<std::is_default_constructible_v<T>>* = nullptr>
|
||||
inline constexpr TypeMetaData::New* _PickNew() {
|
||||
return &_New<T>;
|
||||
}
|
||||
|
||||
template <typename T,
|
||||
std::enable_if_t<!std::is_default_constructible_v<T>>* = nullptr>
|
||||
inline constexpr TypeMetaData::New* _PickNew() {
|
||||
return &_NewNotDefault<T>;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Copy helpers
|
||||
// ---------------------------------------------------------------------------
|
||||
template <typename T>
|
||||
inline void _Copy(const void* src, void* dst, size_t n) {
|
||||
const T* typed_src = static_cast<const T*>(src);
|
||||
T* typed_dst = static_cast<T*>(dst);
|
||||
for (size_t i = 0; i < n; ++i) typed_dst[i] = typed_src[i];
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void _CopyNotAllowed(const void* /*src*/, void* /*dst*/, size_t /*n*/) {
|
||||
_ThrowRuntimeTypeLogicError(std::string("Type ") + typeid(T).name() +
|
||||
" does not allow assignment.");
|
||||
}
|
||||
|
||||
template <typename T, std::enable_if_t<std::is_copy_assignable_v<T>>* = nullptr>
|
||||
inline constexpr TypeMetaData::Copy* _PickCopy() {
|
||||
return (is_paddle_fundamental<T>::value || std::is_pointer_v<T>) ? nullptr
|
||||
: &_Copy<T>;
|
||||
}
|
||||
|
||||
template <typename T,
|
||||
std::enable_if_t<!std::is_copy_assignable_v<T>>* = nullptr>
|
||||
inline constexpr TypeMetaData::Copy* _PickCopy() {
|
||||
return &_CopyNotAllowed<T>;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// PlacementDelete helpers
|
||||
// ---------------------------------------------------------------------------
|
||||
template <typename T>
|
||||
inline void _PlacementDelete(void* ptr, size_t n) {
|
||||
T* typed_ptr = static_cast<T*>(ptr);
|
||||
for (size_t i = 0; i < n; ++i) typed_ptr[i].~T();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline constexpr TypeMetaData::PlacementDelete* _PickPlacementDelete() {
|
||||
return (is_paddle_fundamental<T>::value || std::is_pointer_v<T>)
|
||||
? nullptr
|
||||
: &_PlacementDelete<T>;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Delete helpers
|
||||
// ---------------------------------------------------------------------------
|
||||
template <typename T>
|
||||
inline void _Delete(void* ptr) {
|
||||
delete static_cast<T*>(ptr);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline constexpr TypeMetaData::Delete* _PickDelete() noexcept {
|
||||
return &_Delete<T>;
|
||||
}
|
||||
|
||||
// Sentinel type for uninitialized TypeMeta.
|
||||
class _Uninitialized final {};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// caffe2::TypeMeta
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* TypeMeta is a thin class that stores the type of a container (e.g. Blob or
|
||||
* Tensor elements) with a unique run-time id. It mirrors the PyTorch / Caffe2
|
||||
* TypeMeta API so that code written against libtorch's typeid.h compiles
|
||||
* against this compat header without changes.
|
||||
*/
|
||||
class C10_API TypeMeta final {
|
||||
public:
|
||||
using New = detail::TypeMetaData::New;
|
||||
using PlacementNew = detail::TypeMetaData::PlacementNew;
|
||||
using Copy = detail::TypeMetaData::Copy;
|
||||
using PlacementDelete = detail::TypeMetaData::PlacementDelete;
|
||||
using Delete = detail::TypeMetaData::Delete;
|
||||
|
||||
// Default-constructs to "Undefined / uninitialized".
|
||||
// NOTE: body is defined AFTER the _Uninitialized specialization below
|
||||
// to avoid "specialization after instantiation" errors.
|
||||
TypeMeta() noexcept;
|
||||
~TypeMeta() = default;
|
||||
|
||||
TypeMeta(const TypeMeta& src) noexcept = default;
|
||||
TypeMeta& operator=(const TypeMeta& src) noexcept = default;
|
||||
TypeMeta(TypeMeta&& src) noexcept = default;
|
||||
TypeMeta& operator=(TypeMeta&& src) noexcept = default;
|
||||
|
||||
inline TypeMeta& operator=(c10::ScalarType scalar_type) noexcept {
|
||||
index_ = static_cast<uint16_t>(scalar_type);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// Accessors
|
||||
// ------------------------------------------------------------------
|
||||
TypeIdentifier id() const noexcept { return data().id_; }
|
||||
|
||||
inline bool isScalarType() const noexcept {
|
||||
return index_ <= static_cast<uint16_t>(c10::ScalarType::Undefined);
|
||||
}
|
||||
inline bool isScalarType(c10::ScalarType scalar_type) const noexcept {
|
||||
return index_ == static_cast<uint16_t>(scalar_type);
|
||||
}
|
||||
|
||||
inline size_t itemsize() const noexcept { return data().itemsize_; }
|
||||
|
||||
New* newFn() const noexcept { return data().new_; }
|
||||
PlacementNew* placementNew() const noexcept { return data().placementNew_; }
|
||||
Copy* copy() const noexcept { return data().copy_; }
|
||||
PlacementDelete* placementDelete() const noexcept {
|
||||
return data().placementDelete_;
|
||||
}
|
||||
Delete* deleteFn() const noexcept { return data().delete_; }
|
||||
std::string_view name() const noexcept { return data().name_; }
|
||||
|
||||
friend bool operator==(const TypeMeta& lhs, const TypeMeta& rhs) noexcept;
|
||||
|
||||
template <typename T>
|
||||
bool Match() const noexcept {
|
||||
return *this == Make<T>();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// Static helpers
|
||||
// ------------------------------------------------------------------
|
||||
template <class T>
|
||||
static constexpr TypeIdentifier Id() noexcept {
|
||||
return TypeIdentifier::Get<T>();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static std::string_view TypeName() noexcept {
|
||||
return typeid(T).name();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static constexpr size_t ItemSize() noexcept {
|
||||
return sizeof(T);
|
||||
}
|
||||
|
||||
/** Returns a TypeMeta for type T. */
|
||||
template <typename T>
|
||||
static TypeMeta Make() {
|
||||
return TypeMeta(_typeMetaData<T>());
|
||||
}
|
||||
|
||||
/** Convert ScalarType enum → TypeMeta. */
|
||||
static inline TypeMeta fromScalarType(c10::ScalarType scalar_type) {
|
||||
const auto index = static_cast<uint16_t>(scalar_type);
|
||||
TORCH_INTERNAL_ASSERT_DEBUG_ONLY(
|
||||
index <= static_cast<uint16_t>(c10::ScalarType::Undefined),
|
||||
"Unrecognized ScalarType");
|
||||
return TypeMeta(index);
|
||||
}
|
||||
|
||||
/** Convert TypeMeta → ScalarType enum. */
|
||||
inline c10::ScalarType toScalarType() const {
|
||||
if (C10_LIKELY(isScalarType())) {
|
||||
return static_cast<c10::ScalarType>(index_);
|
||||
}
|
||||
PADDLE_THROW(common::errors::InvalidArgument(
|
||||
"Unsupported TypeMeta in toScalarType (index=%d)",
|
||||
static_cast<int>(index_)));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// Dynamic type registration (mirrors CAFFE_KNOWN_TYPE machinery)
|
||||
// ------------------------------------------------------------------
|
||||
template <class T>
|
||||
static uint16_t addTypeMetaData() {
|
||||
const auto identifier = TypeIdentifier::Get<T>();
|
||||
std::lock_guard<std::mutex> lock(getTypeMetaDatasLock());
|
||||
// Check whether already registered (e.g. from another DSO).
|
||||
const uint16_t existing = existingMetaDataIndexForType(identifier);
|
||||
if (existing != kMaxTypeIndex) return existing;
|
||||
const uint16_t index = nextTypeIndex++;
|
||||
TORCH_CHECK(index <= kMaxTypeIndex,
|
||||
"Maximum number of CAFFE_KNOWN_TYPE declarations exceeded.");
|
||||
typeMetaDatas()[index] =
|
||||
detail::TypeMetaData{sizeof(T),
|
||||
detail::_PickNew<T>(),
|
||||
detail::_PickPlacementNew<T>(),
|
||||
detail::_PickCopy<T>(),
|
||||
detail::_PickPlacementDelete<T>(),
|
||||
detail::_PickDelete<T>(),
|
||||
identifier,
|
||||
typeid(T).name()};
|
||||
return index;
|
||||
}
|
||||
|
||||
private:
|
||||
explicit TypeMeta(uint16_t index) noexcept : index_(index) {}
|
||||
|
||||
// Maximum number of type-metadata slots (scalar + custom).
|
||||
static constexpr uint16_t kMaxTypeIndex = 255;
|
||||
|
||||
static std::mutex& getTypeMetaDatasLock();
|
||||
|
||||
static uint16_t nextTypeIndex;
|
||||
|
||||
static detail::TypeMetaData* typeMetaDatas();
|
||||
|
||||
static uint16_t existingMetaDataIndexForType(TypeIdentifier identifier);
|
||||
|
||||
// Template specialisations return indexes into typeMetaDatas().
|
||||
// Defined below the class for scalar types; compiled-in for custom types.
|
||||
template <class T>
|
||||
static uint16_t _typeMetaData() noexcept;
|
||||
|
||||
uint16_t index_;
|
||||
|
||||
inline const detail::TypeMetaData& data() const {
|
||||
return typeMetaDatas()[index_];
|
||||
}
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Specialisations of TypeMeta::_typeMetaData for ScalarType types
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// 3-argument AT_FORALL_SCALAR_TYPES_WITH_COMPLEX_AND_QINTS
|
||||
#define DEFINE_SCALAR_METADATA_INSTANCE(T, _2, name) \
|
||||
template <> \
|
||||
inline constexpr uint16_t TypeMeta::_typeMetaData<T>() noexcept { \
|
||||
return static_cast<uint16_t>(c10::ScalarType::name); \
|
||||
}
|
||||
AT_FORALL_SCALAR_TYPES_WITH_COMPLEX_AND_QINTS(DEFINE_SCALAR_METADATA_INSTANCE)
|
||||
#undef DEFINE_SCALAR_METADATA_INSTANCE
|
||||
|
||||
// _Uninitialized → Undefined slot
|
||||
template <>
|
||||
inline constexpr uint16_t
|
||||
TypeMeta::_typeMetaData<detail::_Uninitialized>() noexcept {
|
||||
return static_cast<uint16_t>(c10::ScalarType::Undefined);
|
||||
}
|
||||
|
||||
// Default constructor defined here so that _typeMetaData<_Uninitialized> is
|
||||
// already specialised before it is first called.
|
||||
inline TypeMeta::TypeMeta() noexcept
|
||||
: index_(_typeMetaData<detail::_Uninitialized>()) {}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Comparison / stream operators
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
inline bool operator==(const TypeMeta& lhs, const TypeMeta& rhs) noexcept {
|
||||
return lhs.index_ == rhs.index_;
|
||||
}
|
||||
inline bool operator!=(const TypeMeta& lhs, const TypeMeta& rhs) noexcept {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
inline std::ostream& operator<<(std::ostream& stream,
|
||||
caffe2::TypeMeta typeMeta) {
|
||||
return stream << typeMeta.name();
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// CAFFE_KNOWN_TYPE macros (compat versions)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#if defined(_MSC_VER) || defined(__clang__)
|
||||
#define EXPORT_IF_NOT_GCC C10_EXPORT
|
||||
#else
|
||||
#define EXPORT_IF_NOT_GCC
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#define C10_TEMPLATE_API C10_API
|
||||
#else
|
||||
#define C10_TEMPLATE_API
|
||||
#endif
|
||||
|
||||
// For use in a .cpp file.
|
||||
#define CAFFE_KNOWN_TYPE(T) \
|
||||
template C10_TEMPLATE_API uint16_t TypeMeta::addTypeMetaData<T>(); \
|
||||
template <> \
|
||||
EXPORT_IF_NOT_GCC uint16_t TypeMeta::_typeMetaData<T>() noexcept { \
|
||||
static const uint16_t index = addTypeMetaData<T>(); \
|
||||
return index; \
|
||||
}
|
||||
|
||||
// For use in a .cpp file when a declaration in the header is provided.
|
||||
#define CAFFE_DEFINE_KNOWN_TYPE(T, ident) \
|
||||
template C10_TEMPLATE_API uint16_t TypeMeta::addTypeMetaData<T>(); \
|
||||
namespace detail { \
|
||||
EXPORT_IF_NOT_GCC extern const uint16_t ident##_metadata_index = \
|
||||
TypeMeta::addTypeMetaData<T>(); \
|
||||
} /* namespace detail */
|
||||
|
||||
// Declaration counterpart: provides an inline fast-path via a detail var.
|
||||
// NOTE: On MSVC, directly referencing cross-DLL const data symbols is fragile
|
||||
// and can cause unresolved externals during libpaddle linking. Use a
|
||||
// function-local static cache there and keep non-MSVC behavior aligned with
|
||||
// upstream declare/define model.
|
||||
#if defined(_MSC_VER)
|
||||
#define CAFFE_DECLARE_KNOWN_TYPE(T, ident) \
|
||||
extern template C10_API uint16_t TypeMeta::addTypeMetaData<T>(); \
|
||||
namespace detail { \
|
||||
extern C10_API const uint16_t ident##_metadata_index; \
|
||||
} /* namespace detail */ \
|
||||
template <> \
|
||||
C10_ALWAYS_INLINE uint16_t TypeMeta::_typeMetaData<T>() noexcept { \
|
||||
static const uint16_t index = addTypeMetaData<T>(); \
|
||||
return index; \
|
||||
}
|
||||
#else
|
||||
#define CAFFE_DECLARE_KNOWN_TYPE(T, ident) \
|
||||
extern template uint16_t TypeMeta::addTypeMetaData<T>(); \
|
||||
namespace detail { \
|
||||
extern C10_API const uint16_t ident##_metadata_index; \
|
||||
} /* namespace detail */ \
|
||||
template <> \
|
||||
EXPORT_IF_NOT_GCC C10_ALWAYS_INLINE uint16_t \
|
||||
TypeMeta::_typeMetaData<T>() noexcept { \
|
||||
return detail::ident##_metadata_index; \
|
||||
}
|
||||
#endif
|
||||
|
||||
// Header-safe variant: lazy static, no external .cpp needed.
|
||||
#define CAFFE_KNOWN_TYPE_NOEXPORT(T) \
|
||||
template <> \
|
||||
inline uint16_t TypeMeta::_typeMetaData<T>() noexcept { \
|
||||
static const uint16_t index = addTypeMetaData<T>(); \
|
||||
return index; \
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Built-in known types
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
namespace detail {
|
||||
template <class T>
|
||||
class _guard_long_unique_dummy final {};
|
||||
|
||||
template <class T>
|
||||
using _guard_long_unique =
|
||||
std::conditional_t<std::is_same_v<long, int32_t> || // NOLINT(runtime/int)
|
||||
std::is_same_v<long, // NOLINT(runtime/int)
|
||||
int64_t>,
|
||||
_guard_long_unique_dummy<T>,
|
||||
T>;
|
||||
} // namespace detail
|
||||
|
||||
CAFFE_DECLARE_KNOWN_TYPE(std::string, std_string)
|
||||
CAFFE_DECLARE_KNOWN_TYPE(char, char)
|
||||
CAFFE_DECLARE_KNOWN_TYPE(std::unique_ptr<std::mutex>, std_unique_ptr_std_mutex)
|
||||
CAFFE_DECLARE_KNOWN_TYPE(std::unique_ptr<std::atomic<bool>>,
|
||||
std_unique_ptr_std_atomic_bool)
|
||||
CAFFE_DECLARE_KNOWN_TYPE(std::vector<int32_t>, std_vector_int32_t)
|
||||
CAFFE_DECLARE_KNOWN_TYPE(std::vector<int64_t>, std_vector_int64_t)
|
||||
CAFFE_DECLARE_KNOWN_TYPE(std::vector<unsigned long>, // NOLINT(runtime/int)
|
||||
std_vector_unsigned_long)
|
||||
CAFFE_DECLARE_KNOWN_TYPE(bool*, bool_ptr)
|
||||
CAFFE_DECLARE_KNOWN_TYPE(char*, char_ptr)
|
||||
CAFFE_DECLARE_KNOWN_TYPE(int*, int_ptr)
|
||||
CAFFE_DECLARE_KNOWN_TYPE(
|
||||
detail::_guard_long_unique<long>, // NOLINT(runtime/int)
|
||||
detail_guard_long_unique_long)
|
||||
CAFFE_DECLARE_KNOWN_TYPE(
|
||||
detail::_guard_long_unique<std::vector<long>>, // NOLINT(runtime/int)
|
||||
detail_guard_long_unique_std_vector_long)
|
||||
CAFFE_DECLARE_KNOWN_TYPE(float*, float_ptr)
|
||||
CAFFE_DECLARE_KNOWN_TYPE(at::Half*, at_Half)
|
||||
|
||||
} // namespace caffe2
|
||||
Reference in New Issue
Block a user